MQ の適用済パッチのログメッセージを一括取得する extension を書いた

たとえば,

$ hg qpush
applying 248.diff
now at: 248.diff

$ hg qpush
applying 249.diff
now at: 249.diff

$ hg qseries -s
248.diff: 記事追加機能を仮実装した(うまくいっていない)
249.diff: 記事追加機能を修正した
250.diff: 記事編集機能を実装した

こんな状況の場合 hg qseries -s でだいたいの変更内容は取得できるんだけど,一つのパッチ(コミット)のログが複数行にわたる場合,これだけだとわかんない。

いちおう,hg log -v すると,複数行のログもとれる。

$ hg log -r qbase:qtip -v
changeset:   248:cf52d09c494d
tag:         qbase
user:        dayflower <dayflower@example.com>
date:        Tue Jun 23 14:22:08 2009 +0900
files:       lib/AddArticle.pm
description:
記事追加機能を仮実装した(うまくいっていない)


changeset:   249:94502ca09ad5
tag:         qtip
tag:         tip
user:        dayflower <dayflower@example.com>
date:        Tue Jun 23 14:41:07 2009 +0900
files:       lib/AddArticle.pm db/schema.sql
description:
記事追加機能を修正した
スキーマを変更した

だけど,なにかと冗長な情報になってしまう。

今回つくった extension を使うと,

$ hg qlog
[248:cf52d09c494d]
記事追加機能を仮実装した(うまくいっていない)

[249:94502ca09ad5]
記事追加機能を修正した
スキーマを変更した

のように,qbaseqtip(つまり applied queue)に限って,changeset ID とログメッセージを取得することができます。

これをコピペすれば,他の VCS へコミットするときのコミットメッセージに使える,というわけです。


実は hg log には表示に使うテンプレートを指定する機能があるので,それ使えば同じようなことは標準のモジュールだけでできるんだけど,勉強のために extension として書いてみました。

# qlog.py

from mercurial import context, util, cmdutil, error
from mercurial.i18n import _
from mercurial.node import hex, short

class qlog_printer(cmdutil.changeset_printer):
    def _show(self, ctx, copies, prop):
        changenode = ctx.node()
        log        = self.repo.changelog
        changes    = log.read(changenode)

        self.ui.write(_("[%d:%s]\n") % (ctx.rev(), short(changenode)))

        description = changes[4].strip()
        if description:
            self.ui.write(description)
            self.ui.write("\n")

        self.ui.write("\n")

def qlog(ui, repo):
    try:
        repo.lookup('qbase')
        repo.lookup('qtip')
    except error.RepoError:
        return

    get = util.cachefunc(lambda r: repo[r].changeset())
    changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, [], get,
                                                 {'rev': ['qbase:qtip']})

    patch = False       # matchfn or cmdutil.matchall(repo)

    displayer = qlog_printer(ui, repo, patch, {}, True)

    for st, rev, fns in changeiter:
        if st == 'add':
            displayer.show(context.changectx(repo, rev))
        elif st == 'iter':
            displayer.flush(rev)

cmdtable = {
    "qlog": (qlog, [], _('hg qlog')),
}

コード自体は Mercurial のコードをコピペしたので,あんまり見通しはよくないです*1

extension でコマンドを実装するには,このように cmdtable というテーブル変数に関数などを登録しておけばいいみたい。


この extension のインストールのしかたは,適当な場所において,.hgrc

[extensions]
qlog=/home/dayflower/hgext/qlog.py

とかみたく,extension を置いた場所をフルパスで指定すればいいです。このへんのしくみは非常にお手軽ですね。

*1:てか Mercurial のコードは期待したほど綺麗な構造でもなかった。