4 # (C) 2005 The Measurement Factory http://www.measurement-factory.com/
5 # This software is distributed under Apache License, version 2.0.
8 # The cvsVsvn.pl script compares CVS and Subversion projects. The
9 # user is notified if project files maintained by CVS differ from
10 # those maintained by Subversion:
12 # $ CVSROOT=/my/cvsrepo ./cvsVsvn project1 svn+ssh://host/path/projects/p1
13 # collecting CVS tags...
15 # comparing tagged snapshots...
16 # HEAD snapshots appear to be the same
18 # CVS and SVN repositories differ because cvs_foo and svn_tags_foo
19 # export directories differ in cvsVsvn.tmp
21 # The comparison is done for every CVS tag and branch (including
22 # HEAD), by exporting corresponding CVS and Subversion snapshots and
23 # running 'diff' against the two resulting directories. One can edit
24 # the script or use the environment variable DIFF_OPTIONS to alter
25 # 'diff' behavior (e.g., ignore differences in some files).
27 # Commit logs are not compared, unfortunately. This script is also
28 # confused by files that differ due to different keyword expansion by
33 # cvsVsvn exports a user-specified module from CVS and Subversion
34 # repositories and compares the two exported directories using the
35 # 'diff' tool. The procedure is performed for all CVS tags (including
38 die(&usage
()) unless @ARGV == 2;
39 my ($CvsModule, $SvnModule) = @ARGV;
41 my $TmpDir = 'cvsVsvn.tmp'; # directory to store temporary files
43 my @Tags = &collectTags
();
45 print(STDERR
"comparing tagged snapshots...\n");
46 foreach my $tagPair (@Tags) {
47 &compareTags
($tagPair->{cvs
}, $tagPair->{svn
});
50 print(STDERR
"CVS and Subversion repositories appear to be the same\n");
54 print(STDERR
"collecting CVS tags...\n");
63 # get CVS log headers with symbolic tags
66 my $cmd = sprintf('cvs rlog -h %s', $CvsModule);
67 open(IF
, "$cmd|") or die("cannot execute $cmd: $!, stopped");
70 my ($name, $version) = /\s+(\S+):\s*(\d\S*)/;
71 if ($inNames = defined $version) {
72 my @nums = split(/\./, $version);
74 (2*int(@nums/2) != @nums) ||
75 (@nums > 2 && $nums[$#nums-1] == 0);
76 my $status = $isBranch ?
'branches' : 'tags';
77 my $oldStatus = $names{$name};
78 next if $oldStatus && $oldStatus eq $status;
79 die("change in $name tag status, stopped") if $oldStatus;
80 $names{$name} = $status;
83 $inNames = /^symbolic names:/;
88 while (my ($name, $status) = each %names) {
91 svn
=> sprintf('%s/%s', $status, $name)
93 push (@tags, $tagPair);
96 printf(STDERR
"found %d CVS tags\n", scalar @tags);
101 my ($cvsTag, $svnTag) = @_;
108 &diffDir
($cvsTag, $svnTag);
110 # identical directories, clean up
115 my ($cvsTag, $svnTag) = @_;
116 my $cvsDir = &cvsDir
($cvsTag);
117 my $svnDir = &svnDir
($svnTag);
119 my $same = systemf
('diff --brief -b -B -r "%s" "%s"',
120 $cvsDir, $svnDir) == 0;
121 die("CVS and SVN repositories differ because ".
122 "$cvsDir and $svnDir export directories differ in $TmpDir; stopped")
125 print(STDERR
"$cvsTag snapshots appear to be the same\n");
131 &systemf
('mkdir %s', $dir) == 0 or die("cannot create $dir: $!, stopped");
136 chdir($TmpDir) or die($!);
140 chdir('..') or die($!);
141 &systemf
('rm -irf %s', $TmpDir) == 0
142 or die("cannot delete $TmpDir: $!, stopped");
148 my $dir = &cvsDir
($cvsTag);
150 &systemf
('cvs -Q export -r %s -d %s %s', $cvsTag, $dir, $CvsModule) == 0
151 or die("cannot export $cvsTag of CVS module '$CvsModule', stopped");
157 my $dir = &svnDir
($svnTag);
159 &systemf
('svn list %s/%s > /dev/null', $SvnModule, $svnTag) == 0
160 && &systemf
('svn -q export %s/%s %s', $SvnModule, $svnTag, $dir) == 0;
161 die("cannot export $svnTag of svn module '$SvnModule', stopped")
162 unless $cvsOk && -d
$dir;
166 my ($category, $tag) = @_;
168 my $dir = sprintf('%s_%s', $category, $tag);
169 # remove dangerous chars
170 $dir =~ s/[^A-z0-9_\.\-]+/_/g;
175 return &tag2dir
('cvs', @_);
179 return &tag2dir
('svn', @_);
183 my ($fmt, @params) = @_;
185 my $cmd = sprintf($fmt, (@params));
186 #print(STDERR "$cmd\n");
191 return "usage: $0 <CVS module name> <Subversion URL>\n";