Gitosis for Mercurial

As far as DVCSs go I’ve been a git user. That’s mostly because it was the first one I tried and it worked. I’ve been comfy and have enjoyed the world of git and GitHub, but a number of troublemakers have been trying to convince me to give Mercurial a shot. After some nudging I obliged.

After a day or two of toy and experimental projects I started missing one of my primary git utilities–Gitosis. Gitosis is a package that lets you and all your collaborators interact with your git repositories using a single user account over SSH. Gitosis manages user authentication and permissioning using a system of shared keys without ever exposing actual shell functionality.

It took me a little while to find mercurial-server by LShift, which seems to be Mercurial’s equivalent to Gitosis. So, here is how I got Gitosis-style shared key repository management to work with Mercurial.

Installing Mercurial-Server on Ubuntu 9.10 (Karmic)

Luckily, Paul Crowley of LShift, the author of mercurial-server, has volunteered to manage a Debian package for Mercurial-Server, which makes our lives easier. Thanks!

Install the Mercurial-Server Package

Add the following line to your /etc/apt/sources.list file replacing the url with a mirror that’s appropriate for your location:

deb http://mirrors.kernel.org/ubuntu lucid main universe

then:

$ sudo apt-get update
$ sudo apt-get install mercurial mercurial-server

OR, if you want to install the package manually outside of synaptics or apt you can download the .deb from http://packages.ubuntu.com/lucid/all/mercurial-server/download and then:

$ sudo dpkg -i mercurial-server_1.0.1-1_all.deb

Mercurial-Server should now be installed. Additionally, a new user hg has been created and will be used to manage all your interactions with your mercurial repositories.

Setting Up Mercurial-Server Administrator (root)

You now need to grant yourself administrator rights. All permissioning is done with keys, so you’ll need to copy your public key to mercurial-server’s admin keyring:

$ sudo cp id_rsa.pub /etc/mercurial-server/keys/root/YOURUSERNAME

$ sudo -u hg /usr/share/mercurial-server/refresh-auth

The second command refreshes mercurial-server’s authentication system–authorizing your account as an administrator. You’re good to go!

Managing Mercurial-Server

The hgadmin Repository

Just like gitosis’ gitosis-admin repository, mercurial-server’s functionality can be managed via hgadmin. Go ahead and clone the repo:

$ hg clone ssh://hg@MyMercurialServer/hgadmin

Adding New Users

With your hgadmin repository cloned you can now grant access to new users via their public keys

$ cd hgadmin
$ mkdir -p keys/users/
$ cp ~/kurt-key.pub keys/users/kurt
$ hg add
adding keys/users/kurt
$ hg commit -m "Added Kurt's public key"
$ hg push

You can also allow and organize multiple keys per user. In that scenario you create a directory of keys for each user:

$ cd hgadmin
$ mkdir -p keys/users/kurt
$ cp ~/kurt-home.pub keys/users/kurt/home
$ cp ~/kurt-work.pub keys/users/kurt/work
$ hg add
adding keys/users/kurt/home
adding keys/users/kurt/work
$ hg commit -m "Added keys for Kurt's home and work computers"
$ hg push

Creating New Repositories

As administrator, if you want to create a new repository you simple clone a mercurial project to a path on your mercurial-server. For example:

$ cd my_hg_proj
$ hg clone . ssh://hg@MyMercurialServer/my_hg_project

Now you and your collaborators can clone, push, and pull from the server’s repository just as we did with hgadmin. For example:

$ hg clone ssh://hg@MyMercurialServer/my_hg_project

Managing Repository Permissions

Now that you’ve created your repositories and added users you will want to manage permissions. Repository permissions can be managed through an hgadmin file called access.conf. I recommend reading the mercurial-server documentation for more information on managing security.

So far I’ve found mercurial-server to be a great way to collaborate with others on private repositories outside of Bitbucket. My hat off to Paul Crowley and LShift.

Get your Nose Out Of There!

I wrote my first Nose plugin this weekend and I’ve got to say it was dead simple.

Leash Kid

I was looking around for ways to keep Nose from searching for tests in certain directories. You see Nose is a nosey little critter that will scour every nook and cranny of your directory structure looking for unittests to run. Really, it wants your code to work and it loves making dots. But, see I knew better and knew if that little Nose test discoverer ventured down a few rabbit holes it would end up in a world of pain–segfaults or worse. I just wanted to avoid the whole mess and just have Nose exclude a few directories from its massive testhunt.

I asked a few people I know who use Nose regularly about my options. “Write your own plugin,” was the consensus. Nose’s architecture makes it very easy to write plugins for just about every aspect of its behavior…check out its plugin api. The project documentation is also very helpful in this regard.

I spent most of my time trying to figure out how to test my testing plugin. In the end it only took a couple of hours to go from Nose novice to having written a packaged, testable Nose plugin. So, here’s a quick example of how you would use this new nose-exclude plugin:

 $ ls test_dir
dir_with_tests    dir_with_bad_tests
there_be_dragons_here    more_tests

In this example, I want Nose to ignore a couple directories and not even bother searching them. You would run:

$ nosetests --exclude-dir=test_dir/dir_with_bad_tests \
--exclude-dir=test_dir/there_be_dragons_here test_dir

You could further specify to exclude subdirectories if you wanted that level of control. There is also an –exclude-dir-file= option available that allows you to specify a file containing paths to be excluded.

$ nosetests --exclude-dir-file=exclude_dirs.txt test_dir

nose-exclude is pretty simple and covers a fairly basic use case so hopefully others will find it useful. For now nose-exclude is available on bitbucket, but will be up on PyPI shortly.