小林儀
匡
![]() |
本節ではパッチ管理ツール quilt*15 を 取り上げ、 その基本操作を中心に説明します。 quilt は Debian に特有な (つまり Debian-specific な) ソフトウェアではなく、 Debian とは全く関係のない場所で開発されています。 しかし、 このツールが Debian パッケージの作成に有用であることを理 解し、 実際に作成に使用してもらえたら嬉しい限りです。
開発者であれば当然のように作成したり読んだり当てたりしたことがあるパッチですが、 一般ユーザには見慣れないものだと 思います。 そこで、 最初にパッチについて説明しておきます。
パッチとは、 2 つのファイルの差分を含むファイルのことです。 次のような 2 つのファイルがあるとしま しょう。
nori1[3:57]% cat file1.txt saba:~/tmp/q
あいうえお か き く け こ さしすせそ た ち つ て と なにぬねの は ひ ふ へ ほ まみむめも や ゆ よ らりるれろ わ を ん nori1[3:58]% cat file2.txt saba:~/tmp/q あいうえお ば び ぶ べ ぼ たちつてと な に ぬ ね の まみむめも や ゆ よ らりるれろ わ を ん |
これらのファイルのどこが違っているかすぐにわかりますか? 一々目で比べる必要はありません。 diffコマンドでこれらの 差分をとることができます。
nori1[3:57]% diff file1.txt file2.txt saba:~/tmp/q
2,3c2 < かきくけこ < さしすせそ --- > ばびぶべぼ 6d4 < はひふへほ |
file1.txtとfile2.txtの内容や行番号を考えれば、 なんとなく意味がわかると思います。 それでかまいません。 もちろ ん、 この出力を手で書けるようにならなくてかまいません。
この形式でもよいのですが、 通常はdiffコマンドに-uオプションをつけ、 次のようなunified diff という形式で出力させ ます。
nori1[3:57]% diff -u file1.txt file2.txt saba:~/tmp/q
--- file1.txt Thu Jan 18 03:57:14 2007 +++ file2.txt Thu Jan 18 03:57:22 2007 @@ -1,9 +1,7 @@ あいうえお -かきくけこ -さしすせそ + ばびぶべぼ たちつてと なにぬねの -はひふへほ まみむめも や ゆ よ らりるれろ |
こちらのほうが、 追加・削除された行がどちらのファイルに所属するのか、 そしてファイルのどのような部分が異なるのかが わかりやすいでしょう。
パッチとは要は、 次のようにしてこういった出力をファイルに収めたものです。
nori1[3:58]% diff -u file1.txt file2.txt > file.diff saba:~/tmp/q
|
ただし、 全く縁のない 2 つのファイルであれば差分はわざわざファイルに収める必要はないでしょう。 わざわざパッチを作成 するのは、 ファイルに変更を加える前後の差分を見たり、 後で紹介するように機械的な処理で変更を加えられるようにしたりす るためです。 そこで、 ここまではfile1.txtとfile2.txtは無縁のファイルとしてきましたが、 ここからはfile1.txtを改 変 し た も の が file2.txtであると考えてください。 つまりfile1.txtが改変前のファイルで、 file2.txtが改変後のファ イル、 パッチ file.diff には file1.txt を file2.txt にするための変更が含まれている、 と考えてくだ さい。
さて、 作成したパッチは、 patchコマンドを用いて、 その中に含む変更を該当ファイルに適用する (当てる) ことができ ます。
nori1[4:00]% patch < file.diff saba:~/tmp/q
patching file file1.txt |
こうしてfile1.txtの内容はfile2.txtの内容と同一になります。
nori1[4:01]% cat file1.txt saba:~/tmp/q
あいうえお ば び ぶ べ ぼ たちつてと な に ぬ ね の まみむめも や ゆ よ らりるれろ わ を ん nori1[4:02]% cmp file1.txt file2.txt saba:~/tmp/q |
また、 -Rオプションを指定して逆向きに当てることもできます。
nori1[4:18]% patch -R < file.diff saba:~/tmp/q
patching file file1.txt nori1[4:19]% cat file1.txt saba:~/tmp/q あいうえお か き く け こ さしすせそ た ち つ て と なにぬねの は ひ ふ へ ほ まみむめも や ゆ よ らりるれろ わ を ん |
file1.txtの内容は元に戻りました。
パッチは必ずしもうまく当たらないことを忘れてはなりません。 次のように、 file1.txtの 2 行目を手元で改変したとし ます。
nori1[5:29]% cat file1.txt saba:~/tmp/q
あいうえお が ぎ ぐ げ ご さしすせそ た ち つ て と なにぬねの は ひ ふ へ ほ まみむめも や ゆ よ らりるれろ わ を ん |
これに先程のパッチを当てようとすると次のようにエラーになります。
nori1[5:30]% patch < file.diff saba:~/tmp/q
patching file file1.txt Hunk #1 FAILED at 1. 1 out of 1 hunk FAILED -- saving rejects to file file1.txt.rej |
これは、 手元で与えた変更とパッチが加えたい変更が競合しているからです。
もちろん、 file1.txtの 2 行目を改変する代わりに、 次のように最終行に 1 行加えたとします。
nori1[5:32]% cat file1.txt saba:~/tmp/q
あいうえお か き く け こ さしすせそ た ち つ て と なにぬねの は ひ ふ へ ほ まみむめも や ゆ よ らりるれろ わ を ん むふふふふ |
この場合、 手元で加えた変更はパッチが含む変更とは被らないので、 パッチはうまく当たりま す*16 。
nori1[5:36]% patch < file.diff saba:~/tmp/q
patching file file1.txt nori1[5:52]% cat file1.txt saba:~/tmp/q あいうえお ば び ぶ べ ぼ たちつてと な に ぬ ね の まみむめも や ゆ よ らりるれろ わ を ん むふふふふ |
これまでは 1 つのファイルの変更を 1 つのパッチに収めてきましたが、 1 つのパッチに複数のファイルの変更を収めることも 可能です。 以下は、 diffに-rオプションを渡して、 内容の一部が異なる 2 つのファイルを含む 2 つのディレクトリの差分を パッチとして出力させた例です。
nori1[5:14]% diff -ur skkdic.orig skkdic > skkdic.diff saba:~/tmp
nori1[5:14]% cat skkdic.diff saba:~/tmp diff -ur skkdic.orig/debian/changelog skkdic/debian/changelog --- skkdic.orig/debian/changelog Fri Dec 15 03:36:49 2006 +++ skkdic/debian/changelog Mon Dec 25 17:39:10 2006 @@ -1,5 +1,7 @@ skkdic (20061130-2~pre1) unstable; urgency=low + * debian/rules: Pass the ‘-k’ option to dh_installchangelogs so that + all of ChangeLog* are installed equally. * debian/skkdic{,-cdb,-extra}.docs: Deleted since their settings are now moved into debian/rules. diff -ur skkdic.orig/debian/rules skkdic/debian/rules --- skkdic.orig/debian/rules Fri Dec 15 03:36:49 2006 +++ skkdic/debian/rules Mon Dec 25 17:39:10 2006 @@ -2,6 +2,7 @@ include /usr/share/cdbs/1/rules/debhelper.mk include /usr/share/cdbs/1/class/makefile.mk +DEB_DH_INSTALLCHANGELOGS_ARGS := -k DEB_INSTALL_CHANGELOGS_ALL := ChangeLog DEB_INSTALL_DOCS_ALL := ChangeLog.* READMEs/committers.txt |
以上で簡単なパッチの説明は終わりです。 こういったパッチは、 修正した部分を確認したり他人と修正内容をやりとりしたり するのに非常に便利で、 開発作業はこれなしではやっていけないと言っても過言ではないでしょう。 実際に使うに当たっては patch(1) や diff(1) を参照することをお勧めします。
今回説明する quilt はパッチ管理ツールです。 これは、 複数のパッチを管理するためのものです。 どのような場合に必要になる のでしょう?
先程パッチとは「修正した部分を確認したり他人と修正内容をやりとりしたりするのに非常に便利」 だと書きまし た。 その言葉に基づけば、 一般にはパッチとは使い捨ての一時ファイルで短寿命です。 管理する必要はありま せん。
しかし、 以下のようなケースを考えてみてください。
A さんが全体の変更を 1 つのパッチとして管理するのは不可能に近いでしょう。 foo の新しいリリースが出たときに、 元の パッチを当てても (うまく当たる部分もあるでしょうが) 間違いなくうまく当たりません。 しかも複数の変更が混ざっているの でそれを解決するのは非常に大変でしょう。
変更を複数の論理的なパッチに分割すれば、 少しは管理が楽になるでしょう。 1 つずつパッチを当て、 うまく当たるも のと当たらないものを区別できます。 当たらないもののうち、 既に開発元で加えられた修正のパッチは削除 し、 残すべきなのに他の変更の影響で部分的にうまく当たらないパッチはうまく当たるよう調整します。 そ れらの作業は面倒かもしれませんが、 1 つのパッチとして管理するのに比べれば楽でしょう。 ただし、 作業 中に、 現在どのパッチが当たっていてどれが当たっていないかを一々覚えておかなければならないのが大変 です。
そこで登場するのがパッチ管理ツールです。 パッチ管理ツールは、 複数のパッチの取り扱いを楽にするためのツールです。 具 体的には、 どのパッチが当たっておりどれが当たっていないかを管理できます。 また、 一度に複数のパッチを当てたり外したり できるので、 全ての (あるいはある一群の) パッチがうまく当たるかどうかを概観するのも楽にできます。 A さんがやっている ような作業にはうってつけのツールです。
さて、 実は Debian パッケージのメンテナ (保守担当者) はこの A さんのような作業をする必要があります。 すなわち、 開発 元のリリースに複数のパッチを独自に当て、 それらを管理する必要があるのです。 というのも、 一般に開発元と Debian とでは リリースサイクルや品質の基準が異なるからです。 管理すべきパッチは、 ソフトウェアの規模が大きくなればなるほ ど増えるでしょう。 そこで Debian パッケージメンテナはパッチ管理ツールを使用することが推奨されてい ます。
ここでは quilt を使用したパッチ管理を紹介します。 Debian でよく使われるパッチ管理ツール には、 dpatch というものもあります。 こちらは Debian パッケージメンテナンスに特化したツー ルですが、 機能的には quilt とそんなに違いはありません。 興味がある方は、 2005 年 7 月勉強 会*17 の 資料を参照してください。
quilt は、 Debian では quilt パッケージに含まれており、 apt-get や aptitude で普通にインストールでき ます。
quilt では一般に、 quilt <コマンド>という書式で様々なコマンドが利用できます。 利用可能なコマンドの一覧は次のようにし て参照できます。
nori1[13:19]% quilt --help whale:~
使い方: quilt [--trace[=verbose]] [--quiltrc=XX] command [-h] ... quilt --version コマンド一覧: add files import previous setup annotate fold mail push snapshot applied fork new refresh top delete graph next remove unapplied diff grep patches rename upgrade edit header pop series 全コマンド共通オプション: --trace コマンドを bash のトレースモード (-x) で実行。 内部デバッグ用。 --quiltrc file ~/.quiltrc (存在しない場合は代わりに /etc/quiltrc) 以外のコン フィギュレーションファイルを指定。 内容の詳細については PDF のド キュメントを参照。 --version バージョン情報を出力して終了。 |
また各コマンドのヘルプメッセージは各コマンドに-hオプションを指定すれば表示できます。 以下の例ではquilt addのヘ ルプメッセージを表示させています。
nori1[13:45]% quilt add -h whale:~
Usage: quilt add [-P patch] {file} ... Add one or more files to the topmost or named patch. Files must be added to the patch before being modified. Files that are modified by patches already applied on top of the specified patch cannot be added. -P patch Patch to add files to. |
実際に quilt を使う前に、 quilt のデータ構造を知っておきましょう。 quilt は、 あるツリーに対する一連のパッチを一列に並べ てスタックとして管理します。
あるソースツリーに、 以下のような 5 つのパッチを順に加えたいとします。
このとき、 これらのパッチはpatches ディレクトリに含まれていなければなりません。 そして、 パッチの整列順序を収めた次のような内容 のseries ファイル*18 が パッチディレクトリに含まれている必要があります。
______________________________________________________________________________________________
r1091-remove-trailing-garbage.diff
r1092-implement-distclean.diff r1094-add-readme.diff fix-ftbfs-on-m68k.diff work-around-an-error-of-libtool.diff
|
つまりまとめると、 上に挙げた 5 つのパッチを順に加えるようなパッチセットのデータは次のようなもの です。
nori1[14:22]% ls patches/* whale:~/svnwc/deb/serf/trunk/serf-0.1.0
patches/fix-ftbfs-on-m68k.diff patches/r1091-remove-trailing-garbage.diff patches/r1092-implement-distclean.diff patches/r1094-add-readme.diff patches/series patches/work-around-an-error-of-libtool.diff nori1[14:22]% cat patches/series whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1091-remove-trailing-garbage.diff r1092-implement-distclean.diff r1094-add-readme.diff fix-ftbfs-on-m68k.diff work-around-an-error-of-libtool.diff |
quilt のパッチデータはこれが全てです。
なおこのデータ構造は、 7.3.4で後述するパッチ作成作業時に quilt が自動的に作成してくれるので、 通常は手でいじる必要は ありません。 次のセクションでは、 このような patches ディレクトリを既にもったツリーでパッチを当てたり外したりしてみま しょう。
さて、 では quilt を使ってみます。 まずはスタック管理のための操作を眺めてみましょう。 スタック管理に必要な操作は、 もち ろん push と pop です。
最初は何もパッチが当たっていないとします。 この状態でquilt pushを実行すると、 1 番目のパッチ、 つまり r1091-remove-trailing-garbage.diff が当たります。 このパッチは Makefile.in に修正を加えるもの です。
nori1[14:30]% quilt push whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch r1091-remove-trailing-garbage.diff patching file Makefile.in Now at patch r1091-remove-trailing-garbage.diff |
きちんと当たったようですね。 quilt pushは、 引数を与えなければ「次のパッチ」 を当てるコマンドです。 これで現在ツ リーは、 r1091-remove-trailing-garbage.diffだけが当たった状態になりました。
もう一度quilt pushを実行します。
nori1[15:08]% quilt push whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch r1092-implement-distclean.diff patching file Makefile.in Now at patch r1092-implement-distclean.diff |
次のパッチr1092-implement-distclean.diffも当たりました。 これを「r1092-implement-distclean.diffが一番上 に来た状態」 と言うことにしましょう。 スタック (stack) とは英語で「積み重ねたもの」 の意味です。 push 操作ではその上に もの (quilt ではパッチ) を次々に載せていくので、 「パッチ○○まで当てられた状態」 は、 言い換えれば「パッチ○○が一番上 に来た状態」 です。
push の逆は pop です。 すなわち現在一番上にあるパッチを外すのはquilt popです。
nori1[15:15]% quilt pop whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Removing patch r1092-implement-distclean.diff Restoring Makefile.in Now at patch r1091-remove-trailing-garbage.diff nori1[15:15]% quilt pop whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Removing patch r1091-remove-trailing-garbage.diff Restoring Makefile.in No patches applied |
quilt pushやquilt popに引数としてパッチ名を与えると、 そのパッチが一番上に来た状態になるように一連のパッチを 当てたり外したりします。 また引数として数値を与えると、 その数だけパッチを当てたり外したりできます。 -aをオプション として指定すると全てのパッチを当てたり外したりできます。
nori1[15:17]% quilt push 3 whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch r1091-remove-trailing-garbage.diff patching file Makefile.in Applying patch r1092-implement-distclean.diff patching file Makefile.in Applying patch r1094-add-readme.diff patching file README Now at patch r1094-add-readme.diff nori1[15:17]% quilt pop r1091-remove-trailing-garbage.diff Removing patch r1094-add-readme.diff Removing README Removing patch r1092-implement-distclean.diff Restoring Makefile.in Now at patch r1091-remove-trailing-garbage.diff nori1[15:18]% quilt push -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Applying patch r1092-implement-distclean.diff patching file Makefile.in Applying patch r1094-add-readme.diff patching file README Applying patch fix-ftbfs-on-m68k.diff patching file Makefile.in Applying patch work-around-an-error-of-libtool.diff patching file Makefile.in Now at patch work-around-an-error-of-libtool.diff nori1[15:18]% quilt pop -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Removing patch work-around-an-error-of-libtool.diff Restoring Makefile.in Removing patch fix-ftbfs-on-m68k.diff Restoring Makefile.in Removing patch r1094-add-readme.diff Removing README Removing patch r1092-implement-distclean.diff Restoring Makefile.in Removing patch r1091-remove-trailing-garbage.diff Restoring Makefile.in No patches applied |
現在一番上にあるパッチはquilt topで確認できます。 現在一番上にあるパッチの次のパッチと前のパッチはそれぞれ、 quilt nextとquilt previousで確認できます。 現在当てられているパッチと当てられていないパッチはそれぞれ、 quilt appliedとquilt unappliedで確認できます。 そして、 全てのパッチ、 つまり series ファイルの内容はquilt seriesで確 認できます。
nori1[15:31]% quilt top whale:~/svnwc/deb/serf/trunk/serf-0.1.0
No patches applied nori1[15:31]% quilt next whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1091-remove-trailing-garbage.diff nori1[15:31]% quilt previous whale:~/svnwc/deb/serf/trunk/serf-0.1.0 No patches applied nori1[15:31]% quilt applied whale:~/svnwc/deb/serf/trunk/serf-0.1.0 No patches applied nori1[15:31]% quilt unapplied whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1091-remove-trailing-garbage.diff r1092-implement-distclean.diff r1094-add-readme.diff fix-ftbfs-on-m68k.diff work-around-an-error-of-libtool.diff nori1[15:32]% quilt push 2 whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Applying patch r1091-remove-trailing-garbage.diff patching file Makefile.in Applying patch r1092-implement-distclean.diff patching file Makefile.in Now at patch r1092-implement-distclean.diff nori1[15:32]% quilt top whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1092-implement-distclean.diff nori1[15:32]% quilt next whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1094-add-readme.diff nori1[15:32]% quilt previous whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1091-remove-trailing-garbage.diff nori1[15:32]% quilt applied whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1091-remove-trailing-garbage.diff r1092-implement-distclean.diff nori1[15:33]% quilt unapplied whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1094-add-readme.diff fix-ftbfs-on-m68k.diff work-around-an-error-of-libtool.diff nori1[15:33]% quilt series whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1091-remove-trailing-garbage.diff r1092-implement-distclean.diff r1094-add-readme.diff fix-ftbfs-on-m68k.diff work-around-an-error-of-libtool.diff nori1[15:33]% quilt pop -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Removing patch r1092-implement-distclean.diff Restoring Makefile.in Removing patch r1091-remove-trailing-garbage.diff Restoring Makefile.in No patches applied |
ある特定のファイルを変更するパッチの一覧はquilt filesで参照可能です。 逆に、 ある特定のパッチが変更するファイル の一覧はquilt patchesで参照可能です。
nori1[15:35]% quilt files r1091-remove-trailing-garbage.diff
Patch r1091-remove-trailing-garbage.diff is not applied nori1[15:35]% quilt push r1091-remove-trailing-garbage.diff Applying patch r1091-remove-trailing-garbage.diff patching file Makefile.in Now at patch r1091-remove-trailing-garbage.diff nori1[15:35]% quilt files whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Makefile.in nori1[15:36]% quilt files r1091-remove-trailing-garbage.diff Makefile.in nori1[15:36]% quilt pop -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Removing patch r1091-remove-trailing-garbage.diff Restoring Makefile.in No patches applied nori1[15:36]% quilt patches Makefile.in r1091-remove-trailing-garbage.diff r1092-implement-distclean.diff fix-ftbfs-on-m68k.diff work-around-an-error-of-libtool.diff |
これでパッチスタックの操作の説明は終わりです。 パッチを含んだ patches ディレクトリが存在していれば、 その中 のパッチを自由自在に当てたり外したり、 現在当たっているパッチを調べたりできるようになりました。 し かしこれだけでは何の役にも立ちません。 次のセクションではパッチを新たに追加する方法について説明し ます。
いよいよ patches ディレクトリに新たなパッチを追加します。 quilt ではquilt newで新たなパッチに名前をつけて作成を開 始し、 適当な変更を加えた後、 quilt refreshでパッチとして保存します。
新たなパッチを追加する場合、 まずはパッチをスタックのどこに入れるか決めま す*19 。 今 回は (特に意味はありませんが) 1 つ目のパッチであるr1091-remove-trailing-garbage.diffの後に入れましょう。 パッ チの名前はlove-debian.diffとし、 その内容は、 次のような love-debian ターゲットをMakefile.inに加えるものにしま しょう。
______________________________________________________________________________________________
love-debian:
echo "I love debian!!"
|
では作成を開始します。
nori1[17:29]% quilt push r1091-remove-trailing-garbage.diff
Applying patch r1091-remove-trailing-garbage.diff patching file Makefile.in Now at patch r1091-remove-trailing-garbage.diff nori1[17:29]% quilt new love-debian.diff Patch love-debian.diff is now on top |
早速Makefile.inを編集したいところですが、 少し待ってください。 実は quilt では、 パッチに含めるファイルは予め quilt addで追加しておかなければなりません。
nori1[17:29]% quilt add Makefile.in whale:~/svnwc/deb/serf/trunk/serf-0.1.0
File Makefile.in added to patch love-debian.diff |
その上でファイルの編集をし、 その内容をquilt diffで確認します。
nori1[17:35]% vim Makefile.in whale:~/svnwc/deb/serf/trunk/serf-0.1.0
[snip] nori1[17:38]% quilt diff whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Index: serf-0.1.0/Makefile.in =================================================================== --- serf-0.1.0.orig/Makefile.in 2007-01-18 17:35:11.000000000 +0900 +++ serf-0.1.0/Makefile.in 2007-01-18 17:38:38.000000000 +0900 @@ -99,6 +99,9 @@ $(INSTALL) -m 644 $$i $(DESTDIR)$(includedir); \ done +love-debian: + echo "I love debian!!" + clean: rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) |
最後にquilt refreshで保存します。
nori1[17:39]% quilt refresh whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Refreshed patch love-debian.diff |
さて、 実はlove-debian.diffは 1 番目のパッチの後に挿入しました。 ということは、 残りのパッチがうまく当たるか確認 しておかなければなりません。
nori1[17:40]% quilt push -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch r1092-implement-distclean.diff patching file Makefile.in Hunk \#1 succeeded at 104 (offset 3 lines). Applying patch r1094-add-readme.diff patching file README Applying patch fix-ftbfs-on-m68k.diff patching file Makefile.in Applying patch work-around-an-error-of-libtool.diff patching file Makefile.in Now at patch work-around-an-error-of-libtool.diff |
新たな行を挿入したので「Hunk #1 succeeded at 104 (offset 3 lines).」 というメッセージが出ましたが、 問題なく 当たりました。
quilt series を実行すると、 きちんと love-debian.diff が適切な位置に挿入されていることがわかり ます。
nori1[17:41]% quilt series whale:~/svnwc/deb/serf/trunk/serf-0.1.0
r1091-remove-trailing-garbage.diff love-debian.diff r1092-implement-distclean.diff r1094-add-readme.diff fix-ftbfs-on-m68k.diff work-around-an-error-of-libtool.diff nori1[17:41]% quilt pop -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Removing patch work-around-an-error-of-libtool.diff Restoring Makefile.in Removing patch fix-ftbfs-on-m68k.diff Restoring Makefile.in Removing patch r1094-add-readme.diff Removing README Removing patch r1092-implement-distclean.diff Restoring Makefile.in Removing patch love-debian.diff Restoring Makefile.in Removing patch r1091-remove-trailing-garbage.diff Restoring Makefile.in No patches applied |
さて、 パッチを作成した後になって気付いたのですが、 love-debian ターゲットが表示する文字列の中の「debian」 は 「Debian」 と大文字にした方がよさそうです。 このようなときはパッチを改変しましょう。 quilt pushないしquilt popで 目的のパッチ (love-debian.diff) を一番上に持ってきて、 エディタでMakefile.inに変更を施した上でquilt refresh で保存すれば OK です。 Makefile.inは既にパッチlove-debian.diffの変更対象に含まれているので、 エディタでの編集 前にquilt addで追加する必要はありません。
nori1[17:54]% quilt push love-debian.diff
Applying patch r1091-remove-trailing-garbage.diff patching file Makefile.in Applying patch love-debian.diff patching file Makefile.in Now at patch love-debian.diff nori1[17:59]% vim Makefile.in whale:~/svnwc/deb/serf/trunk/serf-0.1.0 [snip] nori1[18:01]% quilt diff whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Index: serf-0.1.0/Makefile.in =================================================================== --- serf-0.1.0.orig/Makefile.in 2007-01-18 17:38:38.000000000 +0900 +++ serf-0.1.0/Makefile.in 2007-01-18 18:01:35.000000000 +0900 @@ -99,6 +99,9 @@ $(INSTALL) -m 644 $$i $(DESTDIR)$(includedir); \ done +love-debian: + echo "I love Debian!!" + clean: rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) nori1[18:01]% quilt refresh whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Refreshed patch love-debian.diff |
さて、 このパッチを眺めているうちにまた気が変わって、 design-guide.txtという別のファイルにも変更を加え、 こ のパッチに含めようと思い立ちました。 design-guide.txt は今のところ love-debian.diff の変更対象 外なので、 今度は、 編集する前に quilt add で変更対象に追加しておかなければなりません。 quilt add design-guide.txtを実行した上でエディタでdesign-guide.txtを開いてもよいのですが、 面倒なのでここではquilt edit コマンドを実行しましょう。 このコマンドは、 「引数のファイルを quilt add で追加した上で、 環境変数 EDITOR で指定されたエディタでそのファイルを開く」 という、 2 つの操作をまとめて実行するためのもの です。
nori1[18:19]% quilt edit design-guide.txt
[snip] nori1[18:21]% quilt diff whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Index: serf-0.1.0/Makefile.in =================================================================== --- serf-0.1.0.orig/Makefile.in 2007-01-18 17:55:20.000000000 +0900 +++ serf-0.1.0/Makefile.in 2007-01-18 18:01:35.000000000 +0900 @@ -99,6 +99,9 @@ $(INSTALL) -m 644 $$i $(DESTDIR)$(includedir); \ done +love-debian: + echo "I love Debian!!" + clean: rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) Index: serf-0.1.0/design-guide.txt =================================================================== --- serf-0.1.0.orig/design-guide.txt 2007-01-18 18:19:30.000000000 +0900 +++ serf-0.1.0/design-guide.txt 2007-01-18 18:20:40.000000000 +0900 @@ -9,6 +9,7 @@ 4. Bucket Read Functions 5. Versioning 6. Bucket lifetimes + 7. Love Debian ----------------------------------------------------------------------------- @@ -150,3 +151,10 @@ ----------------------------------------------------------------------------- + +7. LOVE DEBIAN + +Hey, please love Debian. + + +----------------------------------------------------------------------------- nori1[18:22]% quilt refresh whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Refreshed patch love-debian.diff |
これで新たなパッチlove-debian.diffの内容は完成です。 しかしこれだけだと後で何をしたいパッチだかわからなくなり そうです。 最後に、 パッチの説明を加えておきましょう。 quilt では、 パッチの内容を説明するヘッダを操作す るコマンドは quilt header です。 -e オプションを指定してコマンドを実行すると、 環境変数 EDITOR の エディタでパッチのヘッダを編集できます。 また、 何もオプションを与えずに実行するとヘッダを表示でき ます。
nori1[18:37]% quilt header whale:~/svnwc/deb/serf/trunk/serf-0.1.0
nori1[18:37]% quilt header -e whale:~/svnwc/deb/serf/trunk/serf-0.1.0 [snip] nori1[18:41]% quilt header whale:~/svnwc/deb/serf/trunk/serf-0.1.0 A patch to show my love for Debian. |
本セクションでは、 新たにパッチを作成する手順を学びました。 これで自由にパッチを追加・編集できます。 次のセクション では、 開発元が加えた変更への対応方法を学びます。
パッチをいじれるようになったところで、 開発元が新しいリリースなどで加えた変更に対応してみましょう。 この作業では、 quilt pushの-fオプションが役立ちます。
開発元が加えた変更をマージする前に、 まずやっておかなければならないことがあります。 それは、 ツリーにパッチが適用さ れていない状態にすることです。 既に説明したように、 適用されているパッチを全て外すにはquilt pop -aを実行し ます。
nori1[20:00]% quilt pop -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Removing patch love-debian.diff Restoring Makefile.in Restoring design-guide.txt Removing patch r1091-remove-trailing-garbage.diff Restoring Makefile.in No patches applied |
その上で、 ツリーのファイルを、 開発元が新しくリリースしたものに差し替えます (つまり開発元が加えた変更をマージしま す)。 ここでは以下のような変更が入ったとします。
さあ、 新しいツリーにパッチを当てようとするとどうなるでしょうか。 とりあえずquilt push -aで一度に全て当てようと してみましょう。
nori1[20:32]% quilt push -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch r1091-remove-trailing-garbage.diff patching file Makefile.in Hunk #1 succeeded at 103 with fuzz 2 (offset 3 lines). Applying patch love-debian.diff patching file Makefile.in Hunk #1 FAILED at 99. 1 out of 1 hunk FAILED -- rejects in file Makefile.in patching file design-guide.txt Patch love-debian.diff does not apply (enforce with -f) nori1[20:32]% quilt top whale:~/svnwc/deb/serf/trunk/serf-0.1.0 r1091-remove-trailing-garbage.diff |
love-debian.diffを当てるのに失敗して、 そこでパッチの適用が止まってしまいました。 そこで、 -fオプションをquilt pushにつけて、 love-debian.diffを強制的に適用してみます。
nori1[20:33]% quilt push -f whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch love-debian.diff patching file Makefile.in Hunk #1 FAILED at 99. 1 out of 1 hunk FAILED -- saving rejects to file Makefile.in.rej patching file design-guide.txt Applied patch love-debian.diff (forced; needs refresh) |
Makefile.inがどうなったか眺めてみると、 先程 love-debian ターゲットを加えた箇所に、 次のように love ターゲットと clean-love ターゲットが追加されています。
nori1[20:37]% cat Makefile.in whale:~/svnwc/deb/serf/trunk/serf-0.1.0
[snip] $(INSTALL) -m 644 $$i $(DESTDIR)$(includedir); \ done love: echo "Making love..." clean-love: echo "Clearing my old love..." clean: rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) [snip] |
quilt push -fからのメッセージにあるように、 パッチ適用の拒否の理由はMakefile.in.rejに記されています。 念のた め覗いてみましょう。
***************
*** 99,104 **** $(INSTALL) -m 644 $$i $(DESTDIR)$(includedir); \ done clean: rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) --- 99,107 ---- $(INSTALL) -m 644 $$i $(DESTDIR)$(includedir); \ done + love-debian: + echo "I love Debian!!" + clean: rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) |
これはcontext diff と呼ばれる形式ですが、 意味が掴めればかまいません。 上で説明したように、 love-debian ターゲット を加えるための、 clean ターゲットの前の 3 行がうまく当たらなかったことがわかるでしょう。
強制的にパッチを適用した結果がどうなったかわかったところで、 削除されてしまった大切な love-debian ターゲットを Makefile.inに再度追加した上で、 quilt push -fからのメッセージにあるようにパッチを更新 (refresh) しま しょう。
nori1[20:45]% vim Makefile.in whale:~/svnwc/deb/serf/trunk/serf-0.1.0
[snip] nori1[20:54]% quilt diff whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Index: serf-0.1.0/Makefile.in =================================================================== --- serf-0.1.0.orig/Makefile.in 2007-01-18 20:32:13.000000000 +0900 +++ serf-0.1.0/Makefile.in 2007-01-18 20:52:22.000000000 +0900 @@ -102,6 +102,10 @@ echo "Making love..." clean-love: echo "Clearing my old love..." + +love-debian: + echo "I love Debian!!" + clean: rm -f $(TARGET_LIB) $(OBJECTS) $(OBJECTS:.lo=.o) $(PROGRAMS) $(TEST_OBJECTS) $(TEST_OBJECTS:.lo=.o) Index: serf-0.1.0/design-guide.txt =================================================================== --- serf-0.1.0.orig/design-guide.txt 2007-01-18 20:31:56.000000000 +0900 +++ serf-0.1.0/design-guide.txt 2007-01-18 20:36:10.000000000 +0900 @@ -9,6 +9,7 @@ 4. Bucket Read Functions 5. Versioning 6. Bucket lifetimes + 7. Love Debian ----------------------------------------------------------------------------- @@ -150,3 +151,10 @@ ----------------------------------------------------------------------------- + +7. LOVE DEBIAN + +Hey, please love Debian. + + +----------------------------------------------------------------------------- nori1[20:54]% quilt refresh whale:~/svnwc/deb/serf/trunk/serf-0.1.0 Refreshed patch love-debian.diff |
さあ、 これでlove-debian.diffの問題は解決しました。 再びquilt push -aで残りのパッチを全て当てようとしてみま しょう。
nori1[20:55]% quilt push -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch r1092-implement-distclean.diff patching file Makefile.in Hunk #1 succeeded at 108 (offset 7 lines). Applying patch r1094-add-readme.diff The next patch would create the file README, which already exists! Applying it anyway. patching file README Patch attempted to create file README, which already exists. Hunk #1 FAILED at 1. 1 out of 1 hunk FAILED -- rejects in file README Patch r1094-add-readme.diff can be reverse-applied |
今度はr1094-add-readme.diffを当てるのに失敗して、 そこでパッチの適用が止まってしまいました。 メッセージによれ ば、 このパッチは逆に当てることができます。 それはすなわち、 このパッチが既に当たった状態であることを意味します。 開発 元でREADMEを追加してくれたので、 READMEを追加するためのr1094-add-readme.diffは不要になったのでした。 そこで、 このパッチは削除することにします。
nori1[21:05]% quilt delete r1094-add-readme.diff
Removed patch r1094-add-readme.diff |
これでr1094-add-readme.diffの問題も解決です。 再びquilt push -aで残りのパッチを全て当てようとしてみま しょう。
nori1[21:05]% quilt push -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch fix-ftbfs-on-m68k.diff patching file Makefile.in Applying patch work-around-an-error-of-libtool.diff patching file Makefile.in Now at patch work-around-an-error-of-libtool.diff |
全てうまく当たりました。 これで一連のパッチはうまく当たるようになりました。
nori1[21:06]% quilt pop -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Removing patch work-around-an-error-of-libtool.diff Restoring Makefile.in Removing patch fix-ftbfs-on-m68k.diff Restoring Makefile.in Removing patch r1092-implement-distclean.diff Restoring Makefile.in Removing patch love-debian.diff Restoring Makefile.in Restoring design-guide.txt Removing patch r1091-remove-trailing-garbage.diff Restoring Makefile.in No patches applied |
quilt のquilt graphコマンドと Graphviz を使うと、 適用されたパッチの依存関係を可視化できます。
最初に、 全てのパッチを当てておきます。
nori1[22:18]% quilt push -a whale:~/svnwc/deb/serf/trunk/serf-0.1.0
Applying patch r1091-remove-trailing-garbage.diff patching file Makefile.in Hunk #1 succeeded at 103 with fuzz 2 (offset 3 lines). Applying patch love-debian.diff patching file Makefile.in patching file design-guide.txt Applying patch r1092-implement-distclean.diff patching file Makefile.in Hunk #1 succeeded at 108 (offset 7 lines). Applying patch fix-ftbfs-on-m68k.diff patching file Makefile.in Applying patch work-around-an-error-of-libtool.diff patching file Makefile.in Now at patch work-around-an-error-of-libtool.diff |
この状態で何も与えずにquilt graphを実行すると、 Graphviz 用のソースファイルが出力されます。 これは、 同じファイ ルを変更する複数のパッチの間に依存関係がある、 として計算した結果です。
nori1[22:18]% quilt graph whale:~/svnwc/deb/serf/trunk/serf-0.1.0
digraph dependencies { n0 [label="r1091-remove-trailing-garbage.diff"]; n1 [label="love-debian.diff"]; n2 [label="r1092-implement-distclean.diff"]; n3 [label="fix-ftbfs-on-m68k.diff"]; n4 [style=bold,label="work-around-an-error-of-libtool.diff"]; n0 -> n1 [len="1.39"]; n1 -> n2 [len="1.39"]; n2 -> n3 [len="1.39"]; n3 -> n4 [len="1.39"]; } |
このソースを例えばgraph.dotというファイルに保存すると、 Graphviz を使って (例えばdot -Tpng graph.dot -o graph.pngなどと実行して) 様々な形式のファイルが生成できます。 しかし、 ps を出力するのであれば次のように直接出力す るのが楽でしょう。
nori1[22:35]% quilt graph -T ps > patchdep-1.eps
|
なお、 依存関係の指定はありませんが、 内部的に (/usr/share/quilt/graph で) Graphviz の dot コマン ドを呼び出しているので、 実行には graphviz パッケージがインストールされている必要があります (Bug#407469*20 )。
生成された図は図 1のようになります。
他方で、 同じファイルを変更するだけでなくその変更領域が被っている場合に依存関係がある、 として計算すると次のように なります。 変更領域の被りが 1 行の場合 (図 2) と 2 行 (図 3) の場合です。
nori1[22:44]% quilt graph --lines=1 -T ps > patchdep-2.eps
nori1[22:44]% quilt graph --lines=2 -T ps > patchdep-3.eps |
quilt では以下のような環境変数を指定できます。 ここでは省略していますが、 他にも diff 関連の環境変数がいくつかあり ます。
Debian パッケージ作成時のパッチの管理に quilt を使用するときは、 以下を参考にしてください。
第 24 回東京エリア Debian 勉強会 2007 年 1 月____________________________________________________