とあるwebエンジニアの気ままな備忘録

とあるwebエンジニアの気ままな備忘録

技術的なことをメモ程度にまとめてます。
自分が後から見てわかればいいやー
という感じなので、意味不明になってるかもしれませんが。。
それでも間違えていることを書いていたら突っ込みいれてくださると助かります!

Amebaでブログを始めよう!
プロジェクト管理ツールに redmine 
バージョン管理ツールに svn
を使用しています。

redmine と svn は連携することができ、
redmine の該当するチケット番号を svn にコミットする際、入力していることにより、
チケットに関連する修正ファイルを redmine 上で確認することができます。

開発ブランチからリリースブランチへ、該当ファイルをコミットしていく作業が負担になっていましたので、処理を自動化してみました。

基本的にシェルスクリプトによるコマンド実行ですが、
commit comment から 該当のファイルを抽出する際、 PHP による処理も行っています。
以下、コードです。

まだまだ未熟者ですので、厳しい突っ込みお待ちしております!

-----------------------------------------------------------------
シェルスクリプト
-----------------------------------------------------------------
#!/bin/sh

## コンストラクタ
cd {カレントディレクトリ}
SVN_DEV="{開発ブランチリポジトリパス}"
SVN_PRO="{リリースブランチリポジトリパス}"
DEV_DIR="{開発ブランチ作業コピー}"
PRO_DIR="{リリースブランチ作業コピー}"
LOGFILE="{ログファイルパス}"
XMLFILE="{workファイルパス}"
LISTFILE="{workファイルパス}"
MOVEFILE="{workファイルパス}"
CURDIR=`pwd`
PHP=`which php`" ${CURDIR}/xml_parser.php"

## workファイル削除
if [ -e ${XMLFILE} ]; then
        rm -f ${XMLFILE}
fi
if [ -e ${LISTFILE} ]; then
        rm -f ${LISTFILE}
fi

## リリースブランチへコミットする対象チケットを決定する
echo "チケット番号を # を省略して入力してください"
echo "複数ある場合は 半角スペース で区切って入力してください"
read ANS
TICKET=${ANS}
FIELDS=`echo ${TICKET} | wc -w`

## 開発ブランチの svn log 結果を xml 形式で吐き出す
svn log ${SVN_DEV} -v --stop-on-copy --xml > ${XMLFILE}

for i in `seq 1 ${FIELDS}`
do
        NO=`echo "${TICKET}" | awk --assign awk_var="$i" '{ print $awk_var }'`
        echo "================================================"
        echo "チケット番号 : ${NO}"
        echo "================================================"
        ${PHP} ${NO}
done

## 重複ファイルを削除する
cat ${LISTFILE} | sort | uniq > ${CURDIR}/sort.log
rm -f ${LISTFILE}
cp -p ${CURDIR}/sort.log ${LISTFILE}
rm -f ${CURDIR}/sort.log

## 開発ブランチ/リリースブランチの作業コピーを最新にします
echo "================================================"
echo "${DEV_DIR} を 最新にします"
echo "================================================"
echo "${DEV_DIR}"
svn revert -R ${DEV_DIR}
svn up ${DEV_DIR}
echo "================================================"
echo "${PRO_DIR} を 最新にします"
echo "================================================"
echo "${PRO_DIR}"
svn st "${PRO_DIR}" |grep '^?'|awk '{print $2}'|xargs rm -rf
svn revert -R ${PRO_DIR}
svn up ${PRO_DIR}

## 対象ファイルをリリースブランチにコミットします
echo "================================================"
echo "今回のリリースブランチへのコミット対象一覧"
echo "================================================"
cat ${LISTFILE}
echo "================================================"
while :
do
        echo "上記をコミットしてもよろしいでしょうか?[y/n]"
        read ANS
        if [ "${ANS}" = "y" ]; then
                break
        elif [ "${ANS}" = "n" ]; then
                echo "操作は取り消されました"
                exit 0;
        fi
done

## 移動先ディレクトリを定義する
cat ${LISTFILE} | sed -e "s/\/{開発ブランチ}\//\/{リリースブランチ}\//g" > ${MOVEFILE}
while read line
do
        MOVE=`echo ${line} | sed -e "s/\/{開発ブランチ}\//\/{リリースブランチ}\//g"`
        if [ ! -e ${line} ]; then
                echo "削除開始 : ${MOVE}"
                rm -rf ${MOVE}
        fi
done < ${LISTFILE}

# svn commit を行う
## svn add 対象がある場合 svn add を実行する
ADD_NUM=`svn st "${PRO_DIR}" |grep '^?'|awk '{print $2}'| wc -l`
DEL_NUM=`svn st "${PRO_DIR}" |grep '^!'|awk '{print $2}'| wc -l`
if [ "${ADD_NUM}" != 0 ]; then
        echo "================================================"
        echo "新規追加ファイルを add します"
        echo "================================================"
        svn st "${PRO_DIR}" |grep '^?'|awk '{print $2}'|xargs svn add
fi
if [ "${DEL_NUM}" != 0 ]; then
        echo "================================================"
        echo "削除ファイルを del します"
        echo "================================================"
        svn st "${PRO_DIR}" |grep '^!'|awk '{print $2}'|xargs svn del
fi

## コミットコメント作成
for i in `seq 1 ${FIELDS}`
do
        NO=`echo "${TICKET}" | awk --assign awk_var="$i" '{ print $awk_var }'`
        if [ `echo ${#REFS}` = 0 ]; then
                REFS="refs\ #${NO}"
        elif [ `echo ${#REFS}` != 0 ]; then
                REFS="${REFS} refs\ #${NO}"
        fi
