06 May 2015

Language Select:

はじめに

LaTeXdiffというツールがあります。このツールを使うことで2つのLaTeXソースを比較してその差分を見やすく表示することが出来ます。

論文などをLaTeXで書く際にはGitなどでバージョン管理することがあるかと思います。その時の差分を取って表示することが出来たら便利だと思うので、処理するプログラムを書きました。

やりたいこと

やりたいことは以下の通り

  • GitのコミットIDを2つ指定するとその2つのコミットの差分をLaTeXdiffで調べて出力
  • 単一のLaTeXソースじゃなくて分割したファイルをincludeする場合にも対応

なお、今回は英語の場合しか試してません。

プログラムの概要

必要環境

当然のことながら、TeX環境およびlatexdiffは必要です。latexdiffはMacTeXでインストールした場合には既にインストールされているはずです。

プログラムはPythonで書きましたので、Python環境も必要です。

もともとのTeXソース

まず今回使ったメインのTeXファイル。1.tex2.texなどをincludeしています。

\documentclass[a4paper,12pt,fleqn]{jsarticle}

\begin{document}

\include{0}
\include{1}
\include{2}
\include{3}
\include{4}

\end{document}

今回は1.tex2.tex3.tex4.texの4つのファイルについて差分を取ることにします。

Gitリポジトリからファイルを取り出す

Gitリポジトリから任意のコミット時におけるファイルを開くには

git show a8ebb89:1.tex

のようにします。a8ebb89はコミットIDです。 結果は標準出力に出力されますのでリダイレクトするなりパイプに渡して使うことが出来ます。

実行するPythonプログラム

 1 #!/usr/bin/env python
 2 #coding: utf-8
 3 import sys
 4 import shlex
 5 import subprocess
 6 FileList=['1.tex', '2.tex', '3.tex', '4.tex' ]
 7 
 8 def write_source(input_file, output_file, commit_id):
 9    print('{0} -> {1} [{2}]'.format(input_file, output_file, commit_id))
10    # Show source from Git
11    cmd=shlex.split('git show {0}:{1}'.format(commit_id, input_file))
12    with open(output_file, 'w') as f:
13       proc=subprocess.Popen(cmd, stdout=f, stderr=subprocess.PIPE)
14    stdout, stderr=proc.communicate()
15    # errchk
16    if stderr:
17       print("standard error of subprocess:")
18       print(stderr)
19       sys.exit()
20 
21 
22 def generate_diff(input_file, old, new):
23    # define names
24    old_file='{0}_{1}'.format(old, input_file)
25    new_file='{0}_{1}'.format(new, input_file)
26    output_file='diff_{0}'.format(input_file)
27    # latexdiff
28    cmd=shlex.split('latexdiff {0} {1}'.format(old_file, new_file))
29    with open(output_file, 'w') as f:
30       proc=subprocess.Popen(cmd, stdout=f, stderr=subprocess.PIPE)
31    stdout, stderr=proc.communicate()
32    # errchk
33    if stderr:
34       print("standard error of subprocess:")
35       print(stderr)
36 
37 
38 def clean(old, new):
39    import glob
40    import os
41    print('Removing intermediate files...')
42    for commit_id in [old, new]:
43       files=glob.glob('{0}_*'.format(commit_id))
44       for filename in files:
45          os.unlink(filename)
46 
47 
48 def main(old, new):
49    print('commit id(old): {0}'.format(old))
50    print('commit id(new): {0}'.format(new))
51    for input_file in FileList:
52       for commit_id in [old, new]:
53          output_file='{0}_{1}'.format(commit_id, input_file)
54          write_source(input_file, output_file, commit_id)
55       generate_diff(input_file, old, new)
56 
57 
58 if __name__ == '__main__':
59    # reading arguments
60    argvs=sys.argv
61    argc=len(argvs)
62    if argc != 3:
63       print('This program takes 2 arguments.')
64       print('Usage: python {0} commit id(old) commit id(new)'.format(argvs[0]))
65       sys.exit()
66    main(argvs[1], argvs[2])
67    #clean(argvs[1], argvs[2])

上のプログラムを適当な名前をつけて保存してください。以下ではlatexdiff.pyとして保存したとして話を進めます。

使い方

6行目のFileListに差分を取りたいLaTeXのソースファイルを記入します。

あとは

python latexdiff.py CommitID(old) CommitID(new)

を実行してください。

中間ファイルを削除するためにclean関数も定義してありますが、上のプログラムではコメントアウトしてあります。必要であれば使ってください。

結果を表示するためのTeXソース

上のプログラムを実行すると、diff_1.texのようなファイルが出力されます。 あとは、これらをインクルードするTeXファイルを作ってください。先ほどのメインファイルを少し修正すればいいでしょう。

\documentclass[a4paper,12pt,fleqn]{jsarticle}

\begin{document}

\include{0}
\include{diff_1}
\include{diff_2}
\include{diff_3}
\include{diff_4}

\end{document}

あとはこちらをコンパイルすれば、2つのコミット間の差が見やすく表示されるはずです。

最後のコンパイルがうまくいかない場合

うまくコンパイルできない場合は以下をTeXソースのプリアンブルに記述するとうまくいくと思います。

\RequirePackage[normalem]{ulem}
\RequirePackage{color}\definecolor{RED}{rgb}{1,0,0}\definecolor{BLUE}{rgb}{0,0,1}
\providecommand{\DIFadd}[1]{{\protect\color{blue}\uwave{#1}}}
\providecommand{\DIFdel}[1]{{\protect\color{red}\sout{#1}}}\providecommand{\DIFaddbegin}{}
\providecommand{\DIFaddend}{}
\providecommand{\DIFdelbegin}{}
\providecommand{\DIFdelend}{}
\providecommand{\DIFaddFL}[1]{\DIFadd{#1}}
\providecommand{\DIFdelFL}[1]{\DIFdel{#1}}
\providecommand{\DIFaddbeginFL}{}
\providecommand{\DIFaddendFL}{}
\providecommand{\DIFdelbeginFL}{}
\providecommand{\DIFdelendFL}{}

おわりに

以上です。すでに似たようなことをされてる方もおられるますし、やってることは大したことではありませんが、LaTeXソースを分割してGitでバージョン管理してる人にはそこそこ便利だと思います。

参考



blog comments powered by Disqus

analytics _by_ google