5/11/2009

Отслеживание версий документов LaTeX с помощью скрипта на Python

... и сверху ещё майонезом полить :-) На самом деле, задача вполне актуальная, а именно: есть документ LaTeX, с которым работает много людей - в документ вносятся правки. Большинство людей LaTeX не приемлют по личным причинам. По рукам ходит много распечаток документа разных версий, и нужно отслеживать, какая версия документа у каждого из них.

Публикуемое решение задачи довольно простое: LaTeX с помощью скрипта на Python узнаёт номер версии документа, находящегося под контролем системы управления версиями Subversion, и впечатывает в документ номер версии.
В примере приводится система контроля версий Subversion, о которой уже говорилось, но при желании можно использовать вашу любимую систему контроля версий.

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

Далее нам нужно в текст LaTeX-документа добавить скрипт на Python. Для этого сначала нужно научиться вызывать Python внутри LaTeX, что довольно просто благодаря замечательной статье Python внутри LaTeX ув. тов. jetxee. Итак, требуется:

  • скачать файл python.sty и скопировать его в каталог с документом;
  • в документе в преамбуле включить \usepackage{python};
  • внутри документа фрагменты кода на Python помещать в окружение \begin{python} ... \end{python} - теперь всё, что они выведут, станет частью конечного документа;
  • запускать LaTeX теперь нужно с опцией -shell-escape для запуска встроенного кода из-под LaTeX
Ну и, естественно, нужно иметь рабочий Python на машине. Впрочем, если у вас десктоп с графической оболочкой и обвешан разными рюшками, Python у вас скорее всего уже есть.

Так, всё по отдельности у нас есть, и осталось запалить всё это вместе. Для этого в документ вставляем код (кусок реального документа, чтобы было понятно):

\documentclass[a4paper,10pt,oneside]{article}
\usepackage[T2A]{fontenc}
\usepackage[koi8-r]{inputenc}
\usepackage[russian,english]{babel}
\usepackage{amssymb,amsfonts,amsmath,mathtext}
\usepackage{cite,enumerate,float,indentfirst}
\usepackage{caption2,tabularx}
\usepackage[dvips]{graphicx}
\graphicspath{{pictures/}}

%<--------------Pythonated trick starts HERE!
\usepackage{fancybox,fancyhdr}
\usepackage{python}
\fancyhead[R]{}
\fancyhead[L]{}
\fancyhead[C]{}
\fancyfoot[R]{}
\fancyfoot[C]{\textit{\textbf{\input{svnstatus}}}}
\fancyfoot[L]{}
\begin{python}
#! /usr/bin/python
import os, string
cmd = 'svn status ИМЯФАЙЛАТУТ.tex -v'
fpipe = os.popen(cmd)
piperesult = fpipe.read()
fpipe.close()
results = piperesult.split()
if results[0] == 'M':
out = 'Subversion revision of this document is '+results[1]+', last modified by '+results[3]+', STATUS: '+results[0]
else:
out = 'Subversion revision of this document is '+results[1]+', last modified by '+results[2]
FileName='svnstatus.tex'
fout=open(FileName,'w')
fout.write(out)
fout.close()
\end{python}
%<--------------Pythonated trick ends HERE!


