miauのブログ

はてなダイアリー「miauの避難所」をはてなブログに移行しました

vss2svn.pl のユーザ認証対応ほか

前項 のつづき。結局旧バージョンの vss2svn.pl を使うことにしたわけですが。

このときは新規に SVN サーバを立てて、そこに VSS のファイルを丸ごと移動させる感じだったけど、今回やりたいのはすでに利用されている SVN に VSS の一部データを移行すること。

普通に使われている SVN で、自分が管理者でもないから

  • ユーザ認証がかかっている
  • コミットユーザを書き換えられない
  • --setdates オプションで コミット日時を書き換えられない

という状態で、このままでは使えないので、またちょっといじってみました。

完成品

変更点

SVN のユーザを指定する --svnlogin オプションを追加してみました。

  • SVN へのアクセスに利用する認証情報を USER:PASS 形式で指定する
    • SVN 上でのコミットユーザもこのユーザになるはず
  • これだけでは VSS 上のコミットユーザ&コミット日時の情報が失われるので、--svnlogin オプションが指定された場合はコミットメッセージの末尾に「by USER on YYYY-MM-DD HH:MI」みたいなメッセージを付加する

本当は

  • SVN のユーザ指定
  • コミットユーザを末尾に付加するか
  • コミット日時を末尾に付加するか

あたりを独立したオプションとして設けるべきなんでしょうけど、面倒なのでやってません。--setdates が指定されない前提で処理してます。

その他実行時の注意

VSS には JST での日時が格納されているのですが、vss2svn.pl は(--setdates オプションを渡した場合)システムのロケール情報を読み取って、これを UTC に変換した上で svn:date に設定してくれます。
コメント末尾に付加するコミット日時は、この情報を利用しているので、普通に実行されると UTC で日時が書かれてしまいます。

これを解決するためには、VSS 日付を UTC とみなすためのオプション

--timebias 0

を付加してやる必要があります。

まとめると・・・

環境変数なんかの説明をすっとばすと・・・

:: vss2svn 実行
vss2svn.pl --vssproject "$/Hoge/fuga" --svnrepo "http://svn-server/svn/Hoge/trunk/fuga" --svnlogin user:pass --timebias 0

こんな感じで実行してやればいいことになります。

ハマってた点

何度も SVN へのコミットを試すことになるから、作成したリポジトリのバックアップをとっておいて、vss2svn を実行するたびにそれを復帰してたんだけど。このやり方だと Repository UUID が同一になっちゃうせいか、TortoiseSVN で古い状態(リポジトリ置き換え前)の状態が表示されちゃったりするようで。「なんでうまくいかないんだろ?」という感じで 1 時間くらいは無駄にした。

よく考えたら SVN の格納先のパス(--svnrepo)をどんどん変えていけばよかった。

残念な点

ローカルでの動作検証が済んで、実際に SVN に格納しようとした段階で気づいたんですが・・・他の人が最新のソースをすでにアップロードしてましたorz

せっかく VSS の履歴情報も移行しようと思ったのになー。

普段 SVN の使い方が下手なのを見かけても「使われないよりはマシ、使われないよりはマシ、使われないよりは・・・」と自分に言い聞かせて乗り切ってるんだけど、履歴をばっさり捨てるのはまた話が別。私は結構コミットメッセージを丁寧に書くほうだし、同じ習慣を持ってる開発者が好きなんだけど、それを反故にされると悲しくなる。

ああ、そんなわけで↑のスクリプトは本環境では未検証です。ローカルリポジトリに対してはちゃんと動作したので大丈夫だと思いますが、もし動かなかったらすいません。

diff

ごっちゃり貼っておきますが、たいした変更は加えてません。

--- vss2svn.pl	Sat Jul 15 21:17:57 2006
+++ vss2svn.pl	Fri Aug 28 21:30:13 2009
@@ -600,7 +600,9 @@
 
         &InsertDatabaseRevision($filepath, $rev);
 
-        $USERS{ $rev->{user} } = 1;
+        unless (defined $gCfg{svnlogin}) {
+            $USERS{ $rev->{user} } = 1;
+        }
     }
 
 }
@@ -749,7 +751,7 @@
             # we're in a multi-item commit but user or comment changed;
             # commit previous action
             $multiple = 0;
-            &CommitSvn(1, $prev{comment}, $commitinfo);
+            &CommitSvn(1, \%prev, $commitinfo);
             undef $commitinfo;
             &SetSvnDates(\%prev) if $gCfg{setdates};
             %thistime = ();
@@ -759,7 +761,7 @@
             # changed; commit the single previous file
             $multiple = 0;
 
