cvs-checkout-d - CVS の "checkout -d" と module の関係
目的
CVS の checkout コマンドに -d を付けた時の挙動を理解する。
"-d" オプション付きでのチェックアウト
とある CVS リポジトリを、モジュール名とは別のディレクトリにチェックアウトしようとして以下のように実行したところ、エラーで途中終了した。
% cvs co -d tmp foo # => exit 1
"-d tmp" を付けない場合は正常にチェックアウトできるのだが、なぜだろう?
現象が再現するリポジトリを作る
問題のリポジトリを元に、現象が再現する最小の構成を作った。
CVSROOT/modulesの設定
__foo_alias -a foo/foo.c __bar_alias -a foo/bar __baz_alias -a foo/baz foo_alias -a __foo_alias __bar_alias __baz_alias
foo は foo 自身の中にある2つのディレクトリをaliasとして含んでいる。
(このmodules設定が変則的と言われればその通りだが…作ったのが私ではないので、なんとも答えられない)
checkout 時の動作
このモジュールをcheckoutした時に、以下のエラーのエラーが発生した。
% cvs -d ~/spikelet/repos/cvsroot co -d tmp foo U tmp/bar.c cvs checkout: existing repository /home/taiyo/spikelet/repos/cvsroot/foo does not match /home/taiyo/spikelet/repos/cvsroot/foo/bar cvs checkout: ignoring module foo/bar cvs checkout: existing repository /home/taiyo/spikelet/repos/cvsroot/foo does not match /home/taiyo/spikelet/repos/cvsroot/foo/baz cvs checkout: ignoring module foo/baz # => exit 1
なお、RHEL4のCVS(1.11.17)と、最新stable(1.11.23)で試しても現象は同じ。
考察
CVS の info に、以下の記述がある("Node: checkout options")。
`-d DIR' Create a directory called DIR for the working files, instead of using the module name. In general, using this flag is equivalent to using `mkdir DIR; cd DIR' followed by the checkout command without the `-d' flag. There is an important exception, however. It is very convenient when checking out a single item to have the output appear in a directory that doesn't contain empty intermediate directories. In this case _only_, CVS tries to "shorten" pathnames to avoid those empty directories.
超訳すると、こんな感じか:
checkout コマンド の "-d DIR" オプションは、module 名の代わりに DIR にワーキングファイルを置く。 単一のアイテムを、中間ディレクトリ無しで checkout するのに便利。
おそらく、以下のような処理になっているのではないだろうか。
対策
このmoduleについて、"-d" オプション有りでも無しでも正しくチェックアウトできるmodule設定が無いか、試してみる。
総当たり戦を試してみる
CVSのmodulesは、alias / regular / ampersand の3種類がある。
この3種類それぞれに対して、fooモジュール本体の定義と、各subdir(bar,baz)を変化させて、チェックアウト時の動作を観察する。
foo本体\各subdir | regular | alias | ampersand |
---|---|---|---|
regular | ※ / ※ | ※ / ※ | ※ / ※ |
alias | △ / × | ○ / × | △ / △ |
ampersand | △ / △ | △ / △ | △ / △ |
( '/' の前後は、"-d"オプションありと、オプション無し の結果)
なお、表中の記号の意味は下記の通り:
- ※ = CVS Error (there is no repository ...)
- × = CVS Error (existing repository ... does not match ...)
- △ = checkout result differs from expected
- ○ = checkout reseult matches expected
この結果から、望みがありそう(CVSが処理できそう)なのは、以下の△マークの箇所のみ:
*foo本体\各subdir | *regular | *alias | *ampersand |
regular | × | × | × |
alias | × | × | △(1) |
ampersand | △(2) | △(3) | △(4) |
成功する可能性がありそうなものについて、詳細検討
上の表で△がついたものについて、期待するチェックアウト結果と実際の差を整理すると、以下のようだった:
# | foo本体/各subdir | "-d"オプション無し | "-d"オプション有り |
1 | alias / ampersand | foo/bar -> __bar_amper/foo/bar | tmp/bar -> tmp/foo/bar |
2 | ampersand / regular | foo/bar -> foo_amper_regular/__bar_regular | tmp/bar -> tmp/__bar_regular |
3 | ampersand / alias | foo/bar -> foo_amper_alias/foo/bar | tmp/bar -> tmp/foo/bar |
4 | ampersand / ampersand | foo/bar -> foo_amper_amper/__bar_amper/foo/bar | tmp/bar -> tmp/__bar_amper/foo/bar |
表から、"-d" オプション有り/無しどちらの場合も、余計なディレクトリ名が付いてしまうことがわかる。
ここで、CVS modules の ampersand module の定義を見ると(info cvs の Node: Ampersand modules)、
Ampersand modules ----------------- A module definition can refer to other modules by including `&MODULE' in its definition. MNAME [ options ] &MODULE... Then getting the module creates a subdirectory for each such module, in the directory containing the module. For example, if modules contains ampermod &first-dir then a checkout will create an `ampermod' directory which contains a directory called `first-dir', which in turns contains all the directories and files which live there. For example, the command
ampersandモジュールは、必ずディレクトリが付けられることになっている。
すなわち、上記の表で、"foo/bar" に対して2つ以上のディレクトリが付いているものは、それ以上ディレクトリを削除できないので、どうやっても差分が出る。
これに該当しないのは #2(本体:ampersand、各subdir:regular) のみ。
これをヒントに、なんとかならないかを試してみる。
foo本体:ampersand、各subdir:regular な modules 設定
下記の設定をmodulesに書いて試してみた。
bar -d bar foo/bar baz -d baz foo/baz foo -d foo &baz &bar
"-d"オプション無し
% cvs -d /home/taiyo/spikelet/cvs/cvsroot co foo U baz/baz.c U bar/bar.c % find . -name CVS -prune -o -type f -name '[a-z_]*[^~]' -print ./foo/bar/bar.c ./foo/baz/baz.c
"-d"オプション有り
cvs -d /home/taiyo/spikelet/cvs/cvsroot co -d tmp foo U baz/baz.c U bar/bar.c % find . -name CVS -prune -o -type f -name '[a-z_]*[^~]' -print ./tmp/bar/bar.c ./tmp/baz/baz.c
ひとまず、これで希望の設定はできたようだ。
つまり、以下のような設定をmodulesに書き込む:
- 各subdir は、出力先dirを指定して、subdir と同じ名前の regular module として定義する
- fooモジュール本体は、出力先dirを指定して、各subdirを ampersand module として含める
まとめ
長い(時間も、文章も)わりに、意味があまり無く、結果も面白くない投稿になってしまった。
もっと有意義な事に時間を使いたい…