done

## svn commit 実行
echo "================================================"
echo "コミットを行います"
echo "================================================"
cd ${PRO_DIR}
svn commit ./ -m ${REFS}

echo "================================================"
echo "処理正常に終了しました"
echo "================================================"

exit 0;
-----------------------------------------------------------------

-----------------------------------------------------------------
PHP
-----------------------------------------------------------------
<?php

// コンストラクタ
$xmlfile = (__DIR__."/work/svnlog.xml");
$filename = (__DIR__."/work/xml_parse.log");

// XMLファイルの読込み
$content=file_get_contents($xmlfile);
// XMLデータを配列に格納
$xml_parser=xml_parser_create();
xml_parse_into_struct($xml_parser,$content,$vals);
xml_parser_free($xml_parser);

// 1回のコミット情報を纏める
$count = count($vals);
$cnt = 0;
$array = array();
for ($i=0; $i < $count; $i ++)
{
        $array[$cnt][] = $vals[$i];
        // コミット情報の最後の情報は commit comment のため、
        //MSG だった場合は次の配列に格納させる
        if ($vals[$i]["tag"] == 'MSG')
        {
                $cnt ++;
        }
}

// 該当するチケット番号が格納されている配列の key を取得する
unset($count);
$count = count($array);
for ($i=0; $i < $count; $i ++)
{
        foreach ($array[$i] as $commit_log)
        {
                foreach ($commit_log as $key => $commit_log2)
                {
                        if ($key === "value" && strstr($commit_log2,"refs #".$argv[1]) !== FALSE)
                        {
                                $array_key[] = $i;
                        }
                }
        }
}

if (empty($array_key))
{
        echo "該当するチケット番号に紐づく修正ファイルはありませんでした\n";
        return;
}

// 抽出した key の配列に格納されている file_path を取得する
// 取得した file_path は /tmp/xml_parse.log に出力する
unset($count);
$count = count($array_key);
for ($i = 0; $i < $count; $i ++)
{
        $cnt = 0;
        foreach ($array[$array_key[$i]] as $key => $value)
        {
                if ($value["tag"] === "PATH")
                {
                        echo $array[$array_key[$i]][$cnt]["value"]."\n";
                        file_put_contents($filename,$array[$array_key[$i]][$cnt]["value"]."\n",FILE_APPEND);
                }
                $cnt ++;
        }
}

?>

-----------------------------------------------------------------


auto_increment されているカラムでもなくて、IDがランダム(正確には生成ルールはある。)で割り振られます。
デバッグするときに空いてる番号で100レコードくらいデータ生成したい。
という要望があり、そのとき対応した内容をメモしておきます。

例として、下記のようなテーブル構成だったとします。
-----------------------
CREATE TABLE `test` (
  `id` int(10) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
-----------------------

下記のようなクエリを実行すると、空いている番号のうち一番小さい番号を返してくれます。

-----------------------
SELECT
    max(ID)+1 as empty_ID
FROM
    (SELECT
        0 as ID
UNION 
SELECT
    ID
FROM
    table_name
    ) as z
WHERE
    ID<(SELECT
            min(ID) as ID
        FROM
            (SELECT
                (SELECT
                    count(*)
                FROM
                    table_name
                WHERE
                    ID<=x.ID
                ) as rownum,
                ID
            FROM
                table_name as x
            ) as y
        WHERE
            rownum<>ID
        );
-----------------------

データはこんな感じで入ってるとします。

mysql> select * from test;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
|  5 |
|  8 |
|  9 |
| 10 |
+----+

で、実際の実行結果はこんな感じです。
期待するのは 6 が返ってくることです。

------------------------------ 
mysql> SELECT
    ->     max(id)+1 as empty_id
    -> FROM
    ->     (SELECT
    ->         0 as id
    -> UNION 
    -> SELECT
    ->     id
    -> FROM
    ->     test
    ->     ) as z
    -> WHERE
    ->     id<(SELECT
    ->             min(id) as id
    ->         FROM
    ->             (SELECT
    ->                 (SELECT
    ->                     count(*)
    ->                 FROM
    ->                     test
    ->                 WHERE
    ->                     id<=x.id
    ->                 ) as rownum,
    ->                 id
    ->             FROM
    ->                 test as x
    ->             ) as y
    ->         WHERE
    ->             rownum<>id
    ->         );
+----------+
| empty_id |
+----------+
|        6 |
+----------+
1 row in set (0.00 sec)
------------------------------
無事に 6 が返ってきました。


今のレコードに対して一回連番を振っているので、本当であれば連番管理台帳的なテーブルを作ってあげて、ストアド組めばいいと思うのですが、、(ググったらそんなこと書いてました。)
ストアドが良くわからないので、強引にこんなことしてみました。

まぁ…デバッグでしか使わないしいいかなと。。

とりあえずメモメモ。。
〆(・ω・`*) 

ssh -ntt ${user}@${host}
とすると、${host} で ${user} が を実行して返ってきてくれる。

でも、こうするためには ${user} は ${host} ではNonPassでログイン出来ないといけない。
Password を聴かれてしまうなら expect コマンドを使用するといい。

RedHat系なら
yum install expect

で入ると思う。試してないけど。
使い方としては、

--------------------------
spawn ssh $LOGINACCOUNT@$HOST
expect \"$LOGINACCOUNT@$HOST's password:\"
send \"$LOGINPASSWORD\n\"

"$LOGINACCOUNT@$HOST's password:"
--------------------------

っていう文字が標準出力に表示されると、
$LOGINPASSWORD
を標準入力に送る。