redmine ソースパケジ掘削 (2)
メンテナスクリプト掘削情報を以下に。
debian/prerm
*rm なナニから確認していきます。とりあえず以下はおやくそく。
#!/bin/sh # prerm script for redmine # # see: dh_installdeb(1) set -e #set -x . /usr/share/debconf/confmodule
で、prerm では引数が remove の場合のみ処理が記述されています。
case "$1" in remove) # snip ;; purge|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; esac #DEBHELPER# exit 0
では remove な処理はどうなっているか、というと殆どが dbconfig-common な処理になっています。まず redmine/oldinstances なテンプレを取得して以下。
db_get redmine/old-instances || true gOldInstances="${RET}" for lInstance in $gOldInstances; do db_get redmine/instances/$lInstance/dbconfig-install || true if [ "$RET" = "true" ]; then ( . /usr/share/dbconfig-common/dpkg/prerm ; dbc_go redmine/instances/$lInstance $@ ) fi done
基本的に値は default 一発らしいのですが、そうでないケイスってどうなってるのか、というかどういったケイスでそうなるのか、とか確認したい。とは言え条件式的に言えば dbconfig-common が導入されてりゃ値は true なのだろうなと。
そうであれば dbconfig-common な prerm を source して dbc_go コマンド実行してるのか。おそらくこれは定型なナニのはず。
次は以下。
db_get redmine/current-instances || true gInstances="${RET}" for lInstance in $gInstances; do db_get redmine/instances/$lInstance/dbconfig-install || true if [ "$RET" = "true" ]; then ( . /usr/share/dbconfig-common/dpkg/prerm ; dbc_go redmine/instances/$lInstance $@ ) fi done
同じことを redmine/current-instances についても実行しております。で、最後に以下。
# removes symbolic links installed by vendordir="/usr/share/redmine/vendor/" rm -f ${vendordir}rails
こちらは postinst で symlink 張ってる以下なナニの後始末ですね。
if [ ! -L vendor/rails ]; then ln -s "$fRailsDir" vendor/rails else
これで prerm はおしまい。
debian/postrm
次は postrm ですが、こちらも短いです。まずはお約束。ってか postrm は confmodule の存在チェックしてますね。何らかの根拠があるのかどうか。削除する場合、スデに debconf が削除済み、ってことがあるの? debconf って Pre-Depends なパケジなのだけどどうなんでしょ。
#!/bin/sh # postrm script for redmine # # see: dh_installdeb(1) set -e #set -x if [ -f /usr/share/debconf/confmodule ]; then . /usr/share/debconf/confmodule fi
あと、postrm は remove および purge な引数にのみ対応な様子。
case "$1" in upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) ;; remove) # (snip) ;; purge) # (snip) ;; esac #DEBHELPER# exit 0
順に見ていきます。とりあえず上からってことで remove から。
remove
ここでも存在チェックしてますね。削除の順は保証の範疇外なのだろうか。あ、dbconfig-common は Pre-Depends ではなくて Depends になってますね。
if [ -f /usr/share/dbconfig-common/dpkg/postrm ]; then db_get redmine/old-instances || true gOldInstances="${RET}" for lInstance in $gOldInstances; do db_get redmine/instances/$lInstance/dbconfig-install || true if [ "$RET" = "true" ]; then ( . /usr/share/dbconfig-common/dpkg/postrm ; dbc_go redmine/instances/$lInstance $@ ) fi done
ここも定型なのでしょうね。current-instances についても同じことをしてますが引用は略します。remove な処理はこれだけです。
次は purge なんですが
purge
ヤッツケ感満点な書き方になってます。
db_get redmine/old-instances || true gOldInstances="${RET}" db_get redmine/current-instances || true gInstances="${RET}"
old-instances と current-instances をざくっと取得。これまで別で書いてたのに何があったのだろう、と心配になってしまいます。で、存在チェックしつつ定型の処理。
if [ -f /usr/share/dbconfig-common/dpkg/postrm ]; then for lInstance in $gOldInstances; do db_get redmine/instances/$lInstance/dbconfig-install || true if [ "$RET" = "true" ]; then ( . /usr/share/dbconfig-common/dpkg/postrm ; dbc_go redmine/instances/$lInstance $@ ) fi done
同じことを current-instances についても実行してますが引用略。ここまでは remove と同様です。ここからが purge 特有になります。基本的には /etc とか /var 配下のファイルの削除となっている様子。
まず /etc 配下のナニを old-instances および current-instances について ucf で purge してますね。
if which ucf >/dev/null 2>&1; then for lInstance in $gOldInstances; do ucf --purge /etc/redmine/$lInstance/database.yml ucf --purge /etc/redmine/$lInstance/email.yml ucf --purge /etc/redmine/$lInstance/session.yml done for lInstance in $gInstances; do ucf --purge /etc/redmine/$lInstance/database.yml ucf --purge /etc/redmine/$lInstance/email.yml ucf --purge /etc/redmine/$lInstance/session.yml done fi
む、てことはここらへんは postinst あたりで ucf 使って作成してるのかな。ちょろっと見てみたところでは、database.yml と session.yml は云々されてるけど、email.yml は ucf で云々、ってのは無いみたい。
で、以降でファイルを削除して db_purge で締め。
# package-generated or runtime files are removed rm -f /usr/share/redmine/db/schema.db # removing /var/run files is not needed : it is mounted tmpfs in wheezy - anyway it does not hurt rm -rf /var/run/redmine rm -rf /var/log/redmine rm -rf /usr/share/redmine/tmp rm -rf /var/lib/redmine/*/sessions rm -rf /var/cache/redmine rm -rf /etc/redmine # user files are not rmdir /var/lib/redmine/*/files || true rmdir /var/lib/redmine/* || true db_purge
上記、基本的に postinst で mkdir しているものですかね。なんか /var/run なあたりに微妙なコメントがありますがスルー。
これらを踏まえて postinst を確認していきます。
debian/postinst
順に確認していきます。まずお約束で以下。
#!/bin/sh # postinst script for redmine # # see: dh_installdeb(1) set -e #set -x RAKE_VERBOSE=false . /usr/share/debconf/confmodule
で、コメントにもあるように prerm を remove で呼び出して postrm を purge で呼び出している模様。まず prerm から
# remove and purge old instances each time postinst is called db_get redmine/old-instances || true gOldInstances="${RET}" for lInstance in $gOldInstances; do db_get redmine/instances/$lInstance/dbconfig-install || true if [ "$RET" = "true" ]; then ( . /usr/share/dbconfig-common/dpkg/prerm ; dbc_go redmine/instances/$lInstance remove ) fi done
で、purge なナニは以下。このパケジの postrm が呼びだされるのか、とナチュラル勘違いをしそうになりました。そうではないはず。
で、/etc 配下を ucf で purge したりディレクトリ削除したりもしてます。
for lInstance in $gOldInstances; do db_get redmine/instances/$lInstance/dbconfig-install || true if [ "$RET" = "true" ]; then ( . /usr/share/dbconfig-common/dpkg/postrm ; dbc_go redmine/instances/$lInstance purge ) fi if which ucf >/dev/null 2>&1; then ucf --purge /etc/redmine/$lInstance/database.yml ucf --purge /etc/redmine/$lInstance/email.yml ucf --purge /etc/redmine/$lInstance/session.yml fi rm -rf /etc/redmine/$lInstance done db_set redmine/old-instances ""
で、この時点で redmine/old-instances なテンプレを初期化してますね。その後、もう少し初期処理は続きます。変数設定とか。
fRailsEnv=production fRailsLog=/var/log/redmine fRailsVar=/var/lib/redmine fRailsCache=/var/cache/redmine fRailsDir=/usr/lib/ruby/vendor_ruby/rails if [ ! -e "$fRailsDir" ]; then # keep rails package compatibility fRailsDir="/usr/share/rails-ruby1.8" fi
あとは configure ないし reconfigure の場合、な記述になってます。
case "$1" in configure|reconfigure)
とりあえずアタマから順に見ていきます。
# passenger runs as the owner of that file, thanks Micah Anderson. chown www-data:root /usr/share/redmine/config/environment.rb chown -f www-data:www-data $fRailsLog chown -f www-data:www-data $fRailsVar chown -f www-data:www-data $fRailsCache savedir="`pwd`" cd /usr/share/redmine
これらのディレクトリについてはパケジに同梱されております。postinst はパケジが展開された後に実行されるはずなのでディレクトリの実態はスデに存在する、と。で、それに対して apache な権限を付けてます。ちなみにいっちゃん上のソレはコメントにあるように passenger に配慮したものらしい。逆に言うと redmine て apache+passenger 限定なのかどうなのか。
で、pwd 保存しといて /usr/share/redmine に cd してます。以降は若干 Rails 固有の下準備になるのかどうなのか。
if [ -L vendor/railties ]; then # rails 2.2 to 2.3 migration rm -f vendor/actionmailer rm -f vendor/actionpack rm -f vendor/activemodel rm -f vendor/activerecord rm -f vendor/activeresource rm -f vendor/activesupport rm -f vendor/railties rm -f vendor/rails fi
vendor/railties な symlink があったら云々。あまり Rails 詳しくないのでスルーします。次は vendor/rails な symlink があるとか無いとかなナニ。
if [ ! -L vendor/rails ]; then ln -s "$fRailsDir" vendor/rails else # rails 2.3 to ruby-rails-2.3 migration fMigrateLink=$(readlink vendor/rails) if [ "$fMigrateLink" != "$fRailsDir" ]; then rm -f vendor/rails ln -s "$fRailsDir" vendor/rails fi fi
無ければ作って、あったらリンク実体の確認して云々。で、ファイルが無かった作成したりとか
if [ ! -e app/views/members ]; then mkdir app/views/members fi if [ ! -e app/sweepers ]; then mkdir app/sweepers fi if [ ! -e lib/plugins ]; then mkdir lib/plugins fi
あるいは /usr 配下は writable ではないから云々とか
# this directory should never be used: /usr not writable policy if [ -e tmp ]; then rm -rf tmp fi
で、カレントディレクトリを元に戻して終了。
cd $savedir ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac
で、ここからが核心になります。remine/current-instances 取得して云々
db_get redmine/current-instances || true gInstances="${RET}" for lInstance in $gInstances; do
まず下準備。
fRailsEtc=/etc/redmine/$lInstance fRailsLog=/var/log/redmine/$lInstance fRailsVar=/var/lib/redmine/$lInstance fRailsCache=/var/cache/redmine/$lInstance # dbconfig needs this folder to ouput database.yml mkdir -p $fRailsEtc chown -f www-data:www-data $fRailsEtc withdb=0 lInstall=0
current-instances が複数だった場合に切り分けが可能な形になってます。/etc/redmine まではパケジに含まれてますがその先は mkdir で作成してますね。ucf じゃなくて良いのだろうか。このあたりに切り分けも理解が微妙。
次は dbconfig-common のお約束なナニ。
db_get redmine/instances/$lInstance/dbconfig-install || true if [ "$RET" = "true" ]; then lInstall=1 fCode=0 db_get redmine/instances/$lInstance/dbconfig-reinstall || fCode=$? if [ $fCode -eq 0 ]; then if [ "$RET" = "false" ]; then db_fget redmine/instances/$lInstance/dbconfig-reinstall seen || true if [ "$RET" = "true" ]; then lInstall=0 fi fi fi fi
あら、ここで lInstall な変数をもごもごしてますね。dbconfig-install とか dbconfig-reinstall が云々というあたり、若干微妙です。dbconfig-common 関連のドキュメントが少なすぎる。
で、直後で lInstall の値によって処理が分岐してます。
if [ $lInstall -eq 1 ]; then
とりあえず lInstall が 0 のケイスから (短いので) ということで以下。
elif [ -e "$fRailsEtc/database.yml" ]; then # don't reinstall, but upgrade withdb=1 lInstall=0 fi
ええと lInstall が 0 の場合ってのは
- dbconfig-install が false
- dbconfig-install が true で dbconfig-reinstall が false で dbconfig-reinstall の seen フラグが true
下のケイスってコメントにある_upgrade じゃなくて upgrade_というソレに合致するのかどうか。あ、上の条件に /etc/redmine/default/database.yml がある場合、って事か。
で、次は lInstall が単純に 1 の場合を確認します。ここ、基本的には dbconfig-common なナニをもごもごしてる感じですねぇ。
とりあえず先頭あたりが以下。
fYml=$fRailsEtc/database.yml.new lTemplate="database.yml.template" # if dbtype=sqlite3, use dbbasepath, else dbname fCode=0 db_get redmine/instances/$lInstance/database-type || fCode=$? lDbType="$RET" if [ $fCode -eq 0 -a "$lDbType" = "sqlite3" ]; then lTemplate="database-sqlite.yml.template" lDbType="sqlite" fi
補足するとソースパケジの debian 配下に conf というディレクトリがありまして、その中には
- database-sqlite.yml.template
- database.yml.template
というファイルが投入されております。lDbType の微妙な書き換えも気にはなりますが、スルーします。次はコメントにある通り、redmine-$lDbType なパケジが installed なのかどうかな分岐。
# check if redmine-$lDbType is installed, if not, don't configure and explain what to do hasPack=$(dpkg-query -W -f='${Status}\n' "redmine-$lDbType" |cut -d" " -f3) if [ "$hasPack" != "installed" ]; then # not installed, this cannot be detected in debian/config # since redmine-* packages are not yet installed db_subst redmine/missing-redmine-package dbtype "$lDbType" db_subst redmine/missing-redmine-package instance "$lInstance" db_fset redmine/missing-redmine-package seen "false" db_input high redmine/missing-redmine-package || true db_go || true db_stop || true echo "Skipping $lInstance because of missing dependency." continue fi
dpkg-query ってコマンドがあるんスね。てか、このケイスって非常にレアなエラーケイスになるのでしょうか。redmine-* なパケジは Depends に入っているはずなので。
で、次か。次は dbconfig-common な変数 (?) 設定してます。
dbc_generate_include=template:$fYml dbc_generate_include_args="-o template_infile=/usr/share/redmine/templates/${lTemplate}" dbc_generate_include_owner="root:www-data" dbc_generate_include_perms="640" dbc_dbfile_owner="root:www-data" # this is for sqlite3 to be r/w for www-data dbc_dbfile_perms="0660" dbc_dbuser=redmine # make sure mysql or pgsql database charset is UTF8 dbc_mysql_createdb_encoding="UTF8" dbc_pgsql_createdb_encoding="UTF8" # use same dbname if one has been registered in debconf before # this is also needed for migration from version <= 0.9.0~svn2819
データベースパケジの属性な設定に見えます。このあたりの変数なナニとかもあまりドキュメントが無いんですがソース嫁ってことなのかなぁ。
次に出てくるのは DB 実体へのパスなどの情報設定ですね。
fCode=0 db_get redmine/instances/$lInstance/db/dbname || fCode=$? if [ $fCode -eq 0 -a -n "$RET" ]; then dbc_dbname="$RET" else dbc_dbname=redmine_$lInstance fi fCode=0 db_get redmine/instances/$lInstance/db/basepath || fCode=$? if [ $fCode -eq 0 -a -n "$RET" ]; then dbc_basepath="$RET" fi
dbname なテンプレ設定されてればそれがファイル名になる。そうでなければ redmine_sqlite みたいな形になる。あるいは basepath なテンプレ設定されてれば云々。確認できてるところでは dbname は未設定で basepath は /var/lib/dbconfig-common なんちゃら、が設定されてたはず。あ、dbname は設定されてますね。
redmine/instances/default/db/basepath: /var/lib/dbconfig-common/sqlite3/redmine/instances/default redmine/instances/default/db/dbname: redmine_default
dbname は設定されてたのか後から、なのかは不明です。次は以下なのですが、何を意図しているのか不明。
ucf --purge $fYml ( . /usr/share/dbconfig-common/dpkg/postinst ; dbc_go redmine/instances/$lInstance $@ ) ucf --purge $fYml
dbconfig-common なナニは定型なんだと思いますが、ucf --purge で囲んでいるのが意味不明。で、次で database.yml が作成完了するのかな。
if [ -e $fYml ]; then hasdb=$(grep -m 1 -o -E 'adapter: (mysql|pgsql|sqlite3|postgresql)' $fYml) || true if [ -n "$hasdb" ]; then hasdb=$(echo -n ${hasdb#*:}) withdb=1 case "$hasdb" in mysql|postgresql|pgsql) sed -i -r -e 's/pgsql/postgresql/g' $fYml ;; sqlite3) sed -i -r -e 's/^[^#]+((host|port|username|password): [^:]*)$/# \1/g' $fYml ;; esac fi ucf --debconf-ok $fYml /etc/redmine/$lInstance/database.yml rm -f $fYml fi
置き換えたりコメントアウトしてたりします。最後に ucf で database.yml を投入してますね。これは postrm で ucf --purge されていたはず。
次からが核心部分のクライマックスとなります。
とりあえず処理の対象は configure および reconfigure な様子。
case "$1" in configure|reconfigure) # (snip) ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac
では中身を見ていきます。まずはディレクトリを掘って権限の調整。
# create directories mkdir -p $fRailsLog mkdir -p $fRailsVar mkdir -p $fRailsVar/files mkdir -p $fRailsCache mkdir -p $fRailsCache/plugin_assets chmod 750 $fRailsLog chmod 750 $fRailsVar chmod 755 $fRailsCache chmod 755 $fRailsCache/plugin_assets chown -f www-data:www-data $fRailsLog chown -f www-data:www-data $fRailsVar chown -f www-data:www-data $fRailsVar/files chown -f www-data:www-data $fRailsCache chown -f www-data:www-data $fRailsCache/plugin_assets
で、カレントディレクトリを保存しておいて /usr/share/redmine に移動。
savedir="`pwd`" cd /usr/share/redmine
db/schema.db をコピーしています。なんとなく ucf 使うか使わないかなナニが微妙だなぁ。ここでは単純に cp で良いらしい。
# copy schema.db to its instance directory if [ -f db/schema.db ]; then cp db/schema.db $fRailsCache/schema.db fi
次は $fRailsEtc/session.yml が無かった場合に云々、な模様。
# add secret key, set permissions, manage file with ucf if [ ! -f "${fRailsEtc}/session.yml" ]; then
そうか session.yml をここで生成してるんですね。で、ucf で云々か。
rake -s generate_session_store YML_SESSION_FILENAME="session.yml.new" RAILS_ENV=$fRailsEnv X_DEBIAN_SITEID="${lInstance}" || true chown -f root:www-data ${fRailsEtc}/session.yml.new chmod 640 ${fRailsEtc}/session.yml.new ucf --debconf-ok ${fRailsEtc}/session.yml.new ${fRailsEtc}/session.yml rm ${fRailsEtc}/session.yml.new echo "A new secret session key has been generated in ${fRailsEtc}/session.yml"
う、これって rake でいきなり /etc/redmine 配下 (ちょっと違うけど) に session.yml.new が生成されるの? 直前で /usr/share/redmine に cd してるのでカレントディレクトリはそこなはず。
で、探してみたら、ありました。config/environment.rb な模様。
ENV['X_DEBIAN_SITEID'] ||= 'default' ENV['RAILS_ETC'] ||= "/etc/redmine/#{ENV['X_DEBIAN_SITEID']}"
environment.rb もでびあん方式にするために相当手が入ってるんだろうな。以降は session.yml があった場合の処理になるのか。
else fHasOldSessionName=$(fgrep -c session_key "${fRailsEtc}/session.yml" || true) if [ $fHasOldSessionName -gt 0 ]; then # in-place, because ucf might be configured to keep the old version without asking sed -i -r -e 's/session_key/key/g' ${fRailsEtc}/session.yml fi fi
session_key という文言を置きかえているのかな。次はファイルがあったら云々。意味不明なのでスルー気味で。
if [ -f config/initializers/session_store.rb ]; then mv config/initializers/session_store.rb config/initializers/session_store.rb.dpkg-old echo "The old secret session key can be found in /usr/share/redmine/config/initializers/session_store.rb.dpkg-old" fi
核心部分の最後は withdb が 1 ならば、という条件付き。新規導入の場合と upgrade の場合、ということで良いかな。
if [ $withdb -eq 1 ]; then
まず default-language なテンプレの値を DEFAULT_LANGUAGE という変数に格納してます。
db_get redmine/instances/${lInstance}/default-language && DEFAULT_LANGUAGE="$RET"
で、rake db:migrate してますね。
# handle rake install echo "Populating database for redmine instance \"${lInstance}\". This may take a while." fCode=0 rake -s db:migrate RAILS_ENV=$fRailsEnv X_DEBIAN_SITEID="${lInstance}" VERBOSE=$RAKE_VERBOSE || fCode=$?
で、戻りを確認。
if [ $fCode -eq 0 ]; then echo "Done."
新規導入だったら (?)
if [ $lInstall -eq 1 ]; then
rake redmine:load_default_data して production.log を云々。
rake -s redmine:load_default_data RAILS_ENV=$fRailsEnv X_DEBIAN_SITEID="${lInstance}" REDMINE_LANG=$DEFAULT_LANGUAGE || true # because rake task is executed as root here, and this file is used later by web server, make sure owner is www-data touch ${fRailsLog}/production.log chown -f www-data:www-data ${fRailsLog}/production.log fi
ネストが深いですね。次に db:migrate_plugins して終わり。
# handle plugins migration rake -s db:migrate_plugins RAILS_ENV=$fRailsEnv X_DEBIAN_SITEID="${lInstance}" VERBOSE=$RAKE_VERBOSE || true
以下は rake db:migrate が失敗した場合のナニです。
else echo "Error when running rake db:migrate, check database configuration." exit -1 fi
以下は withdb が 1 以外の場合のナニ。
else echo "Redmine instance \"${lInstance}\" database must be configured manually." fi cd $savedir || true
最後にカレントディレクトリを元に戻しておしまい。こうして見るに他の Rails な Web アプリでも redmine 方式を踏襲してメンテナスクリプトを作るのはありだと思ってます。
ただ、今回は sqlite3 限定にする方向なので沢山手が入るけどある意味簡単になるはず。