1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
|
#!/usr/bin/perl -w
#
# (C) 2005 The Measurement Factory http://www.measurement-factory.com/
# This software is distributed under Apache License, version 2.0.
#
# The cvsVsvn.pl script compares CVS and Subversion projects. The
# user is notified if project files maintained by CVS differ from
# those maintained by Subversion:
#
# $ CVSROOT=/my/cvsrepo ./cvsVsvn project1 svn+ssh://host/path/projects/p1
# collecting CVS tags...
# found 34 CVS tags
# comparing tagged snapshots...
# HEAD snapshots appear to be the same
# ...
# CVS and SVN repositories differ because cvs_foo and svn_tags_foo
# export directories differ in cvsVsvn.tmp
#
# The comparison is done for every CVS tag and branch (including
# HEAD), by exporting corresponding CVS and Subversion snapshots and
# running 'diff' against the two resulting directories. One can edit
# the script or use the environment variable DIFF_OPTIONS to alter
# 'diff' behavior (e.g., ignore differences in some files).
# Commit logs are not compared, unfortunately. This script is also
# confused by files that differ due to different keyword expansion by
# CVS and SVN.
use strict;
# cvsVsvn exports a user-specified module from CVS and Subversion
# repositories and compares the two exported directories using the
# 'diff' tool. The procedure is performed for all CVS tags (including
# HEAD and branches).
die(&usage()) unless @ARGV == 2;
my ($CvsModule, $SvnModule) = @ARGV;
my $TmpDir = 'cvsVsvn.tmp'; # directory to store temporary files
my @Tags = &collectTags();
print(STDERR "comparing tagged snapshots...\n");
foreach my $tagPair (@Tags) {
&compareTags($tagPair->{cvs}, $tagPair->{svn});
}
print(STDERR "CVS and Subversion repositories appear to be the same\n");
exit(0);
sub collectTags {
print(STDERR "collecting CVS tags...\n");
my @tags = (
{
cvs => 'HEAD',
svn => 'trunk'
}
);
# get CVS log headers with symbolic tags
my %names = ();
my $inNames;
my $cmd = sprintf('cvs rlog -h %s', $CvsModule);
open(IF, "$cmd|") or die("cannot execute $cmd: $!, stopped");
while (<IF>) {
if ($inNames) {
my ($name, $version) = /\s+(\S+):\s*(\d\S*)/;
if ($inNames = defined $version) {
my @nums = split(/\./, $version);
my $isBranch =
(2*int(@nums/2) != @nums) ||
(@nums > 2 && $nums[$#nums-1] == 0);
my $status = $isBranch ? 'branches' : 'tags';
my $oldStatus = $names{$name};
next if $oldStatus && $oldStatus eq $status;
die("change in $name tag status, stopped") if $oldStatus;
$names{$name} = $status;
}
} else {
$inNames = /^symbolic names:/;
}
}
close(IF);
while (my ($name, $status) = each %names) {
my $tagPair = {
cvs => $name,
svn => sprintf('%s/%s', $status, $name)
};
push (@tags, $tagPair);
}
printf(STDERR "found %d CVS tags\n", scalar @tags);
return @tags;
}
sub compareTags {
my ($cvsTag, $svnTag) = @_;
&prepDirs();
&cvsExport($cvsTag);
&svnExport($svnTag);
&diffDir($cvsTag, $svnTag);
# identical directories, clean up
&cleanDirs();
}
sub diffDir {
my ($cvsTag, $svnTag) = @_;
my $cvsDir = &cvsDir($cvsTag);
my $svnDir = &svnDir($svnTag);
my $same = systemf('diff --brief -b -B -r "%s" "%s"',
$cvsDir, $svnDir) == 0;
die("CVS and SVN repositories differ because ".
"$cvsDir and $svnDir export directories differ in $TmpDir; stopped")
unless $same;
print(STDERR "$cvsTag snapshots appear to be the same\n");
return 0;
}
sub makeDir {
my $dir = shift;
&systemf('mkdir %s', $dir) == 0 or die("cannot create $dir: $!, stopped");
}
sub prepDirs {
&makeDir($TmpDir);
chdir($TmpDir) or die($!);
}
sub cleanDirs {
chdir('..') or die($!);
&systemf('rm -irf %s', $TmpDir) == 0
or die("cannot delete $TmpDir: $!, stopped");
}
sub cvsExport {
my ($cvsTag) = @_;
my $dir = &cvsDir($cvsTag);
&makeDir($dir);
&systemf('cvs -Q export -r %s -d %s %s', $cvsTag, $dir, $CvsModule) == 0
or die("cannot export $cvsTag of CVS module '$CvsModule', stopped");
}
sub svnExport {
my ($svnTag) = @_;
my $dir = &svnDir($svnTag);
my $cvsOk =
&systemf('svn list %s/%s > /dev/null', $SvnModule, $svnTag) == 0
&& &systemf('svn -q export %s/%s %s', $SvnModule, $svnTag, $dir) == 0;
die("cannot export $svnTag of svn module '$SvnModule', stopped")
unless $cvsOk && -d $dir;
}
sub tag2dir {
my ($category, $tag) = @_;
my $dir = sprintf('%s_%s', $category, $tag);
# remove dangerous chars
$dir =~ s/[^A-z0-9_\.\-]+/_/g;
return $dir;
}
sub cvsDir {
return &tag2dir('cvs', @_);
}
sub svnDir {
return &tag2dir('svn', @_);
}
sub systemf {
my ($fmt, @params) = @_;
my $cmd = sprintf($fmt, (@params));
#print(STDERR "$cmd\n");
return system($cmd);
}
sub usage {
return "usage: $0 <CVS module name> <Subversion URL>\n";
}
|