Extending Mercurial with short shell scripts

There are many cool reasons why using Mercurial on a UNIX system feels good. One of them is that a UNIX system is, by nature, extremely scriptable and extensible. As a quick ‘n’ dirty example, today I wrote two short shell scripts, which make “hg incoming” and “hg outgoing” much more pleasing for me.

The default output of “hg incoming” is fairly verbose, and it includes a lot of information. It typically prints something like:

keramida@kobe:/home/keramida/hg/doc/gker$ hg in
comparing with /home/keramida/hg/doc/ncvs
searching for changes
changeset:   16781:184341152c2f
user:        jkois
date:        Mon Apr 16 15:55:52 2007 +0000
summary:     MFbed:  Update the German documentation set.

changeset:   16782:de4d1edbd7ea
user:        delphij
date:        Tue Apr 17 03:08:25 2007 +0000
summary:     Add lwhsu@

changeset:   16783:3b1eae61b62b
user:        delphij
date:        Tue Apr 17 03:09:11 2007 +0000
summary:     MFen 1.35 -> 1.38

changeset:   16784:bac66b9b7370
user:        delphij
date:        Tue Apr 17 03:12:05 2007 +0000
summary:     Refresh with latest snapshot from FreeBSD Simplified

changeset:   16785:40e310b1cb2f
user:        delphij
date:        Tue Apr 17 03:13:14 2007 +0000
summary:     MFen 1.814 -> 1.824.

changeset:   16786:23a92d1dd31c
user:        rafan
date:        Tue Apr 17 04:06:40 2007 +0000
summary:     - Document __FreeBSD_version 602109: readline 5.2 mfc

changeset:   16787:fa00a1476a72
tag:         tip
user:        brueffer
date:        Tue Apr 17 07:00:37 2007 +0000
summary:     trunk(4) is now lagg(4).

keramida@kobe:/home/keramida/hg/doc/gker$

This is a set of changesets which I was about to pull from a local mirror of the FreeBSD doc/ tree, converted to Mercurial format. The extra verbosity is a bit too much for my eyes most of the time, so I wrote a small shell script to wrap “hg incoming“, and produce output like this:

keramida@kobe:/home/keramida/hg/doc/gker$ inc
         AGE  |       CHANGE | AUTHOR       | DESC
    28 hours  | 184341152c2f | jkois        | MFbed   Update the German documentation set.
    17 hours  | de4d1edbd7ea | delphij      | Add lwhsu@
    17 hours  | 3b1eae61b62b | delphij      | MFen 1.35 -> 1.38
    17 hours  | bac66b9b7370 | delphij      | Refresh with latest snapshot from FreeBSD Simplified
    17 hours  | 40e310b1cb2f | delphij      | MFen 1.814 -> 1.824.
    16 hours  | 23a92d1dd31c | rafan        | - Document __FreeBSD_version 602109  readline 5.2 mfc
    13 hours  | fa00a1476a72 | brueffer     | trunk(4) is now lagg(4).
keramida@kobe:/home/keramida/hg/doc/gker$

The wrapper script itself, which I now keep in my $HOME/bin collection of short hacks and other locally useful stuff, is quite short but tedious to manually type every time I want to see “hg incoming” output:

#!/bin/sh

fmtlog()
{
        awk -F: '
        BEGIN {
                printf "%12s  | %12s | %-12s | %s\n", \
                    "AGE","CHANGE","AUTHOR","DESC";
        }
        {
                printf "%12s  | %12s | %-12s |",$1,$2,$3;
                for (k = 4; k <= NF; k++) {
                        printf " %s", $k;
                }
                printf "\n";
        }'
}

tmpl='{date|age}:{node|short}:{author|email}:{desc|firstline}\n'
hg in --template "${tmpl}" "$@" | grep ':.*:.*:' | fmtlog

It’s trivial to write an equally short shell script called “out“, which wraps around “hg outgoing“, and bingo… with two fairly short scripts, suddenly Mercurial can show a fair amount of incoming/outgoing changeset information using an one-liner format for each changeset :-)