Homebrew package for monotone

Apparently there is a new kid on the block when it comes to package managers / software installers on Mac OS X and its dubbed “Homebrew”.

While I scrolled down their lengthy list of recipes (they call it “formulas”), I recognized that somebody was already so nice and created such a formula for monotone there.

So if you dislike MacPorts or Fink for some reason, you might want to look into Homebrew instead.

Bugfest analysis

The last couple of days have been very busy in the monotone team: A total of 21 bugs have been processed by the attendees of our little bug hunt day and while it was quite stressful for me to keep track and review everything, it was lots of fun. A complete list with references to all the changes can be found here.

I won’t bore you with all the nitty gritty details, instead I show you the highlights that will arrive in the upcoming version 0.48 as fallout of this bugfest:

  • mtn ls tags will be able to show the branch name a tag is on
  • netsync commands will gain a new `–anonymous` option to enforce anonymous pulls and clones
  • a new `undrop` command which recreates formerly dropped files while keeping their contents in-tact
  • head-changing commands like pull, merge, propagate, disapprove and others will get a new `–update` option, which changes an underlying workspace to the new head revision
  • monotone now prints out warnings in a couple of places if you’re about to create divergence, f.e. by disapproving an old revision
  • diff output will now track renames and will also list file deletes

We’re planning to hold off such a bug hunt day or “hackfest” every few months, while keeping the balance between too less and too often. If you’re interested and want to join, drop me a note, idle in monotone’s IRC channel or subscribe to our mailing list. Looking forward to hear from you 🙂

Was ist falsch an diesem Bild?

Auf dem Bild (Quelle: AP) ist zu sehen, wie Abgeordnete des Deutschen Bundestages am heutigen Freitag zur Abstimmung über die 22,4 Mrd. Euro Kredit-Nothilfe für Griechenland schreiten. Ich möchte gar nicht über Sinn und Unsinn dieser Kredite sprechen, nein, ich wundere mich ganz konkret über die in diesem Bild aufgefangene Situation:

Der Deutsche Bundestag beschließt Milliarden-Nothilfen zu Zeiten klammer Kassen, zurückgehender Steuereinnahmen und einer noch nicht vollständig von der letzten Wirtschaftskrise erholten Nation – und die Abgeordneten schreiten lachend und feixend zur Abstimmung über eine noch größere Ausgabenlast…?

Da haben wohl einige die Bodenhaftung gänzlich verloren – nach dem Motto “Ist ja nicht mein Geld…”. Liebe (Noch-)Volksvertreter, wundert Euch nicht, wenn das Volk eines Tages doch mal gewaltig rein Tisch macht.

monotone merchandise / bug hunt day

I recently created a new cafepress shop for monotone which uses the updated logo and our new claim, “reliable, distributed version control” and I have to say that this looks really cool now.

The reason why I did this is not because I’m a greedy bastard (no, the old shop which was set up by Graydon – the original author of monotone – back in 2005 didn’t bought us anything), but because the monotone developers will soon hold off a “Bug Hunt Day” to fix and close many of the old outstanding bugs we still have in the Savannah bug tracker. And what is better then bribing the devs with cool merchandise they’re receiving when they close more bugs than others…?

So if you want one of those cool caps, mugs or t-shirts, you have two options – either go directly to the shop and order one of the listed products there (and support your beloved version control tool :)) or you attend our little bug hunting – for the latter just go to this doodle survey and add your name and possible dates when you’re available.

Subscribing to monotone’s development list or idling around in our IRC channel might be helpful as well… I would be pleased to see you there!

Quitting a Qt application from the Mac OS X dock

So for some weird reason my application was not closable from the Mac OS X dock – it quit properly when you selected “Quit” from the application menu or hit the Cmd-Q shortcut – but the dock menu’s quit action was completely ignored.

While debugging the issue I hooked into `QApplication::notify(QObject *, QEvent *)` and noted that a `QCloseEvent` was send to my application… wait, what? A `QCloseEvent`? Yes, I also thought that these kinds of events would only be send to widgets, namely, top level widgets, but I got one for my application, and Qt plainly ignored it. So I went further ahead and tried to quit the application directly when the event occured, similar to this

bool MyApp::event(QEvent * ev)
{
    bool eaten = false;
    switch (ev->type())
    {
        // other stuff ...
#ifdef Q_WS_MAC:
        case QEvent::Close:
        {
            quit();
            eaten = true;
            break;
        }
#endif
        default:
            eaten = QCoreApplication::event(ev);
            break;
    }
    return eaten;
}

but this didn’t work out so nicely: while the application quitted correctly, the `quit()` slot was apparently called twice in a row. My guess is that Qt ignores the `quitOnLastWindowClosed` property – which I’ve set to false – and since I close all windows in the quit slot it executes quit again, or something else, so I decided to just close all open windows when the `QCloseEvent` arrived – without calling `quit()` directly, and tada, my application quitted and the slot was also only called once. (This was a mistake on my side because I missed a break.)

monotone plugin for indefero (updated)

I’ve started hacking on a monotone plugin for indefero – a source code / project management tool which supports various SCM backends. You can find the code for it on github (git, because, well, indefero uses git…).

While there are a couple of web-related tools for monotone, namely TracMonotone and ViewMTN, both projects haven’t seen many updates over the last couple of years and are now even maintained by a single person who has not much time either. Having very good and broad tool support is however crucial for an SCM system, because only very few people are willing to use the command line for everything, so I hope that the addition of indefero as tool which will support monotone in one of its next versions will help both projects a little.