-            &CommitSvn(0, $prev{comment}, $commitinfo);
+            &CommitSvn(0, \%prev, $commitinfo);
             undef $commitinfo;
             &SetSvnDates(\%prev) if $gCfg{setdates};
             %thistime = ();
@@ -770,7 +772,7 @@
 
             if (defined $commitinfo) {
                 # done with this date, so commit what we have so far
-                &CommitSvn($multiple, $prev{comment}, $commitinfo);
+                &CommitSvn($multiple, \%prev, $commitinfo);
                 undef $commitinfo;
 
                 &SetSvnDates(\%prev) if $gCfg{setdates};
@@ -790,7 +792,7 @@
     }
 
     if (defined $commitinfo) {
-        &CommitSvn($multiple, $prev{comment}, $commitinfo);
+        &CommitSvn($multiple, \%prev, $commitinfo);
 
         &SetSvnDates(\%prev) if $gCfg{setdates};
         %thistime = ();
@@ -876,13 +878,17 @@
 #  CommitSvn
 ###############################################################################
 sub CommitSvn {
-    my($multiple, $comment, $commitinfo) = @_;
+    my($multiple, $info, $commitinfo) = @_;
+    my $comment = $info->{comment};
 
     $comment = Encode::encode('utf8', $comment) if $gCfg{utf8};
 
     open COMMENTFILE, ">$gCfg{tmpfiledir}/comment.txt"
         or die "Could not open $gCfg{tmpfiledir}/comment.txt for writing";
     print COMMENTFILE $comment;
+    if (defined $gCfg{svnlogin}) {
+        print COMMENTFILE "\nby $commitinfo->{user} on $info->{date} $info->{time}";
+    }
     close COMMENTFILE;
 
     PrintMsg "   (COMMITTING SVN...)\n";
@@ -906,7 +912,9 @@
 
     my $enc = $gCfg{utf8}? ' --encoding UTF-8' : '';
 
-    $SVN->{user} = $commitinfo->{user};
+    unless (defined $gCfg{svnlogin}) {
+        $SVN->{user} = $commitinfo->{user};
+    }
     $SVN->svn("commit$enc --file \"$gCfg{tmpfiledir}/comment.txt\" "
               . "--non-recursive", $commitinfo->{file})
         or die "Could not perform SVN commit on \"$commitinfo->{file}\". "
@@ -925,7 +933,9 @@
 
     my $enc = $gCfg{utf8}? ' --encoding UTF-8' : '';
 
-    $SVN->{user} = $commitinfo->{user};
+    unless (defined $gCfg{svnlogin}) {
+        $SVN->{user} = $commitinfo->{user};
+    }
     $SVN->svn("commit$enc --file \"$gCfg{tmpfiledir}/comment.txt\" \".\"")
         or die "Could not perform SVN commit. "
         . "Have you set your httpd authorization file correctly?";
@@ -1027,7 +1037,7 @@
 ###############################################################################
 sub Initialize {
     GetOptions(\%gCfg,'vssproject=s','vssexclude=s@','svnrepo=s','comment=s',
-               'vsslogin=s','setdates','noprompt','timebias=i','dstbias=i',
+               'vsslogin=s','svnlogin=s','setdates','noprompt','timebias=i','dstbias=i',
                'iconv=s','utf8','debug','help',);
 
     &GiveHelp(undef, 1) if defined $gCfg{help};
@@ -1069,11 +1079,16 @@
 
     $SVN = Vss2Svn::Subversion->new( $gCfg{svnrepo} );
     $SVN->{interactive} = 0;
-    $SVN->{user} = 'vss_migration';
-    $SVN->{passwd} = ''; # all passwords are blank
+    if (defined $gCfg{svnlogin}) {
+        @{ $SVN }{'user', 'passwd'} = split(':', $gCfg{svnlogin});
+    }
+    else {
+        $SVN->{user} = 'vss_migration';
+        $SVN->{passwd} = ''; # all passwords are blank
+    }
     $SVN->{_debug} = 1;
 
-    %USERS = ( vss_migration => 1, );
+    %USERS = ( $SVN->{user} => 1, );
 
     &CheckIconvPath;
 
@@ -2335,6 +2350,10 @@
 B<WARNING --> if the username/password combo you provide is
 incorrect, this program will hang as ss.exe prompts you for
 a username! (This is an unavoidable Microsoft bug).
+
+=item --svnlogin "USER:PASSWD":
+
+Set SVN username and password, separated by a colon.
 
 =item --timebias <OFFSET_MINUTES>: