Работаем с меркуриалом из питона¶
Занимаюсь потихоньку своим толстым редактором po-файлов, и захотелось сделать интеграцию с меркуриалом. Поэтому начал копать вот эту документацию http://mercurial.selenic.com/wiki/MercurialApi и исходники (/usr/local/lib/python2.6/dist-packages/mercurial/).
Итак, для начала:
from mercurial import ui as mercurial_ui, hg, commands
ui = mercurial_ui.ui()
repo = hg.repository(ui, '/home/kost/workspace/3.1.1-i18n/')
В меркуриале есть модуль commands, в котором функции – по сути команды в командной строе. То есть, чтоб сделать
hg log --limit 2
вы можете вызвать
commands.log(ui, repo, limit=2, date=None, rev=None, user=None)
Note
Заметьте кучу ненужных date=None, rev=None, user=None. По идее их быть не должно, но так уж исторически сложилось что в меркуриале много “обязательных” параметров. Если он ругается, что какого-то не хватает, просто передайте его как None.
Но нас не интересует эта штука, потому что она тупо печатает вывод команды (а мы ведь не собираемся её парсить, а хотим нормальной работы). Потому попытаемся получить hg log в виде списка ченджсетов.
В официальной вики (по той же ссылке) документация о Change contexts имеется, но она довольно скудная.
Вообще задача состоит в том, чтоб пройтись по ревизиям конкретных файлов (мы предварительно найдём все .po-файлы в репозитории) и сделать что-то с содержанием этих файлов в той ревизии. Для начала хотя бы научимся ходить по ревизиям.
Мне удалось этого добиться как-то вот так:
opts = {'rev': None,}
limit = 10
pats = [os.path.join(REPO_PATH, 'uaprom/i18n/tr/LC_MESSAGES/uaprom.po')]
matchfn = cmdutil.match(repo, pats, opts)
def prep(ctx, fns):
pass
for i, ctx in enumerate(cmdutil.walkchangerevs(repo, matchfn, opts, prep)):
i += 1
print ctx
if i >= limit:
break
Честно скажу, что как API (даже тот, который более-менее внутренний), так и сам стиль кодирования (везде геттеры через функции с именем аргумента, частое использование во внутренних функциях внешних переменных) мне показались крайне странными и не-питонячьими.
Если вам нужно просто получить содержимое какого-то файла в какой-то ревизии – тут дела обстоят лучше, есть способ “попроще”.
filectx = repo[ctx.rev()][pofiles[0]]
file_data = mercurial.encoding.fromlocal(filectx.data())
Затем я продолжил копаться в исходниках меркуриала и того, как он устроен (в конце концов, должен быть какой-то путь попроще для этого всего и покрасивее), пока меня не остановили.
Внезапно появляется vcs¶
И тут, внезапно на канале #mercurial (freenode) мне советуют посмотреть в сторону пакета vcs.
И теперь всё стало намного проще:
repo = vcs.get_repo(path=REPO_PATH)
pofiles = ['uaprom/i18n/tr/LC_MESSAGES/uaprom.po']
for pofile in pofiles:
print repo.get_changeset().get_node(pofile).content[:1000]
API намного лучше и чище нативного (хотя все равно мне кажется немного странным), плюс получим поддержку из коробки и гита заодно. Но (насколько я понял), искать все po-файлы нам все равно придется руками. Ну что ж, это уже не такой большой минус.