ビルドは仮想マシンで。
最近なにかと喧しい仮想化。遅ればせながら、僕も最近いろいろ試してみている。VMware を使って Windows Vista の上に Fedora を入れてみたりすると、なんだか非常に面白い。ブートローダや OS インストーラといった普段ならモニタを占有する者達がウィンドウの中にちんまりと収まっている様はいとあはれなり。
ところが、実用性となるとどうか。大して使い込んだわけでもないのにこんなことを言うと怒られそうだが、正直、実用は無理だ。なんていうか、ウザい。動きがもっさりとかはあんまり感じない*1が、マウスポインタの動き方とかが微妙に怪しい。管理コンソールとかが鬱陶しい。ちょっと我慢すればすぐに慣れるのかもしれないが、我慢するのは嫌いだ。
やっぱりアレだね。仮想化ってのは、OS インストールマニア*2のオモチャだね。動作検証とかで矢鱈に沢山のマシンを並べなきゃいけない、とかでもない限り、実際に使うところはないんじゃないかな?
……なんてほざいていたのは、昨日までの僕だ。仮想化はメチャクチャ便利な実用技術で、サーバ管理には必須の機能じゃないですか。
事の発端は、id:KENZ さんの一言:
これだ。これに尽きる。○○-devel とかが澱のように積もることもなく、そいつらが連れてくる得体の知れない依存パッケージに怯えることもなく、動作検証だって誰に気兼ねすることもない。GUI など元から無いので、操作感はいつもの端末画面と何ら変わらない。
落としてきた SRPM のビルドとか、Xen の上でやったらいいんじゃないですか?
パッケージのビルドなどという下賤な作業は下々の仮想マシンどもにやらせ、高貴なるサーバ本体様はその上前をハねるだけ。一度使ってしまうと、この運用の便利さは手放せない。
SRPM も Yum で最新に保ちたい
Yum はいいね。最初に Debian から Fedora にしてみたときには apt-get がなくてキレそうだったけど、今ではすっかり Yum の虜。
サーバは CentOS にして*1、パッケージの少なさにまたもやキレそうだっけど、EPEL のおかげでそれも解決。そのついでに覚えた yum-priorities プラグインがこれまた最高。自分ビルドのパッケージを exclude やら lock やらで死守していたあの頃の手間はいったい何だったのか……。
ただ、まだ1つ、問題が残っている。Yum は SRPM を管理してくれない。SRPM に管理も何もないと思われるかもしれないが、こういう事態になって困るのだ:
- 出来合いのパッケージにやや不満 (最新バージョンが使いたい、ビルドオプション変えたい、パッチ当てたい、などなど)。
- Fedora とかから SRPM をもらってくる。
- rpmbuild とかして悦*2。
- そんなことはすっかり忘れてしまった頃、Fedora の方でセキュリティフィックスが出る……。
そう。SRPM に手を出した途端、最新版が出てないか四六時中気にするあの不毛な生活に逆戻りだ。
というわけで、手持ちの SRPM が最新かどうかをチェックするスクリプトを作ってみました((yumdownloader --source
で SRPM が落とせるようになっているのと rpmdev-vercmp コマンドがある(EPEL の rpmdevtools
パッケージにあります) のが前提になります。))。/var/local/srpm にある *.src.rpm よりも新しい SRPM が出てないかを報告してくるので、cron とかで回します*3:
#! /bin/sh set -e export LC_ALL=C export LANG=C cd /var/local/srpm SrpmFileNamePattern='^\(.\+\)-\([^-]\+\)-\([^-]\+\)\.src\.rpm$' function listSrpmUri() { local Packages="$( ls *.src.rpm |sed -e "s/${SrpmFileNamePattern}/\1/" |sort |uniq )" yumdownloader --source --urls $Packages |grep -E '\.src\.rpm$' } function getSrpmFileNamePart() { local SrpmFile="$1" local Part="$2" echo "$SrpmFile" |sed -e "s/${SrpmFileNamePattern}/\\${Part}/" } function isNewerThan() { local SrpmFile1="$1" local SrpmFile2="$2" local Version1="$( getSrpmFileNamePart "$SrpmFile1" 2 )" local Version2="$( getSrpmFileNamePart "$SrpmFile2" 2 )" local Release1="$( getSrpmFileNamePart "$SrpmFile1" 3 )" local Release2="$( getSrpmFileNamePart "$SrpmFile2" 3 )" rpmdev-vercmp '' "$Version1" "$Release1" '' "$Version2" "$Release2" \ |grep -F "${Version1}-${Release1}" |grep -Fi 'newer' >/dev/null } function getSrpmId() { SrpmPackageFileName="$1" echo $( getSrpmFileNamePart "$SrpmPackageFileName" 2 ) - \ $( getSrpmFileNamePart "$SrpmPackageFileName" 3 ) \ |sed -e 's/ //g' } function checkUpdate() { local SrpmUri="$1" local RemoteFile="$( echo "$SrpmUri" |sed -e 's|^.*/\([^/]\+\)$|\1|' )" local PackageName="$( getSrpmFileNamePart "$RemoteFile" 1 )" CurrentSrpms='' for LocalFile in *.src.rpm do if [ "$( getSrpmFileNamePart "$LocalFile" 1 )" != "$PackageName" ] then continue fi if ! isNewerThan "$RemoteFile" "$LocalFile" then return 0 fi CurrentSrpms="${CurrentSrpms} $( getSrpmId "$LocalFile" )" done echo "${PackageName}:${CurrentSrpms} --> $( getSrpmId "$RemoteFile" )" } function main() { for SrpmUri in $( listSrpmUri ) do checkUpdate "$SrpmUri" done } main exit 0
cd してから実行する
いろいろとあって、svnserve
を cd
してから実行する、という必要に迫られた。tar
の -C
オプションみたいなことがしたい((逆に、tar
にわざわざ -C
があるということは、うまい逃げ道はないのかも。))。
で、sh -c
やら exec
やら sudo
やらをいろいろ弄ってみたわけだが、結局ダメ。仕方なく、こういうスクリプトに逃げましたとさ:
- /usr/local/bin/run-at
-
#! /bin/sh cd "$1" shift exec "$@"
どなたか、もっといい方法をご存じないですか?
※今回は UNIX なので、Windows の
START
コマンドは使えません。
実装者と設計者、理解することとさせること
- 理解したいと思わない人は、実装しない方がいい。
- 理解させたいと思わない人は、設計しない方がいい。
バッチファイルで、カレントディレクトリのパスが空白を含まないかを判定する
ちょっといじってみたいところがあって、Subversion を自分のところでビルドしている。
ところが、これがかなり鬱陶しい。Subversion 開発者の皆さんは UNIX ユーザが多いのだろうか? Windows 上でのビルドが一筋縄ではいかない。調子に乗って最新バージョンの 0.28.1 を使ったせいか、neon のビルドがこける。
で、あれやこれやといじった結果、カレントディレクトリのパスに空白があるとダメというショボそうな結論に至った。「$(Make)
と書かなければいけないところが "$(Make)"
になっているという」バグ*1が neon-0.28.0 で修正されたらしいが、そのあたりが悪さをしているのかもしれない*2。
で、やっと本題。
ビルド手順を間違えないようにバッチファイルを作っているのだが、これの先頭で、「カレントディレクトリのパスに空白が含まれていたらエラーで終了させる」ということがしたい。シェルスクリプトなら grep
だし WSH なら JScript の正規表現なり String.indexOf()
なりで片付けられるんだが、バッチファイルだとどうやるんだろう?
恥ずかしながら、現状の解はこう:
@ECHO OFF DIR %CD% >NUL 2>NUL IF %ERRORLEVEL% NEQ 0 ( ECHO [エラー] カレントディレクトリのパスに空白が含まれているとビルドに失敗します。>&2 EXIT /B 1 )
どなたか、もっといい方法をご存じないですか?
Subversion の属性値もコピーしてくるシェルスクリプト
Subversion でベンダブランチを作る際、一次開発元も Subversion を使っている場合には、属性値も全部そのまま持ってきたい。なんか、そういうツールは絶対どこかにあるんじゃないかとは思うんだが、探せなくて作ってしまった:
適当なワーキングコピー中にあるディレクトリを引数に指定して実行すると、そのディレクトリ以下の全内容・全属性をカレントディレクトリの下に再現する:
#! /bin/sh set -e if [ "$1" != "--sub" ] then VENDOR_ROOT="$1" if [ -z "$VENDOR_ROOT" ] then echo "usage: ${0##*/} <vendor-root>" 1>&2 exit 1 fi svn info "$VENDOR_ROOT" >/dev/null # checking whether $VENDOR_ROOT is a working copy. if echo "$VENDOR_ROOT" |grep -v '/$' >/dev/null then VENDOR_ROOT="${VENDOR_ROOT}/" fi exec find "$VENDOR_ROOT" ! -name '.svn' ! -path '*/.svn/*' \ -exec "$0" --sub "$VENDOR_ROOT" '{}' \; fi VENDOR_ROOT="$2" function CopyProperty() { local NODE_FROM="$1" local PROPERTY="$2" local NODE_TO="$3" if echo $PROPERTY |grep -E "^'" >/dev/null 2>&1 then return fi if echo $PROPERTY |grep -E '^の属性:' >/dev/null 2>&1 then return fi local VALUE="$( svn propget "$PROPERTY" "$NODE_FROM" )" svn propset "$PROPERTY" "$VALUE" "$NODE_TO" } function CopyNode() { local NODE_FROM="$1" local NODE_TO="$( echo -n "$NODE_FROM" |sed -e "s|^$VENDOR_ROOT||" )" if [ -z "$NODE_TO" ] then NODE_TO='.' fi if [ -L "$NODE_FROM" ] then ln -s "$( readlink "$NODE_FROM" )" "$NODE_TO" svn add "$NODE_TO" return fi if [ -d "$NODE_FROM" ] then if [ "$NODE_TO" != '.' ] then svn mkdir "$NODE_TO" fi else cp -p "$NODE_FROM" "$NODE_TO" svn add "$NODE_TO" fi for PROPERTY in $( svn proplist "$NODE_FROM" ) do CopyProperty "$NODE_FROM" "$PROPERTY" "$NODE_TO" done } CopyNode "$3" exit 0