Содержание
Mercurial предоставляет мощный механизм позволяющий контролировать как будет выводиться информация. Механизм базируется на шаблонах. Вы можете использовать шаблоны для генерации специфичного вывода одной команды или настроить весь вывод встроенного web интерфейса.
Пакет Mercurial поставляется с некоторыми стилями вывода, которые вы можете использовать незамедлительно. Стиль — просто предустановленный шаблон, который кто-то написал и установил где-либо и который может найти Mercurial.
До того как мы рассмотрим встроенные стили, давайте взглянем на обычный вывод.
$
hg log -r1
changeset: 1:6f5ce6bc1898 tag: mytag user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:09 2012 +0000 summary: added line to end of <<hello>> file.
Это информативно, но занимает довольно много места — пять линий на набор изменений. Стиль compact
уменьшает это до трех линий, представленных в разреженном виде.
$
hg log --style compact
3[tip] c19f42cb5b95 2012-02-02 14:10 +0000 bos Added tag v0.1 for changeset b94147c22394 2[v0.1] b94147c22394 2012-02-02 14:10 +0000 bos Added tag mytag for changeset 6f5ce6bc1898 1[mytag] 6f5ce6bc1898 2012-02-02 14:10 +0000 bos added line to end of <<hello>> file. 0 5b2b97feb76c 2012-02-02 14:10 +0000 bos added hello
Стиля changelog
показывает выразительность и мощь шаблонного движка в Mercurial. Стиль следует принципам проекта GNU для отображения changelog[web:changelog].
$
hg log --style changelog
2012-02-02 Bryan O'Sullivan <bos@serpentine.com> * .hgtags: Added tag v0.1 for changeset b94147c22394 [c19f42cb5b95] [tip] * .hgtags: Added tag mytag for changeset 6f5ce6bc1898 [b94147c22394] [v0.1] * goodbye, hello: added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye. [6f5ce6bc1898] [mytag] * hello: added hello [5b2b97feb76c]
Вы не будете шокированы, узнав, что стиль вывода Mercurial по умолчанию называется default
.
Вы можете изменить стиль вывода, который Mercurial будет использовать для каждой команды, редактируя файл ~/.hgrc
, указав стиль который вы предпочитаете использовать.
[ui] style = compact
Если вы напишете свой стиль, вы можете использовать его, либо указав путь к файлу стиля или скопировав файл стиля в папку, в которой mercurial сможете его найти (как правило, шаблоны расположены в поддиректории templates
того каталога, куда установлен Mercurial).
Все команды Mercurial «похожие на log
» позволяют использовать стили и шаблоны: hg incoming, hg log, hg outgoing, и hg tip.
Когда я писал это руководство, только эти команды, поддерживали стили и шаблоны. Поскольку это наиболее важные команды, у которых должен настраиваться вывод, давление со стороны сообщества Mercurial по поводу возможности пользователю добавлять стили и шаблоны для других команд было небольшим.
В самом простом случае шаблон mercurial это фрагмент текста. Часть текста не меняется, в то время как другая часть развёртывается и заменяется новым текстом, в случае необходимости.
Для начала давайте посмотрим, как обычно Mercurial оформляет вывод.
$
hg log -r1
changeset: 1:6f5ce6bc1898 tag: mytag user: Bryan O'Sullivan <bos@serpentine.com> date: Thu Feb 02 14:10:09 2012 +0000 summary: added line to end of <<hello>> file.
Теперь, давайте выполним ту же команду, но с использованием шаблона для изменяющего данный вывод.
$
hg log -r1 --template 'i saw a changeset\n'
i saw a changeset
Приведенный выше пример иллюстрирует простейший шаблон, это просто статичный текст, напечатанный один раз для каждой ревизии. Опция --template
команды hg log говорит Mercurial использовать данный текст в качестве шаблона при печати каждой ревизии.
Обратите внимание, что строки шаблона заканчиваются текстом «\n
». Это управляющая последовательность, говорящая Mercurial печатать новую строку в конце каждого пункта шаблона. Если вы пропустите этот символ новой строки, Mercurial будет печатать все блоки на одной строке. Смотрите раздел Раздел 11.5, «Escape последовательности»; для более подробной информации о управляющих последовательностях.
Шаблон, который выводит фиксированную строку текста все время не очень полезен, давайте попробуем что-нибудь более сложное.
$
hg log --template 'i saw a changeset: {desc}\n'
i saw a changeset: Added tag v0.1 for changeset b94147c22394 i saw a changeset: Added tag mytag for changeset 6f5ce6bc1898 i saw a changeset: added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye. i saw a changeset: added hello
Как видите, строка «{desc}
»> в шаблоне заменяется на выходе описанием каждой ревизии. Каждый раз, когда Mercurial читает, текст, заключенный в фигурные скобки («{
» и «}
»), он будет пытаться заменить фигурные скобки и текст подставляя все, что внутри. Для печати символа фигурной скобки, вы должны экранировать ее, как описано в разделе Раздел 11.5, «Escape последовательности».
Вы можете начать писать простые шаблоны, сразу же с помощью ключевых слов указанных ниже.
branches
: string. Название ветки, в которой была зафиксирована ревизия. Будет пустым, если имя ветки default
.
date
: Дата. Дата, когда была зафиксирована ревизия. Эта дата не человекочитаема, надо пропустить её через фильтр, чтобы отобразить её соответствующим образом. Смотрите раздел Раздел 11.6, «Фильтрация ключевых слов, чтобы отобразить результат» для получения дополнительной информации об этих фильтрах. Дата выражается в виде пары чисел. Первое метка времени Unix UTC (в секундах с 1 января 1970); второе является смещением часового пояса коммиттера от UTC в секундах.
files
: Список строк. Все файлы, измененные, добавленные или удаленные в этой ревизии.
node
: string. Идентификационный хеш ревизии, 40-символьная шестнадцатеричная строка.
Несколько простых экспериментов покажет нам, чего ожидать, когда мы используем эти слова, вы можете увидеть результаты ниже.
$
hg log -r1 --template 'author: {author}\n'
author: Bryan O'Sullivan <bos@serpentine.com>$
hg log -r1 --template 'desc:\n{desc}\n'
desc: added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.$
hg log -r1 --template 'files: {files}\n'
files: goodbye hello$
hg log -r1 --template 'file_adds: {file_adds}\n'
file_adds: goodbye$
hg log -r1 --template 'file_dels: {file_dels}\n'
file_dels:$
hg log -r1 --template 'node: {node}\n'
node: 6f5ce6bc18989ecdb1e0ddf5d63d539787a66eb2$
hg log -r1 --template 'parents: {parents}\n'
parents:$
hg log -r1 --template 'rev: {rev}\n'
rev: 1$
hg log -r1 --template 'tags: {tags}\n'
tags: mytag
Как мы уже отмечали выше, ключевое слово date выводит не человекочитаемый текст, поэтому мы должны обрабатывать его специально. Это связано с использованием фильтров, о которых смотрите в разделе Раздел 11.6, «Фильтрация ключевых слов, чтобы отобразить результат».
$
hg log -r1 --template 'date: {date}\n'
date: 1328191809.00$
hg log -r1 --template 'date: {date|isodate}\n'
date: 2012-02-02 14:10 +0000
Движок шаблонов Mercurial распознаёт наиболее часто используемые управляющие последовательности в строках. Когда он видит символ обратной косой черты («\
»), он читает следующий символ и заменяет 2 символа на один, как описано ниже.
Как указано выше, если вы хотите при развёртывании шаблона использовать символы «\
», «{
» или «}
», вы должны экранировать их.
Некоторые из результатов расширения шаблона не просты в использовании. Mercurial позволяет указать необязательную цепочку фильтров, чтобы изменить результат расширения ключевого слова. Вы уже видели, общий фильтр, isodate
, в действии выше, чтобы сделать дату читаемой.
Ниже приведен список наиболее часто используемых фильтров, которые поддерживает Mercurial. Некоторые фильтры могут быть применены к любому тексту, а другие могут быть использованы только в конкретных обстоятельствах. За именем каждого фильтра ниже сначала следует описание, где он может быть использован, а потом описание его действия.
addbreaks
: Любой текст. Добавляет тег XHTML «<br/>
» перед концом каждой строки, кроме последней. Например, «foo\nbar
» преобразуется в «foo<br/>\nbar
».
age
: ключевое слово date
. Формирует интервал времени который прошел со времени ревизии до текущего времени. Возвращает строку типа «10 minutes
».
basename
: Любой текст, но наиболее полезна для работы с ключевым словом files
и похожими. Применённый к пути файла, и верней имя файла. Например, «foo/bar/baz
» преобразуется в «baz
».
date
: ключевое слово date
. Формирует дату в том же формате, что и команда Unix date
, но с указанием часового пояса. Возвращает строку, например «Mon Sep 04 15:13:13 2006 -0700
».
domain
: Любой текст, но наиболее полезно для ключевого слова author
. Находит первую строку, которая выглядит как адрес электронной почты, и извлекает только доменную часть. Например, «Bryan O'Sullivan <bos@serpentine.com>
» преобразуется в «serpentine.com
».
email
: Любой текст, но наиболее полезно для ключевого слова author
. Находит первую строку, которая выглядит как адрес электронной почты, и извлекает email. Например, «Bryan O'Sullivan <bos@serpentine.com>
» преобразуется в «bos@serpentine.com
».
escape
: Любой текст. Заменяет спецсимволы XML/XHTML «&
», «<
» и «>
» на XML-entities.
fill68
: Любой текст. Разбивает текст чтоб он помещался в 68 колонок. Это полезно, сделать перед тем как передать текст на фильтр tabindent
, если мы все еще хотим, чтобы он помещается в 80 колонок фиксированного шрифта окна.
fill76
: Любой текст. Разбивает текст чтоб он помещался в 76 колонок.
firstline
: Любой текст. Возвращает первую строку текста, без завершающих строк.
hgdate
: ключевое слово date
. Генерирует дату, как пара читаемых чисел. Возвращает строку вида «1157407993 25200
».
isodate
: ключевое слово date
. Генерирует дату, как текстовую строку в формате ISO 8601. Возвращает строку вида «2006-09-04 15:13:13 -0700
».
obfuscate
: Любой текст, но наиболее полезно для ключевого слова author
. Возвращает текст преобразованный в последовательность XML entities. Это помогает победить некоторых, особенно глупых сканеров собирающих адреса для спам-ботов.
person
: Любой текст, но наиболее полезно для ключевого слова author
. Возвращает текст перед адресом email. Например, «Bryan O'Sullivan <bos@serpentine.com>
» преобразуется в «Bryan O'Sullivan
».
rfc822date
: ключевое слово date
. Генерирует дату, как текстовую строку в формате использующемся в заголовках email. Возвращает строку вида «Mon, 04 Sep 2006 15:13:13 -0700
».
short
: Хеш ревизии. Возвращает короткую форму хеша ревизии. 12-символьную шестнадцатеричную строку.
shortdate
: ключевое слово date
. Генерирует год, месяц и день даты. Возвращает строку вида «2006-09-04
».
strip
: Любой текст. Удаляет все начальные и конечные пробелы из строки.
tabindent
: Любой текст. Возвращает текст в котором каждая строка, кроме первой, начинаются с символа табуляции.
urlescape
: Любой текст. Экранирует все символы, которые считаются «специальными» для url-анализаторов. Так, например, foo bar
преобразуется в foo%20bar
.
user
: Любой текст, но наиболее полезно для ключевого слова author
. Возвращает часть «user» из email адреса. Например, «Bryan O'Sullivan <bos@serpentine.com>
» преобразуется в «bos
».
$
hg log -r1 --template '{author}\n'
Bryan O'Sullivan <bos@serpentine.com>$
hg log -r1 --template '{author|domain}\n'
serpentine.com$
hg log -r1 --template '{author|email}\n'
bos@serpentine.com$
hg log -r1 --template '{author|obfuscate}\n' | cut -c-76
Bryan O'Sulli$
hg log -r1 --template '{author|person}\n'
Bryan O'Sullivan$
hg log -r1 --template '{author|user}\n'
bos$
hg log -r1 --template 'looks almost right, but actually garbage: {date}\n'
looks almost right, but actually garbage: 1328191809.00$
hg log -r1 --template '{date|age}\n'
2 seconds ago$
hg log -r1 --template '{date|date}\n'
Thu Feb 02 14:10:09 2012 +0000$
hg log -r1 --template '{date|hgdate}\n'
1328191809 0$
hg log -r1 --template '{date|isodate}\n'
2012-02-02 14:10 +0000$
hg log -r1 --template '{date|rfc822date}\n'
Thu, 02 Feb 2012 14:10:09 +0000$
hg log -r1 --template '{date|shortdate}\n'
2012-02-02$
hg log -r1 --template '{desc}\n' | cut -c-76
added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some m$
hg log -r1 --template '{desc|addbreaks}\n' | cut -c-76
added line to end of <<hello>> file.<br/> <br/> in addition, added a file with the helpful name (at least i hope that some m$
hg log -r1 --template '{desc|escape}\n' | cut -c-76
added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some m$
hg log -r1 --template '{desc|fill68}\n'
added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.$
hg log -r1 --template '{desc|fill76}\n'
added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.$
hg log -r1 --template '{desc|firstline}\n'
added line to end of <<hello>> file.$
hg log -r1 --template '{desc|strip}\n' | cut -c-76
added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some m$
hg log -r1 --template '{desc|tabindent}\n' | expand | cut -c-76
added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope tha$
hg log -r1 --template '{node}\n'
6f5ce6bc18989ecdb1e0ddf5d63d539787a66eb2$
hg log -r1 --template '{node|short}\n'
6f5ce6bc1898
Легко объединять фильтры для получения нужного результата. Следующая цепочка фильтров приводит в порядок описание, убеждаемся что оно влезает в 68 столбцов, потом вставляем отступы в 8 символов (по крайней мере на unix-подобных системах, где табуляция условно занимает 8 символов).
$
hg log -r1 --template 'description:\n\t{desc|strip|fill68|tabindent}\n'
description: added line to end of <<hello>> file. in addition, added a file with the helpful name (at least i hope that some might consider it so) of goodbye.
Обратите внимание на использование «\t
» (символ табуляции) в шаблоне, чтобы заставить первую строку отступить, это необходимо, поскольку tabindent
вставляем отступы везде, кроме первой строки.
Имейте в виду, что порядок фильтров в цепочке является важным. Первый фильтр применяется к результату ключевого слова, второй к результату первого фильтра, и так далее. Например, использование fill68|tabindent
даст очень разные результаты в сравнении с tabindent|fill68
.
Шаблон в командной строке предоставляет простой и быстрый способ для форматирования некоторого вывода. Шаблоны могут стать слишком многословным, хотя, и это полезно, чтобы иметь возможность указать имени шаблон. Файл стиля представляет собой шаблон с именем, хранящийся в файле.
Более того, использование файла стиля открывает силу движка шаблонов Mercurial таким образом, который не представляется возможным с помощью опции командной строки --template
.
Наш простой файл стиля содержит всего одну строчку:
$
echo 'changeset = "rev: {rev}\n"' > rev
$
hg log -l1 --style ./rev
rev: 3
Это указывает Mercurial, «при печати ревизии, используй текст справа как шаблон»
Синтаксические правила файла стиля просты.
Если строка начинается с одного из символов «#
» или «;
», эта строка считается комментарием и пропускается как пустая.
Строка начинается с ключевого слова. Оно должно начинаться с буквы или символа подчеркивания, и может в дальнейшем содержать любые алфавитно-цифровые символы и знак подчеркивания. (Ключевое слово должно удовлетворять следующему регулярному выражению [A-Za-z_][A-Za-z0-9_]*
.)
Следующий элемент должен быть символ «=
», в окружении произвольного количества пробелов.
Если остальная часть строки начинается и заканчивается с соответствующими кавычками (как одинарными, так и двойными), она рассматривается в качестве тела шаблона.
Если остальная часть строки не начинается с кавычки, то она рассматривается как имя файла, содержимое этого файла будет читаться и использоваться в качестве тела шаблона.
Чтобы показать, как писать стилевой файл, напишем несколько примеров. Вместо того, чтобы обеспечивать полный стилевой файл и проходить по нему, мы отобразим обычный процесс разработки стилевого файла, начиная с чего-то очень простого, и переходя через набор последовательно более полных примеров.
Если Mercurial сталкивается с проблемой в файле стиля, с которым вы работаете, он печатает краткие сообщения об ошибках на самом деле очень полезными, как только вы поймёте, что они означают.
$
cat broken.style
changeset =
Обратите внимание, что broken.style
пытается определить ключевое слово changeset
, но забывает дать какой-либо контент для него. Когда вы указываете Mercurial использовать этот файл стиля, он оперативно жалуется.
$
hg log -r1 --style broken.style
** unknown exception encountered, please report by visiting ** http://mercurial.selenic.com/wiki/BugTracker ** Python 2.7.2 (default, Nov 3 2011, 15:14:27) [GCC 4.5.3] ** Mercurial Distributed SCM (version 2.0) ** Extensions loaded: Traceback (most recent call last): File "/usr/bin/hg-2.7", line 38, in <module> mercurial.dispatch.run() File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 27, in run sys.exit(dispatch(request(sys.argv[1:]))) File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 64, in dispatch return _runcatch(req) File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 87, in _runcatch return _dispatch(req) File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 684, in _dispatch cmdpats, cmdoptions) File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 466, in runcommand ret = _runcommand(ui, options, cmd, d) File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 738, in _runcommand return checkargs() File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 692, in checkargs return cmdfunc() File "/usr/lib64/python2.7/site-packages/mercurial/dispatch.py", line 681, in <lambda> d = lambda: util.checksignature(func)(ui, *args, **cmdoptions) File "/usr/lib64/python2.7/site-packages/mercurial/util.py", line 454, in check return func(*args, **kwargs) File "/usr/lib64/python2.7/site-packages/mercurial/commands.py", line 3822, in log displayer = cmdutil.show_changeset(ui, repo, opts, True) File "/usr/lib64/python2.7/site-packages/mercurial/cmdutil.py", line 893, in show_changeset t = changeset_templater(ui, repo, patch, opts, mapfile, buffered) File "/usr/lib64/python2.7/site-packages/mercurial/cmdutil.py", line 762, in __init__ cache=defaulttempl) File "/usr/lib64/python2.7/site-packages/mercurial/templater.py", line 298, in __init__ if val[0] in "'\"": IndexError: string index out of range
Это сообщение об ошибке выглядит устрашающе, но его не слишком трудно исследовать.
Первым компонент является просто способом Mercurial сказать: «Я прерываю выполнение».
___abort___: broken.style:1: parse error
Далее идёт название файла стиля который содержит ошибку
abort: ___broken.style___:1: parse error
После имени файла идёт номер строки, где произошла ошибка.
abort: broken.style:___1___: parse error
Наконец, описание того, что пошло не так.
abort: broken.style:1: ___parse error___
Описание проблемы, не всегда понятно (как в данном случае), но даже если оно загадочно, то проблема почти всегда тривиальна, посмотрите на указанную строку в файле стиля и посмотрите, что в ней неправильно.
Если вы хотите, иметь возможность определить репозиторий Mercurial «довольно однозначно», используя короткую строку, в качестве идентификатора, вы можете использовать первую ревизию в репозитории.
$
hg log -r0 --template '{node}'
618e49b7b3328b9f52044186fc5089f37ebce576
Она может быть уникальной, и поэтому она является полезной во многих случаях. Есть несколько предостережений.
Предположим, мы хотим, чтобы список файлов изменившихся в ревизии, по одному на строке, с небольшой отступом перед каждым именем файла.
$
cat > multiline << EOF
>
changeset = "Changed in {node|short}:\n{files}"
>
file = " {file}\n"
>
EOF
$
hg log --style multiline
Changed in bb7c31cb2621: .bashrc .hgrc test.c
Давайте попробуем подражать формату вывода который по умолчанию использует другой инструмент контроля версий, Subversion.
$
svn log -r9653
------------------------------------------------------------------------ r9653 | sean.hefty | 2006-09-27 14:39:55 -0700 (Wed, 27 Sep 2006) | 5 lines On reporting a route error, also include the status for the error, rather than indicating a status of 0 when an error has occurred. Signed-off-by: Sean Hefty <sean.hefty@intel.com> ------------------------------------------------------------------------
Стиль с выводом похожим на Subversion является достаточно простым, легко скопировать и вставить кусок его вывода в файл, и заменить текст, подготовленный выше Subversion шаблонными значениями, которые мы хотели бы видеть при развёртывании.
$
cat svn.template
r{rev} | {author|user} | {date|isodate} ({date|rfc822date}) {desc|strip|fill76} ------------------------------------------------------------------------
Есть несколько мелочей, в котором этот шаблон отличается от вывода, производимого Subversion.
Subversion печатает «читаемую» дату (как «Wed, 27 Sep 2006
» в примере выше) в скобках. Шаблон движка Mercurial не дает возможности отображения даты в этом формате без печати времени и часового пояса.
Мы подражать выводу Subversion вместе с «разделителем» строкой, заполненной символами «-
» путем завершения шаблона такой строкой. Мы используем ключевое слово header
шаблонного движка для печати разделительной линии в качестве первой строки вывода (см. ниже), что позволит достичь аналогичного вывода в Subversion.
Вывод Subversion включает в себя в заголовке счётчик строк в сообщении фиксации. Мы не можем повторить это в Mercurial; шаблонный движок в настоящее время не обеспечивает фильтр, который подсчитывает количество строк сгенирированных шаблоном.
Мне потребовалось не более минуты или две работы, заменить точный текст из примера с выводом Subversion с некоторыми ключевыми словами и фильтрами используемыми в шаблоне выше. Файл стиля содержит ссылку на шаблон.
$
cat svn.style
header = '------------------------------------------------------------------------\n\n' changeset = svn.template
Мы могли бы включить текст шаблона непосредственно в файл стиля, заключив его в кавычки и заменяя перевод строк на последовательность «\n
», но это сделало бы файл стиля слишком трудночитаемым. Читаемость является хорошим руководством, когда вы пытаетесь решить, будет ли какой-нибудь текст принадлежит файлу стиля или файлу шаблона. Если файл стиля будет выглядеть слишком большим или непонятным если вы вставите шаблон точным фрагментом текста, поместите его лучше в шаблон.