2011/05/01

Mercurial拡張の書きかたについて

MercurialがPythonで書かれていることもあり、単純なMercurial拡張を自分で書くのは意外と簡単です。この記事では簡単なMercurial拡張を作成してhgコマンドから呼び出す方法を簡単に説明します。

なお、Mercurialの内部APIを用いた場合には、そのコードはMercurialのライセンス (GPL) に従うことになるので注意してください。

スクリプトとしての起動

Mercurial拡張は単にMercurial APIを利用しているPythonのモジュールです。その出発点は次のようなスクリプトになります。

#!/usr/bin/python
# -*- coding: utf-8 -*-

from mercurial import ui, hg

def print_users(ui, repo, **opts):
    print repo

if __name__ == '__main__':
    ui   = ui.ui()
    repo = hg.repository(ui, ".") # カレントディレクトリのrepoオブジェクト
    print_users(ui, repo)

uiはユーザとのインタラクションを行うためのオブジェクトですが、単純な拡張であれば不要であるためここで説明しません。repoはリポジトリオブジェクトで、ここではカレントディレクトリのリポジトリを取得しています。また、後で拡張として呼び出せるようにするため、関数print_usersは3引数を取るようにしています。なお、optsはオプションのためのもので、この記事では使用しないため詳細は省略します。

このスクリプトを作業ディレクトリで実行すると次のようになります。

> python ~/src/print_users.py
<hgext.mq.mqrepo object at 0x101779890>

hgからの実行

先ほどのスクリプトをhgから実行できるようにしてみましょう。まず、.hgrc内のextensionsセクションに次のような行を追加します。

[extensions]
print_users=~/src/print_users.py

次に、先ほどのスクリプトの末尾に次のようにディクショナリcmdtableを書きます。これはコマンドラインオプションを解釈して適切に処理させるためのテーブルです。

cmdtable = {
    # "コマンド名": (関数, オプション, ヘルプ)
    "users":     (print_users, [], "print users")
}

これによって拡張をhgから呼び出すことができます。

> hg users 
<hgext.mq.mqrepo object at 0x1011db510>

コードの追加

さらに、関数print_usersを書き替えて、関数get_user_countを追加します。この関数はリビジョン0からtipまでの各リビジョンのユーザを調べていきます。関数print_usersではこれを利用して、コミット回数の多いユーザのトップ10を表示させます。

def print_users(ui, repo, **opts):
    user_count = get_user_count(repo)
    l = sorted(user_count, lambda i,j:user_count[j] - user_count[i])[:10]
    for i in l:
        print user_count[i], i

def get_user_count(repo):
    tip     = repo.changectx("tip")
    tip_rev = tip.rev()

    user_count = {}
    for i in range(tip_rev):
        ctx = repo.changectx(i)
        user = ctx.user()
        if user_count.has_key(user):
            user_count[user] += 1
        else:
            user_count[user]  = 1

    return user_count;

例えば、ある時点におけるMercurialリポジトリ上で実行すると次のような結果となりました (メールアドレス部は変更しています)。

> hg users
2324 Matt Mackall <mpm@example.com>
965 Thomas Arendsen Hein <thomas@example.com>
917 Benoit Boissinot <benoit.boissinot@example.com>
913 Martin Geisler <mg@example.com>
862 Patrick Mezard <pmezard@example.com>
768 mpm@example.com
617 Brendan Cully <brendan@example.com>
533 Alexis S. L. Carvalho <alexis@example.com>
498 Dirkjan Ochtman <dirkjan@example.com>
476 Vadim Gelfer <vadim.gelfer@example.com>

debugshell

拡張を書くときに便利なインタラクティブな環境としてdebugshell拡張が用意されています。これは、Mac portsの場合には.hgrcのextensionsセクションにdebugshell=/opt/local/share/mercurial/contrib/debugshell.pyと書くだけでよいです。

> hg debugshell
loaded repo : /Users/foobar/src/mysample
using source: /opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/mercurial
>>> repo
<hgext.mq.mqrepo object at 0x1011db5d0>
>>> cl
<mercurial.changelog.changelog object at 0x1011fa5d0>
>>> mercurial
<proxied module 'mercurial'>

まとめ

Mercurial拡張を作成する方法を説明しました。

関連記事

0 件のコメント:

コメントを投稿

注: コメントを投稿できるのは、このブログのメンバーだけです。