実は 0.10.9 現在の cygport では想定するソースはアーカイブである必要があるという制限がある。具体的に言うと、hoge.c みたいな単体のソーステキストからパッケージにするには少し HACK が必要となる。
cygport のサブコマンド prep は内部の unpack() という関数で指定されたファイルの拡張子を基に解凍するコマンドを決定している。
# unpacks archives unpack() { local unpack_cmd; local unpack_file_path; local unpack_file_name; local unpack_out; for unpack_file_path do unpack_file_name=${unpack_file_path##*/}; if [ ! -f ${unpack_file_path} ] then error "Cannot find source package ${unpack_file_name}"; fi # determine correct source decompression command case ${unpack_file_path} in *.asc|*.md5|*.sig|*.sign) continue ;; *.tar.bz2|*.tbz2|*.tar.bz|*.tbz) unpack_cmd="tar jxf" ;; *.tar.gz|*.tgz|*.tar.Z) unpack_cmd="tar zxf" ;; *.tar.lzma|*.tar.xz) check_prog_req xz unpack_cmd="tar --xz -xf" ;; *.tar.lz) check_prog_req lzip unpack_cmd="tar -I lzip -xf" ;; *.tar.lzo) check_prog_req lzop unpack_cmd="tar --lzop -xf" ;; *.tar) unpack_cmd="tar xf" ;; *.bz2) unpack_cmd="bunzip2 -c"; unpack_out="${unpack_file_name%.bz2}"; ;; *.cpio.gz) if check_prog bsdtar then unpack_cmd="bsdtar zxf"; else unpack_cmd="__cpio_gz_extract"; fi ;; *.gz) unpack_cmd="gunzip -c"; unpack_out="${unpack_file_name%.gz}"; ;; *.gem) unpack_cmd="__gem_extract"; ;; *.rar) check_prog_req unrar; unpack_cmd="unrar x -inul"; ;; *.src.rpm) unpack_cmd="__srpm_extract"; ;; *.shar) check_prog_req unshar; unpack_cmd="unshar"; ;; *.xar) check_prog_req xar; unpack_cmd="xar -xf"; ;; *.zip|*.ZIP) check_prog_req unzip; unpack_cmd="unzip -oq"; ;; *.7z) if check_prog 7zr then unpack_cmd="7zr x"; elif check_prog 7za then unpack_cmd="7za x"; else error "p7zip is required to unpack this source package"; fi ;; *) unpack_cmd="cp -t ${SRC_DIR}" ;; esac __step "Unpacking source ${unpack_file_name}"; if defined unpack_out then if ! ${unpack_cmd} ${unpack_file_path} > ${unpack_out} then error "${unpack_cmd} ${unpack_file_name} failed"; fi else if ! ${unpack_cmd} ${unpack_file_path} then error "${unpack_cmd} ${unpack_file_name} failed"; fi fi done }
非アーカイブの場合は case 文の最後の条件にマッチすることになるため、cp でコピーをする処理に入るのだが、SRC_DIR はこのファイルを処理する前に別のアーカイブがアーカイブと同じ名前のルートディレクトリを含んでいて、それが既に展開されていることを仮定しているため、そのままではコピー先のディレクトリがないと言われてエラーになってしまう。
ちなみにアーカイブであっても、そのアーカイブがアーカイブ名と同じルートディレクトリを含まない場合は unpack() の後の cd で移動先のディレクトリがないと言われて、同様にエラーとなってしまう。
ここでコピー先となる SRC_DIR の初期値はアーカイブの名前から拡張子を覗いたものであるが、アーカイブの名前とアーカイブ内のルートディレクトリの名前が異なる場合はこの変数を .cygport ファイル内で再定義する必要がある。
アーカイブ内にルートディレクトリがある場合は SRC_DIR の再定義で対処できるが、ルートディレクトリがない場合やそもそもソーステキストのみしか配布されていない場合はルートディレクトリを用意する必要がある。
unpack() を見る限り外部から hook するのは難しいと思ったが、unpack_cmd を function にすることで対処できることに気づいた。
unzip() { /usr/bin/unzip $* -d ${SRC_DIR} }
cp() { mkdir -p ${SRC_DIR} /usr/bin/cp $* }
上記のようなコマンド名と同じ function を定義することで行儀の良くないアーカイブからでもパッケージにすることができる。*1
まとめ
if (ソースがアーカイブ) { if (アーカイブがルートディレクトリを含む) { そのままで良い } else { ダミーのルートディレクトリをつくってそこにアーカイブを展開させる } } else { // ソーステキストのみ ダミーのルートディレクトリをつくってそこにコピーする }
【追記】tar を再定義する場合は prep の場合のみ動作するようにする必要がある。
tar() { case ${argv[${arg_n}]} in prep|unpack) mkdir -p ${P} cd ${P} ;; esac /usr/bin/tar $* }