Mercurial скриптинг с питоном - PullRequest
29 голосов
/ 20 июля 2009

Я пытаюсь программно получить номер / идентификатор версии Mercurial (это хэш, а не номер) в Python.

Причина в том, что я хочу добавить его в файлы css / js на нашем сайте следующим образом:

<link rel="stylesheet" href="example.css?{% mercurial_revision "example.css" %}" />

Чтобы при изменении таблицы стилей он получал новый URL и больше не использовал старую кэшированную версию.

ИЛИ , если вы знаете, где найти хорошую документацию для ртутного модуля Python , это также будет полезно. Кажется, я нигде не могу его найти.

Мое решение

В итоге я использовал подпроцесс, чтобы просто запустить команду, которая получает узел hg. Я выбрал это решение, потому что API не гарантированно останется прежним, но интерфейс bash, вероятно, будет:

import subprocess

def get_hg_rev(file_path):
    pipe = subprocess.Popen(
        ["hg", "log", "-l", "1", "--template", "{node}", file_path],
        stdout=subprocess.PIPE
        )
    return pipe.stdout.read()

пример использования:

> path_to_file = "/home/jim/workspace/lgr/pinax/projects/lgr/site_media/base.css"
> get_hg_rev(path_to_file)
'0ed525cf38a7b7f4f1321763d964a39327db97c4'

Ответы [ 7 ]

15 голосов
/ 20 июля 2009

Это правда, что официального API нет, но вы можете получить представление о лучших практиках, прочитав другие расширения, особенно те, которые связаны с hg. Для этой конкретной проблемы я бы сделал что-то вроде этого:

from mercurial import ui, hg
from mercurial.node import hex

repo = hg.repository('/path/to/repo/root', ui.ui())
fctx = repo.filectx('/path/to/file', 'tip')
hexnode = hex(fctx.node())

Обновление В какой-то момент порядок параметров изменился, теперь это выглядит так:

   repo = hg.repository(ui.ui(), '/path/to/repo/root' )
8 голосов
/ 20 июля 2009

Вы имеете в виду эту документацию ?
Обратите внимание, что, как указано на этой странице, нет официального API, поскольку они по-прежнему оставляют за собой право изменить его в любое время. Но вы можете увидеть список изменений в последних нескольких версиях, он не очень обширный.

5 голосов
/ 25 февраля 2014

Обновленная, более чистая версия подпроцесса (использует .check_output(), добавлена ​​в Python 2.7 / 3.1), которую я использую в своем файле настроек Django для грубой сквозной проверки развертывания (я выкидываю ее в комментарий HTML):

import subprocess

HG_REV = subprocess.check_output(['hg', 'id', '--id']).strip()

Вы можете обернуть его в try, если не хотите, чтобы какой-то странный сбой предотвращал запуск:

try:
    HG_REV = subprocess.check_output(['hg', 'id', '--id']).strip()
except OSError:
    HG_REV = "? (Couldn't find HG)"
except subprocess.CalledProcessError as e:
    HG_REV = "? (Error {})".format(e.returncode)
except:
    # should never have to deal with a hangup 
    HG_REV = "???"
3 голосов
/ 02 марта 2015

Если вы используете Python 2, вы хотите использовать hglib.

Я не знаю, что использовать, если вы используете Python 3, извините. Возможно hgapi.

Содержание этого ответа

  • API Mercurial
  • Как использовать hglib
  • Почему hglib - лучший выбор для пользователей Python 2
  • Если вы пишете ловушку, этот обескураженный внутренний интерфейс очень удобен

API Mercurial

У Mercurial есть два официальных API.

  1. Сервер команд Mercurial. Вы можете общаться с ним из Python 2, используя пакет hglib ( wiki , PyPI ), который поддерживается командой Mercurial.
  2. Интерфейс командной строки Mercurial. Вы можете поговорить с ним через subprocess, или hgapi, или через некоторое время.

Как использовать hglib

Установка:

pip install python-hglib

Использование:

import hglib
client = hglib.open("/path/to/repo")

commit = client.log("tip")
print commit.author

Больше информации об использовании на странице вики hglib .

Почему hglib - лучший выбор для пользователей Python 2

Поскольку он поддерживается командой Mercurial, и это то, что команда Mercurial рекомендует для взаимодействия с Mercurial.

Из вики Mercurial следующее утверждение о взаимодействии с Mercurial:

Для подавляющего большинства стороннего кода наилучшим подходом является использование опубликованного, документированного и стабильного API Mercurial: интерфейса командной строки. Альтернативно, используйте CommandServer или библиотеки, основанные на нем, чтобы получить быстрый, стабильный, не зависящий от языка интерфейс.

Со страницы командного сервера:

[Командный сервер позволяет] сторонним приложениям и библиотекам взаимодействовать с Mercurial по каналу, который исключает накладные расходы при запуске каждой команды. Затем библиотеки могут инкапсулировать генерацию и синтаксический анализ команд, чтобы представить для этих команд соответствующий API язык.

Интерфейс Python для командного сервера Mercurial, как сказано, hglib.

Кстати, командные издержки интерфейса командной строки - не шутка. Однажды я создал очень маленький набор тестов (всего около 5 тестов), который использовал hg через subprocess для создания, фиксации с фиксацией, нескольких репозиториев, например, с. ситуации слияния. На протяжении всего проекта время выполнения пакета составляло от 5 до 30 секунд, при этом почти все время было потрачено на hg вызовы.

Если вы пишете ловушку, этот обескураженный внутренний интерфейс очень удобен

Подпись функции ловушки Python выглядит так:

# In the hgrc:
# [hooks]
# preupdate.my_hook = python:/path/to/file.py:my_hook

def my_hook(
    ui, repo, hooktype, 
    ... hook-specific args, find them in `hg help config` ..., 
    **kwargs)

ui и repo являются частью вышеупомянутого нежелательного неофициального внутреннего API . Тот факт, что они есть в ваших аргументах функций, делает их очень удобными в использовании, например, в этом примере preupdate ловушка, которая запрещает слияния между определенными ветвями.

def check_if_merge_is_allowed(ui, repo, hooktype, parent1, parent2, **kwargs):
    from_ = repo[parent2].branch()
    to_ = repo[parent1].branch()
    ...
    # return True if the hook fails and the merge should not proceed.

Если ваш код перехвата не так важен, и вы его не публикуете, вы можете использовать не рекомендуемый неофициальный внутренний API. Если ваш хук является частью расширения, которое вы публикуете, лучше использовать hglib.

3 голосов
/ 20 июля 2009
1 голос
/ 26 ноября 2012

FWIW, чтобы избежать извлечения этого значения на каждой странице / просмотре рендера, я просто перенес его в файл settings.py. Тогда я могу сослаться на settings.REVISION без лишних затрат на доступ к Mercurial и / или другому процессу. Вы когда-нибудь меняли это значение без перезагрузки сервера?

0 голосов
/ 26 ноября 2012

Я хотел сделать то же самое, что и ОП, получить hg id -i из скрипта (получить ревизию всего хранилища, а не одного ФАЙЛА в этом репо), но я не хотел использовать popen, и код из brendan заставил меня начать, но не то, что я хотел.

Итак, я написал это ... Комментарии / критика приветствуются. Получает подсказку rev в шестнадцатеричном виде в виде строки.

from mercurial import ui, hg, revlog
# from mercurial.node import hex  # should I have used this?

def getrepohex(reporoot):
    repo = hg.repository(ui.ui(), reporoot)
    revs = repo.revs('tip')
    if len(revs)==1:
      return str(repo.changectx(revs[0]))
    else:
      raise Exception("Internal failure in getrepohex")
...