なんだこれは

はてなダイアリーから移転しました。

svn blame でこんなことがしたい

subversion で管理している、Cのソースコード(rev 1234)を静的解析ツールで処理するとこんなふうなリストが出力される。

/foo/bar/baz.c:23	hogehoge..
/foo/bar/baz.c:45	fugafuga..
/foo/bar/baz.c:67	hirahore..
/foo/bar/hoge.c:18	harahore..

これに、subversion のアカウント名をつけたリストに変換したい。

/foo/bar/baz.c:23	piyo	hogehoge..
/foo/bar/baz.c:45	hiko	fugafuga..
/foo/bar/baz.c:67	masaru	hirahore..
/foo/bar/hoge.c:18	fumin	harahore..

そう、一つのファイルを複数のアカウントが編集していることがあるんだ。これがやっかい。
しかし、subversionsvn blame をつかうと実現できそうなんだ。

svn blame /foo/bar/baz.c -r 1234 | head -23 | tail -1

これであとは二番目の項目さえとりだせば、いけると思っていたんだけれど、この方法では毎回ファイルを作成してしまう。*1
だから、指摘行数が数万とあるようなダメダメな状況では時間がかかりすぎてしまう。
単純にループをまわすわけにはいかないようだ。
指摘をうけるファイルは次のファイルと同じことが多いから、svn blameで書き出すファイルを共有するしくみが必要なようだ。

やっぱり、Virtual Machineで Linux動かして、こういうのはperl と shellで組めば...

use strict;
use warnings;
use utf8;

my $path;
my $prevpath;
my @work;
my $rev=$ARGV[1];

while(<>){
  chomp;
  if( $_ =~ /([-/0-9a-zA-Z._]+):(\d+)\W(.+)$){
      $path = $1;
      my $num = $2;
      my $errorline = $3;
      if( ( (defined $prevpath) and ($path ne $prevpath )) or (not defined $prevpath)){
          if (defined $rev) {
             open $COM, '|-', "svn blame $path -r $rev";
          } else {
             open $COM, '|-', "svn blame $path";
          }
          @work = <$COM>;
          close $COM;
          $prevpath = $path;
      }
      my @line = split(/\W/, $work[$num]);
      my $account = $line[1];

      print "$path".':'."$num".':'."$account".'\t'."$errorline".'\n';
  }
}

*1:Windoseはパイプをテンポラリファイル作成で実装しているだと...。駄目だ、早くなんとかしないと...