Sunday, May 2, 2010

Setting up a shared repository for Mercurial

 

Mercurial -- Source Versioning Control


(this is also available as a Google Doc)

Use of Mercurial over SSH

Please review the section named: Using the Secure Shell (ssh) protocol in Mercurial's "Definitive Guide" -- you may also find useful to review this blog entry (but there are differences with my 'paranoid' settings....)

I have configured my SSH port away from the standard sshd (22) and I'm using Dynamic DNS to use with my broadband connection (see http://dyndns.org for more info); further, I recommend only allowing SSH connections from a (limited) number of trusted IP (ranges) by editing /etc/hosts.allow; if you can't get this one to work, please figure out which IP address are you connecting from (http://www.formyip.com) and tweak your hosts.allow accordingly:

ssh -p 666 -l [user] yourdomain.dyndns.org

at this stage, you should be prompted for your password, that is to be expected.
If you can't connect, make sure you can DNS-lookup the server (nslookup yourdomain.dyndns.org must return something meaningful -- this is achieved via inadyn, so if you get an IP address, but still can't connect, it is -marginally- possible that inadyn is down and the IP was changed by your ISP).

Creating a private/public key pair

On the local Linux[1] box do the following:

ssh-keygen -t rsa

[1] if are using Windoze, you're too far down in the evolution chain for me to waste any time educating you, but you can do worse than Google "putttygen key pairs" or some such thing.

this will generate a private/public key pair in your ~/.ssh directory, one of which should be named something like id_rsa.pub -- copy that one (not the id_rsa private key!) on the remote machine's ~/.ssh directory (or in /tmp, it doesn't really matter).

You must then add this public key to your ~/.ssh/authorized_keys file (if it does not exist, you will need to touch it, remember to chmod it to 500 -- only YOU must be able to rw it);

touch ~/.ssh/authorized_keys
chmod 500 ~/.ssh/authorized_keys
cat /tmp/id_rsa.pub >>
~/.ssh/authorized_keys

logout from the remote machine, then re-issue the ssh command above, you should then be logged in, without the remote SSH server asking for the password.

Setting up your username

It's always good practice to ensure that your changes can easily be tracked back to you: as an essential part of this, setting up a meaningful username for HG is critical: you can use the HGUSER environment variable (export HGUSER="Marco Massenzio <m.massenzio@gmail.com>") or set it up in a more 'permanent' way by editing the Mercurial configuration file (~/.hgrc):

# This is a Mercurial configuration file.
[ui]
username = Marco Massenzio <m.massenzio@gmail.com>

Pulling a changelist from the remote repository

The directory where we will place HG repositories is in /usr/local/hgrepo, each directory will be a project's repository -- a simple test repo is 'hello' (/usr/local/hgrepo/hello) and you should be able to clone it onto your machine by issuing the following (from a local shell -- do not ssh into the remote server):

hg clone ssh://user@yourdomain.dyndns.org:666//usr/local/hgrepo/hello

A couple of things worthy of note:

  1. note the // after 666 (//usr) this tells SSH to start at the root of the filesystem (/) instead of your homedir (~/)
  2. replace the username in user@ with your actual username -- do not send the password in cleartext, you should in fact not be asked for a password (if you are, then something went wrong with the private/public key pair setup above)
  3. you should now have a hello directory, containing a few files on your local machine; if something went wrong, you should see an error message.

Making changes to the files in the (local) repository

Follow the usual HG practices -- edit the file with your favourite editor, save it, and once you are happy with it, commit it to the (local) repository:

hg ci -m "Did something astounding"

Pushing changes to the (remote) repository

Once you are happy with the changes, and think it's time for the other developers to see them, push them back to the remote repository:

hg push -v ssh://user@yourdomain.dyndns.org:666//usr/local/hgrepo/hello

By design, doing so, will not make the changes the 'tip' (or head) of the remote repository -- see the book as for why -- you should run an hg update command on the remote directory: the simplest way I found is to SSH into your remote machine and then run an hg update on the repo:

ssh -p 666 -l user yourdomain.dyndns.org
cd /usr/local/hgrepo/hello
hg status
# this should be an empty line, no editing of files should happen on the remote machine
hg glog -l 6
# see the 'graphic log' extension section in the hg manual
# this will show a list of the last 6 CLs, the 'active' one marked with an @
hg update
# this will make 'head' the 'active' revision

if no conflicts arise then this should update head; if there are conflicts, you will have to run a merge command:
hg merge
# I discourage doing merges on the remote machine however: merges are best done using a visual
# editor, suck as tkdiff, or similar.

possibly resolving the merge conflicts as they arise.

Pulling changes from the (remote) repository

Before starting any work, you should pull the latest version of the repository from ibw:

hg pull -v ssh://user@yourdomain.dyndns.org:666//usr/local/hgrepo/hello

By design, doing so will not make the changes the 'tip' (or head) of the local repository -- see the book as for why -- you should run an hg update command on the local directory:

hg up

if no conflicts arise then this should update head; if there are conflicts, you will have to run a merge command:

hg merge


Pulling / Pushing changes in Eclipse

Use the Mercurial Eclipse plugin [follow instructions on the site to install -- update site: http://www.vectrace.com/eclipse-update/] then use the right-click context sensitive Team menu with the Project folder selected, and choose accordingly.

The Repository URL to use is:
ssh://user@yourdomain.dyndns.org:666//usr/local/hgrepo/hello
 
but do not enter username/password in the dialog box, SSH will pick up the private key and proceed to conduct the handshake (if the pub/priv keys setup does not work for any reason, Eclipse will still be able to connect to the repository, but you will be asked for the password a couple of times, or possibly more).

Personally, I'm not using the Eclipse plugin (the initial delay in starting up at Eclipse launch is most irritating) and only use hg's command-line interface.



Putting some Google Goodines in your Code

Adding Protocol Buffers and GTest to your C++ project in Eclipse

(this post is also available as a Google Doc)

Use of Protocol Buffers

Download the package from the Google Code website (we are currently using version 2.2.0) and unpack the tar.gz file in a directory (say, /usr/share/protobuf_2.2.0) and then follow the steps outlined in the INSTALL.TXT file.

NOTE -- you must run the last step as root or installation will fail:

sudo make install

(optionally, run sudo make clean).

Once installed, you will have a bunch of files in your /usr/local/include and /usr/local/lib directories, these matter!

Using Eclipse, you can create a new C++ Project and then have to set up the include directories and add the protobuf.a library -- otherwise your code will not compile/link.
(this is not explained anywhere in the protobuf documentation).

Add the include directory

Right-click on the Project's folder, Properties > Settings: add /usr/local/include in the Directories for the C++ Compiler options:






Add the libraries directory

In the Directories for the C++ Linker options add /usr/local/lib; however, this does not seem to work, if one then adds libprotobuf.a in the box above (Libraries) the Linker will complain that it cannot find the file. Not sure whether this is a bug or "intended behaviour".


Select instead "Miscellaneous" and add into the "Other objects" dialog the full path to libprotobuf.a: /usr/local/lib/libprotobuf.a



Accept (OK) the settings, build the project, profit!


Adding gUnit Tests


This is a very similar procedure to the above: download and install Google Test from the Google Code website, install the code someplace on your disk and then add /usr/local/lib/libgtest.a and /usr/local/lib/libgtest_main.a to the Miscellaneous section in the C++ Linker.

NOTE -- to run the unit tests, your code must NOT have a main() function defined (simply rename it to something else).

Then you can add a prime_test.cc file in your project and run it simply by right-clicking the Project's folder and choosing Run As > Local C/C++ Application; libgtest_main will provide the main() to run the tests.

/* * p3_unittest.cc * * Unit test for Problem 3 * * See p3.cc * * Created on: 21-Dec-2008 * Author: Marco Massenzio (m.massenzio@gmail.com) */

#include <iostream>
#include <gtest/gtest.h>

#include <set>


#include "../common/euler.h"

using namespace euler;

TEST(PrimeTest, IsThree) {
ASSERT_TRUE(isPrime(3));
}

TEST(PrimeTest, IsTen) {
ASSERT_FALSE(isPrime(10));
}



where isPrime() is defined in euler.h/euler.cc as follows:

namespace euler {
// returns true if n is prime
bool isPrime(const long n);
}