CVS のレポジトリをまるごと Mercurial 化するスクリプト
だんだんスニペット置き場になりつつあるような気がする…。いや、日本語で喋るかプログラミング言語で喋るかの違いしかないよね。
追記1: 今見たら EXIT_SUCCESS がなぜか 1 になってたので修正しました。はずかしー><
追記2: -d:pserver:anonymous... はあくまで例です。好きなCVSレポジトリを指定できます (そりゃそうか)。
以下のスクリプトの使い方
hg convert を使うための前提条件 (cvsps を入れとくとか、hgrc に hgext.convert= を追加しておくとか) はクリアしておかないと正しく動作しません。
基本は
./cvs2hg.sh -d:pserver:anonymous@pam-mysql.cvs.sourceforge.net:/cvsroot/pam-mysql
でOK。これを実行すると、次のようなメッセージが表示され、カレントディレクトリに1モジュール=1レポジトリの対応でレポジトリが作られる。
Retrieving module list from :pserver:anonymous@pam-mysql.cvs.sourceforge.net:/cvsroot/pam-mysql... done. The following modules will be checked out and converted to Mercurial repositories: * CVSROOT * pam_mysql * pam_mysql_ng Do you want to proceed? [y/n]: y Checking out module CVSROOT... done. Converting CVSROOT... done. Checking out module pam_mysql... done. Converting pam_mysql... done. Checking out module pam_mysql_ng... done. Converting pam_mysql_ng... done.
./cvs2hg.sh
-d を省略すると環境変数 CVSROOT が参照される。
./cvs2hg.sh -d:pserver:anonymous@pam-mysql.cvs.sourceforge.net:/cvsroot/pam-mysql /path/to/some-location
/path/to/some-location というディレクトリにレポジトリが作られる。
./cvs2hg.sh -d:pserver:anonymous@pam-mysql.cvs.sourceforge.net:/cvsroot/pam-mysql -C
-C オプションをつけると、次のようなメッセージが出て、CVS レポジトリとの同期用クローンがモジュール名に .sync というサフィックスをつけたディレクトリに作られる。
Creating a clone for synchronization in ./CVSROOT.sync... done. Creating a clone for synchronization in ./pam_mysql.sync... done. Creating a clone for synchronization in ./pam_mysql_ng.sync... done.
このレポジトリで
cvs up hg co hg push
を自動的にやってやれば、MercurialとCVSのレポジトリを (簡易的に) 同期できる。なお、ブランチは考慮していない。
#!/bin/bash # CVS to HG (mercurial) fully-automatic conversion script # 2008 Copyright (C) 詠み人知らず. No rights reserved. EXIT_SUCCESS=0 EXIT_INT=130 EXIT_TERM=139 EXIT_FATAL=255 CVS=cvs HG=hg progname=`basename $0` usage() { echo "usage: $progname [-dCVSROOT] [-C] [output-dir]" } prompt() { echo -n "$1 [y/n]: " while read resp; do [ "$resp" = "y" -o "$resp" = "Y" ] && return 0 [ "$resp" = "n" -o "$resp" = "N" ] && return 1 echo -n "Enter either \`y' or \`n': " done } output_dir="." create_sync_dir= while [ ! -z "$1" ]; do case $1 in -d*) CVSROOT=`echo $1 | sed -e 's/^-d//'` export CVSROOT ;; -C) create_sync_dir=1 ;; *) output_dir="$1" ;; esac shift done if [ -z "$CVSROOT" ]; then echo "$progname: no CVSROOT specified." 2>&1 exit $EXIT_FATAL fi CVSCONV_ROOT=`mktemp -d` ( try() { trap 'echo interrupted.; return $EXIT_INT' INT trap 'echo aborted.; return $EXIT_TERM' TERM cvsroot_dir=`echo "$CVSROOT" | sed -e 's/^.*:\([^:]*\)$/\1/g'` modules_file="$CVSCONV_ROOT/.modules" echo -n "Retrieving module list from $CVSROOT... " fifo="$CVSCONV_ROOT/.fifo" mkfifo $fifo ( sed -e "s#^$cvsroot_dir\\/\\?\\([^/]*\\).*,v\$#\\1#; t e; d; :e" "$fifo" \ | uniq > "$modules_file" ) & if ! error_msg=`"$CVS" rlog -R . 2>&1 > "$fifo"`; then echo "failed." echo "$progname: subprocess returned error status: $error_msg" >&2 return $? fi wait echo "done." echo echo "The following modules will be checked out and converted to Mercurial " echo "repositories:" echo sed -e 's/^/ * /' "$modules_file" echo if ! prompt "Do you want to proceed?"; then echo "Cancelled." return 1 fi echo cat "$modules_file" | while read module; do echo -n "Checking out module $module... " pushd "$CVSCONV_ROOT" >/dev/null if ! error_msg=`"$CVS" co "$module" 2>&1 > /dev/null`; then echo "failed." echo "$progname: subprocess returned error status: $error_msg" >&2 return $? fi echo "done." popd >/dev/null co_dir="$CVSCONV_ROOT/$module" echo -n "Converting $module... " if ! error_msg=`"$HG" convert "$co_dir" "$output_dir/$module" 2>&1 >/dev/null`; then echo "failed." echo "$progname: subprocess returned error status: $error_msg" >&2 return $? fi echo "done." if [ ! -z "$create_sync_dir" ]; then sync_dir="$output_dir/$module.sync" echo -n "Creating a clone for synchronization in $sync_dir... " if ! error_msg=`"$HG" clone "$output_dir/$module" "$sync_dir" 2>&1`; then echo "failed." echo "$progname: subprocess returned error status: $error_msg" >&2 return $? fi if ! error_msg=`( cd "$co_dir"; find . -type d -name "CVS" ) |\ while read dir; do if [ -d "$sync_dir/\`dirname $dir\`" ]; then cp -R "$co_dir/$dir" "$sync_dir/$dir" fi done 2>&1`; then echo "failed." echo "$progname: subprocess returned error status: $error_msg" >&2 return $? fi if [ ! -e "$sync_dir/.hgignore" ]; then echo "syntax: glob" > "$sync_dir/.hgignore" fi format=`sed -e '1 { s/^\s*syntax:\s*//; p }; d' "$sync_dir/.hgignore"` case "$format" in glob) echo 'CVS' >> "$sync_dir/.hgignore" ;; regexp) echo '^CVS$' >> "$sync_dir/.hgignore" ;; esac echo "done." fi done return 0 } finally() { rm -rf "$CVSCONV_ROOT" } try; STATUS=$?; finally exit $STATUS ) exit $?