Today Ohloh finished importing the Launchpad source code and produced the first source code analysis report. There seems to be something fishy about the reported line counts (e.g. -3,291 lines of SQL), but the commit counts and contributor list look about right. If you’re interested in what sort of effort goes into producing an application like Launchpad, then it is worth a look.
One of the nice features of Bazaar is the ability to send a bundle of changes to someone via email. If you use a supported mail client, it will even open the composer with the changes attached. If your client isn’t supported, then it’ll let you compose a message in your editor and then send it to an SMTP server.
GMail is not a supported mail client, but there are a few work arounds listed on the wiki. Those really come down to using an alternative mail client (either the editor or Mutt) and sending the mails through the GMail SMTP server. Neither solution really appealed to me. There doesn’t seem to be a programatic way of opening up GMail’s compose window and adding an attachment (not too surprising for a web app).
What is possible though is connecting via IMAP and adding messages to the drafts folder (assuming IMAP support is enabled). So I wrote a small plugin to do just that. It can be installed with the following command:
bzr branch lp:~jamesh/+junk/bzr-imapclient ~/.bazaar/plugins/imapclient
And then configure the IMAP server, username and mailbox according to the instructions in the README file. You can then use “bzr send” as normal and then complete and send the draft at your leisure.
One nice thing about the plugin implementation is that it didn’t need any GMail specific features: it should be useful for anyone who has their drafts folder stored on an IMAP server and uses an unsupported mail client.
The main area where this could be improved would be to open up the compose screen in the web browser. However, this would require knowing the internal message ID for the new message, which I can’t see how to access via IMAP.
One thing that has been mentioned in the GNOME DVCS debate was that it is as easy to do “git diff” as it is to do “svn diff” so the learning curve issue is moot. I’d have to disagree here.
Traditional Centralised Version Control
With traditional version control systems (e.g. CVS and Subversion) as used by Free Software projects like GNOME, there are effectively two classes of users that I will refer to as “committers” and “patch contributors”:
Patch contributors are limited to read only access to the version control system. They can check out a working copy to make changes, and then produce a patch with the “diff” command to submit to a bug tracker or send to a mailing list. This is where new contributors start, so it is important that it be easy to get started in this mode.
Once a contributor is trusted enough, they may be given write access to the repository moving them to the committers group. They now have access to more functionality from the VCS, including the ability to checkpoint changes into focused commits, possibly on branches. The contributor may still be required to go through patch review before committing, or may be given free reign to commit changes as they see fit.
Some problems with this arrangement include:
- New developers are given a very limited set of tools to do their work.
- If a developer goes to the trouble of learning the advanced features of the version control system, they are still limited to the read only subset if they decide to start contributing to another project.
A DVCS allows anyone to commit to their own branches and provides the full feature set to all users. This splits the “committers” class into two classes:
The social aspect of the “committers” group now becomes the group of people who can commit to the main line of the project – the core developers. Outside this group, we have people who make use of the same features of the VCS as the core developers but do not have write access to the main line: their changes must be reviewed and merged by a core developer.
I’ve left the “patch contributor” class in the above diagram because not all contributors will bother learning the details of the VCS. For projects I’ve worked on that used a DVCS, I’ve still seen people send simple patches (either from the “xxx diff” command, or as diffs against a tarball release) and I don’t think that is likely to change.
Making the lives of core developers better is often brought up as a reason to switch to a DVCS (e.g. through features like offline commits, local cache of history, etc). I’d argue that making life easier for non core contributors is at least as important. One way we can measure this is by looking at whether such contributors are actually using VCS features beyond what they could with a traditional centralised setup.
By looking at the relative numbers of contributors who submit regular patches and those that either publish branches or submit changesets we can get an idea of how much of the VCS they have used.
It’d be interesting to see the results of a study based on contributions to various projects that have already adopted DVCS. Although I don’t have any reliable numbers, I can guess at two things that might affect the results:
- Familiarity for existing developers. There is a lot of cross pollination in Free Software, so it isn’t uncommon for a new contributor to have worked on another project before hand. Using a VCS with a familiar command set can help here (or using the same VCS).
- A gradual learning curve. New contributors should be able to get going with a small command set, and easily learn more features as they need them.
I am sure that there are other things that would affect the results, but these are the ones that I think would have the most noticeable effects.
Yesterday, a BoF was scheduled for discussion of distributed version control systems with GNOME. The BoF session did not end up really discussing the issues of what GNOME needs out of a revision control system, and some of the examples Federico used were a bit snarky.
We had a more productive meeting in the session afterwards where we went over some of the concrete goals for the system. The list from the blackboard was:
- Contributor collaboration (i.e. let anyone use the tool rather than just core developers).
- Distro ⇔ distro and distro ⇔ upstream collaboration.
- Host GNOME source code repositories
- Code review
- Server side hooks
- Translators: what to do?
- Enforced checks
- Offline operations
- Documentation authors?
- Support Win32/Mac (important for GTK)
The sys admin tasks were broken down to:
- MAINTAINERS file syntax checking
- PO file syntax checking
- CIA integration.
- Commits mailing list
- Check that commit messages are not empty
- Trigger updates from commits (e.g. the web site module).
- Release notes tarballs
- Damned Lies support
It was clear from the discussion that neither Git or Bazaar satisfied all of the criteria.
John Carr did a great job setting up Bazaar mirrors of all the GNOME modules. This provided an easy way for people to see play around with Bazaar. However, it only gave you half the experience since it didn’t provide a way to publish code and collaborate.
To aid in this, we have set up the bzr-playground.gnome.org machine, which any GNOME developer should be able to use to publish branches based on John’s imports. Instructions on getting set up can be found on the wiki. I hope that we will get a lot of people trying out this infrastructure.
We gave a presentation today on some of the things Bazaar provides that could be useful when hacking on GNOME. Demoing bzr-playground was a bit problematic due to the internet connection problems at the venue, but I think we still showed some useful tools for local collaboration, searching and code review.
Meanwhile, Robert Collins has been working on some of the GNOME sysadmin features that Bazaar was lacking. Among other things, he got Damned Lies working with both Subversion and Bazaar, with a test installation on the playground machine.
The published Bazaar branches include 8 years of history going back to MySQL 3.23.22, imported from the BitKeeper repositories. So you can see a lot more than just the history since the switch: you can use all the normal Bazaar tools to see where the code came from and how it evolved. Giuseppe Maxia has posted some instructions on how to check out the code for those who are interested.
I haven’t checked extensively, but I wouldn’t be surprised if this is the largest public code base managed with Bazaar. I’ve known from personal experience working on Launchpad that it is capable of handling large trees, but it is good to have a high profile project to point at as an example now.
One of the features I recently discovered in Bazaar is the --author option for “bzr commit“. This lets you make commits to a Bazaar branch on behalf of another person. When used, the new revision credits two people: you as the committer and the other person as the author.
While Bazaar does make it easy for non-core contributors to send changes in a form that correctly attributes them (e.g. by publishing a branch or sending a bundle), I doubt we’ll ever see the end of pure patches. Some cases include:
- Patches based on a tarball release. In these cases the contributor likely hasn’t even used the VCS.
- People send simple diffs from e.g. “bzr diff” since that is sometimes the easiest solution (or what they do by default due to having transferred their knowledge from another VCS).
- Some people use a VCS bridge so they can work with their favourite VCS. They might not be able to provide their changes as Bazaar commits due to this.
The --author option lets you commit these changes in a way that credits the contributor for their work. The author of the change will then be displayed in “bzr annotate” output and credited along with the you in the “bzr log” output.
The feature is also used by a number of plugins such as bzr-rebase: if you replay or rebase someone else’s changes, the new revisions will creit you as the committer and the original committer as the author.
Last week we moved psycopg from Subversion to Bazaar. I did the migration using Gustavo Niemeyer‘s svn2bzr tool with a few tweaks to map the old Subversion committer IDs to the email address form conventionally used by Bazaar.
The tool does a good job of following tree copies and create related Bazaar branches. It doesn’t have any special handling for stuff in the tags/ directory (it produces new branches, as it does for other tree copies). To get real Bazaar tags, I wrote a simple post-processing script to calculate the heads of all the branches in a tags/ directory and set them as tags in another branch (provided those revisions occur in its ancestry). This worked pretty well except for a few revisions synthesised by a previous cvs2svn migration. As these tags were from pretty old psycopg 1 releases I don’t know how much it matters.
As there is no code browsing set up on initd.org yet, I set up mirrors of the 2.0.x and 1.x branches on Launchpad to do this:
It is pretty cool having access to the entire revision history locally, and should make it easier to maintain full credit for contributions from non-core developers.
While doing a bit of work on Storm, I decided to try out the loom plugin for Bazaar. The loom plugin is designed to help maintain a stack of changes to a base branch (similar to quilt). Some use cases where this sort of tool are useful include:
- Maintaining a long-running diff to a base branch. Distribution packaging is one such example.
- While developing a new feature, the underlying code may require some refactoring. A loom could be used to keep the refactoring separate from the feature work so that it can be merged ahead of the feature.
- For complex features, code reviewers often prefer to changes to be broken down into a sequence of simpler changes. A loom can help maintain the stack of changes in a coherent fashion.
A loom branch helps to manage these different threads in a coherent manner. Each thread in the loom contains all the changes from the threads below it, so the revision graph ends up looking something like this:
Once the plugin has been installed, a normal branch can be converted to a loom with the “bzr loomify” command. The “bzr create-thread” command can be used to create a new thread above the current one.
The “bzr down-thread” and “bzr up-thread” commands can be used to switch between threads. When going up a thread, a merge will be performed if there are new changes from the lower thread. The “bzr show-loom” command shows the current state of the loom, and which thread is currently selected.
The “bzr export-loom” command can be used to explode the loom, creating a standard branch for each thread. The included HOWTO document gives a more detailed tutorial.
There are a few warts in the UI that I’ve encountered though:
- The “bzr combine-thread” command sounds like it should actually merge two threads. Instead it is an advisory command that can be used to remove a thread once its contents have been merged.
- After pulling new changes in from upstream on the bottom thread, it gets a bit tedious bubbling the changes up with “bzr up-thread” and “bzr commit“.
- As well as committing revisions to individual threads, the “bzr record” command can be used to commit the state of the loom as a whole. I haven’t really worked out when I should be using the command.
- No indication is given if there are changes in the loom that haven’t been recorded with “bzr record“. I’d expect some indication from “bzr status” to this effect.
- When using looms to break a larger feature down into smaller chunks, it’d be nice to have a command that generated a sequence of merge requests that built on top of each other. This would be the form needed to submit them for review on a mailing list.
Despite the quirks in the interface, it does make the relevant work flows easier. It will be interesting to see how the plugin develops.
When working on my bzr-avahi plugin, Robert asked me about how it should fit in with his bzr-dbus plugin. The two plugins offer complementary features, and could share a fair bit of infrastructure code. Furthermore, by not cooperating, there is a risk that the two plugins could break when both installed together.
Given the dependencies of the two packages, it made more sense to put common infrastructure in bzr-dbus and have bzr-avahi depend on it. That said, bzr-dbus is a bit more difficult to install than bzr-avahi, since it requires installation of a D-Bus service activation file. After looking at the code, it seemed that there was room to simplify how bzr-dbus worked and improve its reliability at the same time.
The primary purpose of bzr-dbus is to send signals over the session bus whenever the head revision of a branch changes. This was implemented using a daemon that is started using D-Bus activation, and sends out the signals in response to method calls made by short lived bzr processes.
While this seems to be the design the dbus-python tutorial guides you to use, I don’t think it is the best fit for bzr-dbus. The approach I took was to do away with the daemon altogether: the D-Bus session bus does a pretty good job of broadcasting the signals on its own.
The code that previously asked the broadcast daemon to send the revision signal was changed to simply send the signal. The following helper made this pretty easy to do without having to write any extra classes to emit the signals:
def send_signal(bus, dbus_interface, signal_name, signature, *args): """Send a signal on the bus.""" message = dbus.lowlevel.SignalMessage('/', dbus_interface, signal_name) message.append(signature=signature, *args) bus.send_message(message)
With these changes, the commit hook now only needs to connect to the session bus and fire off the signal and return. Previously it was connecting to the bus, getting an the broadcast service (which might involve activating it), sending a method call message and waiting for a method return message. The new code is faster and if no one is listening for the signals, it only wakes the bus.
For code that was consuming the signals, they had to switch to the bus.add_signal_receiver() method to register the callbacks, which allows you to subscribe to a signal irrespective of its origin.
The only missing feature with these changes was annotating the signals with additional URLs when the branch was being shared over the network. As these additional URLs are only really interesting when accessing the branch remotely, I moved the functionality to the “bzr lan-notify” command so that it annotates the revision announcements just before broadcasting them to the local network.
With all the changes applied, the D-Bus API consists entirely of signal emissions, which gives a looser coupling between the various components: each component will happily function in the absence of the others, which is great for reliability.
Once the patches are merged, I’ll have to look at porting bzr-avahi to this infrastructure. Together, these two plugins offer compelling features for local network collaboration.
At Canonical, one of the approaches taken to accelerate development is to hold coding sprints (otherwise known as hackathons, hackfests or similar). Certain things get done a lot quicker face to face compared to mailing lists, IRC or VoIP.
When collaborating with someone at one of these sprints the usual way to let others look at my work would be to commit the changes so that they could be pulled or merged by others. With legacy version control systems like CVS or Subversion, this would generally result in me uploading all my changes to a server in another country only for them to be downloaded back to the sprint location by others.
In contrast, with a modern VCS like Bazaar we should be able to avoid this since the full history of the branch is available locally – enough information to let others pull or merge the changes. That said, we’ve often ended up using a server on the internet to exchange changes despite this. This is the same work flow we use when working from home, so I guess the pain of switching to a new work flow outweighs the potential productivity gains.
Bazaar makes it easy to run a read only server locally:
bzr serve [--directory=DIR]
However, there is still the issue of others finding the branch. They’d need to know the IP address assigned to my computer at the sprint, and the path to the branch on the server. Ideally they’d just need to know the name of the my branch. As it happens, we’ve got the technology to fix this.
Avahi makes it trivial to advertise and browse for services on the local network without having to worry about what IP addresses have been assigned or what people name their computer. So the solution is to hook Avahi and Bazaar together. This was fairly easy due to Avahi’s DBus interface and the dbus-python bindings.
bzr branch lp:bzr-avahi ~/.bazaar/plugins/avahi
To use the plugin, you must have at least version 1.1 of Bazaar, the Python bindings for DBus and Avahi, and a working Avahi setup. Once the plugin is installed, it hooks into the standard “bzr serve” command to do the following:
- scan the directory being served for branches that the user has asked to advertise.
- ask Avahi to advertise said branches
You can ask to advertise a branch using the new “bzr advertise” command:
bzr advertise [BRANCH-NAME]
If no name is specified, the branch’s nickname is used. The advertise command sends a signal over the session bus to tell any running servers about the change, so there is no need to restart “bzr serve” to see the change.
At this point, the advertised branches should be visible with a service browser like avahi-discover, so that’s half the problem solved. From the client side two things are provided: a special redirecting transport and a command to list all advertised branches on the local network.
The transport allows you to access the branch by its advertised name with most Bazaar commands. For example, merging a branch is as simple as:
$ bzr merge local:BRANCH-NAME local:BRANCH-NAME is redirected to bzr://hostname.local:4155/path/to/branch ... All changes applied successfully. $
If you want to get a list of all advertised branches on the network, the “bzr browse” command will print out a list of branch names and the URLs they translate to.
I believe using these tools together should offer a low enough overhead for direct sharing of branches at sprints that people would actually bother using it. It should be quite useful at the next sprint I go to.