The code is still in alpha state, but one can already browse branches and revisions. My current TODO is as follows:

  • finalize the implementation of the changelog view done
  • make branch names shorter in the UI so they don’t overlap with the tree contents done
  • add automate stdio support for the SCM backend class, so we don’t need to create a separate process for every data request done
  • add automate remote_stdio support (possibly by adding a configuration option which allows either setup)
  • truncate the log message in the tree view to a proper size
  • dynamically change the clone url to the branch which the user is currently browsing done
  • check the inTags() and inBranch() implementations – apparently this does not work as it should done

Especially the multi-project nature of indefero requires some additional hacks in monotone and also one of its tools, usher (which is able to serve multiple distinct databases over one connection), so this plugin project really drives a lot of development. If you’re interested in either part and want to team up, drop me a note 😉

guitone 1.0rc3 released

I’m proud to announce the third release candidate of guitone 1.0.
This release fixes some critical bugs and also adds support for
drag’n’drop renames in the workspace amongst other minor improvements.

The complete list of changes is as always listed in NEWS. A Mac OS X
binary is also already available, a package for Windows will follow
tomorrow.

I’m still looking for translators – if you’re interested, please drop me
a note.

openSUSE build service automation

A few weeks ago I’ve hacked together some scripts to use the openSUSE build service as platform for nightly builds. The build is kicked off every hour when something new can be build.

Additionally I’ve created a small PHP client which queries the openSUSE RESTful API and shows packages, binaries, the build log of the last build and a build history.

The code for this is GPL’d and can be cloned via monotone:

$ mtn clone thomaskeller.biz biz.thomaskeller.monotone-nightly

All this could be polished and secured quite a bit more and its even arguable if its a good idea to “misuse” the openSUSE’s infrastructure
for nightly builds like this, but I see it more as a proof of concept. Since their build infrastructure code is open source as well, somebody
can always just setup a build server together with a service and a couple of predefined XEN images and should be good to go.

The concept can now be horizontally applied to other distros and versions as well, basically anything what can run within a Xen instance
(unfortunately this does not include Mac OS X or Windows, so there is still the need for some kind of alternative build infrastructure). I
eventually plan to add a couple of more Xen instances to my project and try to get them build – of course you can be my guest and play with it yourself and lend me a helping hand here 🙂

guitone 1.0rc2 released

I’m proud to announce the immediate release of guitone-1.0rc2. This is the second release in a series of smaller releases which aims at the stabilization of the guitone codebase. A lot of bug fixes went into the code, only a few outstanding issues remain. The addition of an
annotation view is the most visible new feature of this release. Please test and report bugs if possible.

The complete list of changes is written down in the NEWS file as
always. I’ll try and prepare a Windows binary tomorrow, a binary for Mac OS X should arrive shortly as well.

Qt itemviews trouble

Whoever digged a little deeper into Qt’s item views and models in the past knows that they’re quite tricky beasts sometimes. Two problems where driving me nuts recently:

1. How can I auto-expand the root node of a `QTreeView` whenever the view is resetted?
2. How can I restore the expansion / root state of a `QTreeView` when a model filter cleared all the items out before, effectively resetting the view as in 1.?

After a lot of struggling and lots of debugging I think I found a solution for both problems, which are slightly connected.

To get the auto-expansion feature, I connected the `layoutChanged()` signal of the model to a timer in my view, whose `timeout()` signal then again called the following slot:

void MyTreeView::delayedLayoutChanged()
{
    QModelIndex index = model()->index(0, 0, QModelIndex());
    expand(index); // or alternatively: setRootIndex(index);
}

This simply takes the first element of the model and expands it. Why the trick with the timer? Well, apparently the `layoutChanged()` signal is already processed internally by `QAbstractItemView` or `QTreeView` and its implementation resets the view state completly – which is of course problematic if it gets executed _after_ our own slot. A single-shot timer with an interval of 0 ms is enough here to make Qt use the next event loop cycle and do the right thing for us.

Now, things get more complex if you have a `QSortFilterProxyModel` attached to your tree view – imagine one of these fancy find-as-you-type inputs. If a user enters a search word which clears out all items from your current view and then resets the input again to see the original view, the view eventually gets a `layoutChanged()` signal as well, but because of the clearing you may have lost the expansion level in which the user was before!

`QPersistentModelIndex` is here for the rescue. All you have to do is remember the model index you previously used to expand your view and use that instead of the static one if it is still valid:

QPersistentModelIndex MyTreeView::lastExpansion;
void MyTreeView::expandSomething(const QModelIndex & index)
{
    lastExpansion = static_cast(model())
        ->mapToSource(index);
    expand(index);
}
void MyTreeView::delayedLayoutChanged()
{
    QModelIndex index;
    // is the item still part of the source model? 
    // (important for dynamic source models)
    if (lastExpansion.isValid())
    {
        index = static_cast(model())
              ->mapFromSource(lastExpansion);
    }
    else
    {
        index = model()->index(0, 0, QModelIndex());
    }
    expand(index); // or alternatively: setRootIndex(index);
}

While `QPersistentModelIndex` and `QModelIndex` are two distinct classes, the Trolls made them easily interchangable without special casting magic.

Note that you always need to save the source index and never the proxy index which might be invalidated if it is removed from the view. Things get of course even more complex if you have not one, but two proxy models which filter your view…