Создание сценариев Mercurial с помощью python
Вопрос
Я пытаюсь получить номер / идентификатор версии mercurial (это хэш, а не число) программно в python.
Причина в том, что я хочу добавить его в css / js файлы на нашем веб-сайте следующим образом:
<link rel="stylesheet" href="example.css?{% mercurial_revision "example.css" %}" />
Таким образом, всякий раз, когда в таблицу стилей вносятся изменения, она получает новый URL-адрес и больше не использует старую кэшированную версию.
или если вы знаете, где найти хорошую документацию для mercurial модуль 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'
Решение
Это правда, что официального 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' )
Другие советы
Ты имеешь в виду эта документация?
Обратите внимание, что, как указано на этой странице, нет официальный API, потому что они по-прежнему оставляют за собой право изменять его в любое время.Но вы можете посмотреть список изменений в последних нескольких версиях, он не очень обширный.
Обновленная, более чистая версия подпроцесса (использует .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 Exception: # don't use bare 'except', mis-catches Ctrl-C and more
# should never have to deal with a hangup
HG_REV = "???"
дайте попробовать, чтобы расширение ключевого слова
Если вы используете Python 2, вы хотите использовать hglib
.
Я не знаю, что использовать, если вы используете Python 3, извините.Вероятно hgapi
.
Содержание этого ответа
- API-интерфейсы Mercurial
- Как использовать hglib
- Почему hglib - лучший выбор для пользователей Python 2
- Если вы пишете хук, этот обескураженный внутренний интерфейс ужасно удобен
API-интерфейсы Mercurial
Mercurial имеет два официальных API.
- Командный сервер Mercurial.Вы можете общаться с ним из Python 2, используя
hglib
(Вики, PyPI ( ПиПИ )) пакет, который поддерживается командой Mercurial. - Интерфейс командной строки 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:интерфейс командной строки.В качестве альтернативы используйте Командный сервер или библиотеки, которые основаны на нем, чтобы получить быстрый, стабильный, не зависящий от языка интерфейс.
Со страницы командного сервера:
[Командный сервер позволяет] сторонним приложениям и библиотекам взаимодействовать с Mercurial по каналу, что устраняет накладные расходы на запуск для каждой команды.Затем библиотеки могут инкапсулировать генерацию и синтаксический анализ команд, чтобы представить для этих команд соответствующий языку API.
Интерфейс Python к командному серверу Mercurial, как уже было сказано, является hglib
.
Кстати, накладные расходы интерфейса командной строки для каждой команды - это не шутка.Однажды я создал очень небольшой набор тестов (всего около 5 тестов), который использовал hg
через subprocess
чтобы создать, фиксируя за фиксацией, несколько репозиториев, например, собъединяйте ситуации.На протяжении всего проекта время выполнения suite составляло от 5 до 30 секунд, причем почти все время проводилось в hg
звонки.
Если вы пишете хук, этот обескураженный внутренний интерфейс ужасно удобен
Сигнатура функции Python hook выглядит следующим образом:
# 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
.
FWIW чтобы избежать извлечения этого значения при каждом рендеринге страницы / вида, я просто помещаю его в settings.py
файл.Тогда я могу сослаться settings.REVISION
без всех накладных расходов, связанных с доступом к mercurial и / или другому процессу.Менялось ли у вас когда-нибудь это значение без перезагрузки вашего сервера?
Я хотел сделать то же самое, что хотела сделать оперативная группа, получить hg id -i
из скрипта (получите подсказку о пересмотре всего репозитория, а не отдельного файла в этом репозитории), но я не хотел использовать popen, и код из brendan
это заставило меня начать, но это было не то, чего я хотел.
Итак, я написал это...Комментарии / критика приветствуются.Это возвращает значение tip 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")