\makeatletter
\bibliographystyle{unsrt} %Стиль библиографических ссылок БибТеХа
% Заменяем библиографию с квадратных скобок на точку:
\renewcommand{\@biblabel}[1]{#1.}
\makeatother
% Рис.1. - как у нас принято.
\renewcommand{\captionlabeldelim}{.}

% Меняем поля страницы
\usepackage{geometry}
\geometry{left=2cm}
\geometry{right=2cm}
\geometry{top=2cm}
\geometry{bottom=3cm}

\begin{document}

\pagestyle{fancy}


\begin{abstract}
The registration of correlation signals....
\end{abstract}
Небольшие комментарии к коду. Я использовал возможности пакета fancyhdr для того, чтобы вставить упоминание о ревизии документа в колонтитуле - чтобы на каждой странице это было видно. Питонистый скрипт довольно прост, а если вы захотите его оптимизировать - напильник вам в руки.

Как сделать отслеживание версий для Mercurial [добавлено]
Для Mercurial код немного проще, приведу его кусок здесь:
%<--------------Pythonated trick starts HERE!
\usepackage{fancybox,fancyhdr}
\usepackage{python}
\begin{python}
#! /usr/bin/python
import os, string
cmd = 'hg id -n -i'
fpipe = os.popen(cmd)
piperesult = fpipe.read()
fpipe.close()
results = piperesult.split()
out = 'HG Mercurial revision hash of this document is '+results[0]+', revision number is '+results[1]
FileName='paperstatus.tex'
fout=open(FileName,'w')
fout.write(out)
fout.close()

\end{python}
\fancyhead[R]{}
\fancyhead[L]{}
\fancyhead[C]{Page \thepage}
\fancyfoot[R]{}
\fancyfoot[C]{\textit{\textbf{\input{paperstatus}}}}
\fancyfoot[L]{}

%<--------------Pythonated trick ends HERE!

После этого в ваш документ внизу страницы будет вставляться номер его ревизии в Subversion, что будет видно и при печати. Мне это сэкономило много нервов и седых волос.

18 комментариев:

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

    \usepackage{indentfirst}

    ОтветитьУдалить
  2. 1 комментариев:

    2 dpetroff.ru комментирует...
    Спасибо за статью, думаю, пригодится.Пожалуйста. Мне вот уже пригодилась, и не раз :-)

    Единственное, пришлось гуглить насчет пакета, который позволяет делать отступы во всех абзацев, начиная с первого. \usepackage{indentfirst}Очень странно: он должен быть в стандартной поставки, даже в tetex он есть. У вас какой дистрибутив латеха?
    11.05.2009 8:39:00

    ОтветитьУдалить
  3. Очень странно: он должен быть в стандартной поставки, даже в tetex он есть.Товарищ, наверно, имел ввиду то, что про него ещё нужно узнать :-)

    У меня вот какой вопрос: как бы поменять стиль оформления заголовков section в стандартных классах?
    Читал про это у Львовского и в конце получилось вот это:
    renewcommand{\section{\@startsection{section}{1}%
    {0mm}{3.5ex plus 1ex minus .2ex}{15mm}%
    {\normalfont\bfseries\Large\scshape\centering}}
    LaTeX выдаёт ошибку:
    You can't use `\spacefactor' in vertical mode.
    \@->\spacefactor
    \@m

    Даже не знаю, что и думать...

    ОтветитьУдалить
  4. Programmaster вежливо кашлянул, напоминая присутствующим, что он всё ещё здесьЗдрасте :)

    К счастью, эта статья вернула блог в своё русло — а то я уж начал опасаться, что ты со своими примерами из диссертации совсем меня работы лишишь :) Я просто ту статью так до конца и не дочитал — не интересует эта ваша оптика, хоть убей :(

    Хотя у меня завтра экзамен по физике, которую я, кстати, люблю :D

    Ну-с, поехали!

    возможность LaTeX выполнять налету и встраивать в текст результаты работы питонистого скрипта.
    Ну, во-первых, «на лету» пишется раздельно :)
    Во-вторых, как-то не очень читабельно эта фраза выглядит. Не лучше ли написать что-то вроде «возможность LaTeX выполнять Python-скрипт и встраивать результат его работы в документ»? Ну или что-то вроде того…

    ув.тов.jetxee
    А пробел перед ником не нужен?

    скачать файл python.sty и скопировать этот файл
    Тавтология получается. Лучше «скачать файл python.sty и скопировать его».

    внутри документа фрагменты кода на Python … и теперь всё, что эти фрагменты кода будут печатать…
    Аналогично. Может быть, покатит что-то вроде «внутри документа фрагменты кода на Python помещать в окружение \begin{python} ... \end{python} — всё, что они выведут, станет частью конечного документа;».

    для запуска внешнего кода из-под LaTeX
    Почему же код «внешний», когда он в документ встроен? В принципе, по логике больше подходит «внутренний», но так как я такое разделение кода на типы слышу впервые, лучше напиши просто «втроенного кода» :)

    Однако если у вас десктоп с графической оболочкой и обвешан разными рюшками
    «Однако» здесь несколько неуместно. Вот «впрочем» смотрелось бы значительно лучше :)

    запалить всё это вместе.
    Замечание не как редактора, но как читателя: у тебя в семье пожарники есть? :D Ты так любишь всё зажигать да запаливать…
    Или это тебя гентушники на встречах заразили? Ты вроде в отчётах писал, что вы обычно им костёр доверяете — они же что угодно зажгут :D

    Всё, после этого в ваш документ внизу страницы будет вставляться информация о том, что за версия Subversion этого документа
    Опять тавтология. Что-то вроде «всё, после этого в ваш документ внизу страницы будет вставляться номер его ревизии в Subversion» может спасти ситуацию :)

    That's all for today :)

    ОтветитьУдалить
  5. Programmaster уже почти ушёл, но вдруг что-то вспомнил и вернулся
    А вспомнил я вот что: вас не раздражает то, что после </b>, </i> и прочих убираются переносы строк? Причём сколько бы их (переносов) не было — все равно всё убирается и новая строка «прилепляется» к концу предыдущей.

    Вчера поставил эксперимент в своём блоге (да простят меня читатели моего RSS фида). В результате подтвержил свои догадки: можно пользоваться HTML тегом <br>. То есть сразу после закрывающего тега ставишь <br> — и будет тебе счастье :) Как видите, в своём предыдущем комментарии я переносы расставил везде, кроме первой фразы (там где «Здрасте»). Работает ведь :)

    ОтветитьУдалить
  6. СТОП! svn (и др.) поддерживают т.н. keywords в теле документа, вида $Id$

    \begin{abstract}
    Ревизия $Revision$
    ..........

    http://svnbook.red-bean.com/en/1.4/svn.advanced.props.special.keywords.html

    ОтветитьУдалить
  7. 2 Анонимный комментирует...
    У меня вот какой вопрос: как бы поменять стиль оформления заголовков section в стандартных классах?Честно говоря, я с такими вещами не сталкивался, так что увы, помочь не смогу.


    2 Programmaster комментирует...

    Programmaster вежливо кашлянул, напоминая присутствующим, что он всё ещё здесьДа ты заходи, не стесняйся, все свои... :-)

    К счастью, эта статья вернула блог в своё руслоТак ведь не оффтопик, так что всё путём. В комментариях там интересных мыслей подбросили. За что я их, комментаторов, и ценю. Ну кроме спамеров, конечно :-)

    Я просто ту статью так до конца и не дочитал — не интересует эта ваша оптика, хоть убейТак то не оптика, а регистрация изображений. Но не суть.

    не очень читабельно эта фраза выглядит.Поправил - так лучше?

    ув.тов.jetxee
    А пробел перед ником не нужен?
    Нужен. Глазаааааастый :-))


    Тавтология получается. Лучше «скачать файл python.sty и скопировать его».Да, так лучше. Исправлено.

    Может быть, покатит что-то вродеПокатило. :-)

    Почему же код «внешний», когда он в документ встроен?Ммм...так дёргает-то он внешнюю программу? Хотя да, код-то внутри...

    «Однако» здесь несколько неуместно. Вот «впрочем» смотрелось бы значительно лучше :)Так и есть. Пофиксено.

    Замечание не как редактора, но как читателя: у тебя в семье пожарники есть?Неа, это последствия глобального потепления: раньше я мог что-то сморозить, теперь - только отжечь :-)

    Опять тавтология.Да, писал не в ударе, согласен :-)
    Исправил.

    That's all for today :)Let me express my gratitude for your attention and fall down with adoration of your wisdom and greatness. :-)

    2 Programmaster комментирует...
    А вспомнил я вот что: вас не раздражает то, что после /b, /i и прочих убираются переносы строк?Да просто бесит, если честно. Это гугловцы, чтоб их так, опять что-то поломали (на тех.обслуживание вырубают блог уже второй раз за неделю). Надо им телегу накатать, что ли...


    2 Vaulter комментирует...
    СТОП! svn (и др.) поддерживают т.н. keywords в теле документа, вида $Id$Да, мне тут уже прислали вариант с keywords - думаю, надо будет писать ещё один пост (как разберусь). Большое спасибо за идею! И за ссылку тоже.

    ОтветитьУдалить
  8. P.S> Про отсутствие BR в комментариях - оказывается, проблема известна, и давно (уже пару недель). Засабмитил блоггеровцам телегу, авось что придумают.

    ОтветитьУдалить
  9. Насчёт проблемы с заголовками, о которой я спрашивал выше:В очередной раз убеждаюсь, что google может решить все проблемы, а на CTAN уже всё написано :-)
    http://www.tex.ac.uk/tex-archive/macros/latex/contrib/titlesec/
    Вдруг кому-нибудь понадобится :)

    ОтветитьУдалить
  10. А если VСS не поддерживает keywords, как до недавних пор bazaar, например, можно воспользоваться Makefile-ом и \input{}-ом. А то учить Python, хоть и по верхам похоже на «из пушки...» Вы не находите?

    ОтветитьУдалить
  11. Так ведь не оффтопик, так что всё путём.
    И то правда :)

    В комментариях там интересных мыслей подбросили
    Ну это как всегда :)

    Ну кроме спамеров, конечно :-)
    Армагеддон начнётся с появления человека, любящего спаммеров :D

    Так то не оптика, а регистрация изображений. Но не суть.
    Ну тебе виднее. ;)

    Поправил - так лучше?
    Агась :)

    Нужен. Глазаааааастый :-))
    ^_^

    Ммм...так дёргает-то он внешнюю программу? Хотя да, код-то внутри...
    Вобщем-то да, вопрос скользкий. Код внутренний, но интерпретируется он внешней программой. Но это не очень-то и важно — понятно же, что ты имел в виду ;)

    Неа, это последствия глобального потепления: раньше я мог что-то сморозить, теперь - только отжечь :-)
    :D

    >That's all for today :)
    Let me express my gratitude for your attention and fall down with adoration of your wisdom and greatness. :-)

    И кто меня за язык тянул… Пришлось полистать словарик. My pleasure and thanks, короче :)

    Да просто бесит, если честно. Это гугловцы, чтоб их так, опять что-то поломали (на тех.обслуживание вырубают блог уже второй раз за неделю). Надо им телегу накатать, что ли...

    Про отсутствие BR в комментариях - оказывается, проблема известна, и давно (уже пару недель). Засабмитил блоггеровцам телегу, авось что придумают.

    Будем надеяться, они это быстренько починят
    P.S. Кстати, твой коммент в Google Groups позволил мне реабилитироваться (в плане английского) — его я понял без словаря :D

    ОтветитьУдалить
  12. С «my pleasure and thanks» я, наверное, таки лохонулся. Сейчас ещё раз (четвёртый уже :) перечитал свой коммент — ну не звучит оно :(

    ОтветитьУдалить
  13. http://wiki.linuxformat.ru/index.php/LXF87-88:LaTeX -- раздел "LaTeX и контроль версий" и питон не нужен будет. По моему более элегантное решение.

    ОтветитьУдалить
  14. Спасибо за ссылку. Приятно.

    Только, может, лучше не тащить Python, а использовать svn:keywords ($Rev$, $LastChangedDate$, ...)? В исходнике документа будет номер версии.

    ОтветитьУдалить
  15. >У меня вот какой вопрос: как бы поменять стиль
    >оформления заголовков section в стандартных
    >классах?
    >
    >Читал про это у Львовского и в конце получилось
    >вот это:
    >renewcommand{\section{\@startsection{section}{1}%
    >{0mm}{3.5ex plus 1ex minus .2ex}{15mm}%
    >{\normalfont\bfseries\Large\scshape\centering}}
    >LaTeX выдаёт ошибку:
    >You can't use `\spacefactor' in vertical mode.
    >\@->\spacefactor
    >\@m

    LaTeX использует "@" в своих целях. поэтому для корректной обработки содержащие его конструкции необходимо обрамлять командами \makeatletter и \makeatother:

    \makeatletter
    \renewcommand{\section{\@startsection{section}{1}%
    {0mm}{3.5ex plus 1ex minus .2ex}{15mm}%
    {\normalfont\bfseries\Large\scshape\centering}}
    \makeatother

    ОтветитьУдалить
  16. Этот комментарий был удален автором.

    ОтветитьУдалить
  17. а собственно почему для этого не использовать GIT. Кстати Линус Торвальдс недавно в GOOGLE провел конференцию по гиту, а добрые люди ее перевели.
    http://www.youtube.com/watch?v=BtAlN4MaBr8

    ОтветитьУдалить