/[svn2cvs]/trunk/svn2cvs.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/svn2cvs.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Tue Mar 9 21:54:36 2004 UTC (20 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 5379 byte(s)
.svnrev revision number in CVS will correspond to
revision number in SubVersion if you start from
clean CVS repository and invoke this from post-commit
hook. Nice :-)

1 #!/usr/bin/perl -w
2
3 # This script will transfer changes from Subversion repository
4 # to CVS repository (e.g. SourceForge) while preserving commit
5 # logs.
6 #
7 # Based on original shell version by Tollef Fog Heen available at
8 # http://raw.no/personal/blog
9 #
10 # 2004-03-09 Dobrica Pavlinusic <dpavlin@rot13.org>
11
12 use strict;
13 use File::Temp qw/ tempdir /;
14 use Data::Dumper;
15 use XML::Simple;
16
17 # get current user home directory
18 my $HOME = $ENV{'HOME'} || die "can't get home directory!";
19
20 # cvsroot directory
21 my $CVSROOT="$HOME/x/cvsroot";
22 # name of cvs repository to commit to
23 my $CVSREP="svn2cvs";
24
25 # svnroot directory
26 my $SVNROOT="file://$HOME/private/svn/svn2cvs";
27 # name of respository
28 my $SVNREP="trunk";
29
30 # webpac example
31 #$CVSROOT="$HOME/x/cvsroot";
32 #$CVSREP="webpac";
33 #$SVNROOT="file://$HOME/private/svn/webpac/";
34 #$SVNREP="trunk";
35
36 my $TMPDIR=tempdir( "/tmp/checkoutXXXXX", CLEANUP => 1 );
37
38 chdir($TMPDIR) || die "can't cd to $TMPDIR: $!";
39
40 # cvs command with root
41 my $cvs="cvs -d $CVSROOT";
42
43
44 #
45 # sub to do logging and system calls
46 #
47 sub log_system($$) {
48 my ($cmd,$errmsg) = @_;
49 print STDERR "## $cmd\n";
50 system $cmd || die "$errmsg: $!";
51 }
52
53 #
54 # sub to commit .svn rev file later
55 #
56 sub commit_svnrev {
57 my $rev = shift @_;
58 my $add_new = shift @_;
59
60 die "commit_svnrev needs revision" if (! defined($rev));
61
62 open(SVNREV,"> $CVSREP/.svnrev") || die "can't open $TMPDIR/$CVSREP/.svnrev: $!";
63 print SVNREV $rev;
64 close(SVNREV);
65
66 my $path=".svnrev";
67
68 if ($add_new) {
69 system "$cvs add $CVSREP/$path" || die "cvs add of $path failed: $!";
70 } else {
71 my $msg="subversion revision $rev commited to CVS";
72 print "$msg\n";
73 system "$cvs commit -m \"$msg\" $CVSREP/$path" || die "cvs commit of $path failed: $!";
74 }
75 }
76
77
78 # ok, now do the checkout
79
80 log_system("$cvs -q checkout $CVSREP","cvs checkout failed");
81
82 my $rev;
83
84 # check if svnrev exists
85 if (! -e "$CVSREP/.svnrev") {
86 print <<_USAGE_;
87
88 Your CVS repository doesn't have .svnrev file!
89
90 This file is used to keep CVS repository and SubVersion in sync, so
91 that only newer changes will be commited.
92
93 It's quote possible that this is first svn2cvs run for this repository.
94 If so, you will have to identify correct svn revision which
95 corresponds to current version of CVS repository that has just
96 been checkouted.
97
98 If you migrated your cvs repository to svn using cvs2svn, this will be
99 last SubVersion revision. If this is initial run of conversion of
100 SubVersion repository to CVS, correct revision is 0.
101
102 _USAGE_
103
104 print "svn revision corresponding to CVS [abort]: ";
105 my $in = <STDIN>;
106 chomp($in);
107 if ($in !~ /^\d+$/) {
108 print "Aborting: revision not a number\n";
109 exit 1;
110 } else {
111 $rev = $in;
112 commit_svnrev($rev,1); # create new
113 }
114 } else {
115 open(SVNREV,"$CVSREP/.svnrev") || die "can't open $TMPDIR/$CVSREP/.svnrev: $!";
116 my $rev = <SVNREV>;
117 chomp($rev);
118 close(SVNREV);
119 }
120
121 print "Starting after revision $rev\n";
122 $rev++;
123
124
125 #
126 # FIXME!! HEAD should really be next verison and loop because this way we
127 # loose multiple edits of same file and corresponding messages. On the
128 # other hand, if you want to compress your traffic to CVS server and don't
129 # case much about accuracy and completnes of logs there, this might
130 # be good. YMMV
131 #
132 open(LOG, "svn log -r $rev:HEAD -v --xml $SVNROOT/$SVNREP |") || die "svn log for repository $SVNROOT/$SVNREP failed: $!";
133 my $log;
134 while(<LOG>) {
135 $log .= $_;
136 }
137 close(LOG);
138
139 my $xml = XMLin($log, ForceArray => [ 'logentry', 'path' ]);
140
141
142 =begin log_example
143
144 ------------------------------------------------------------------------
145 r256 | dpavlin | 2004-03-09 13:18:17 +0100 (Tue, 09 Mar 2004) | 2 lines
146
147 ported r254 from hidra branch
148
149 =cut
150
151 my $fmt = "\n" . "-" x 79 . "\nr%5s| %8s | %s\n\n%s\n";
152
153 if (! $xml->{'logentry'}) {
154 print "no newer log entries in SubVersion repostory. CVS is current\n";
155 exit 0;
156 }
157
158 foreach my $e (@{$xml->{'logentry'}}) {
159 die "BUG: revision from .svnrev ($rev) greater than from subversion (".$e->{'revision'}.")" if ($rev > $e->{'revision'});
160 $rev = $e->{'revision'};
161 log_system("svn export --force -q -r $rev $SVNROOT/$SVNREP $CVSREP", "svn export of revision $rev failed");
162
163 printf($fmt, $e->{'revision'}, $e->{'author'}, $e->{'date'}, $e->{'msg'});
164 foreach my $p (@{$e->{'paths'}->{'path'}}) {
165 my ($action,$path) = ($p->{'action'},$p->{'content'});
166
167 print "svn2cvs: $action $path\n";
168
169 # prepare path and message
170 my $file = $path;
171 $path =~ s,^/$SVNREP/*,, || die "BUG: can't strip SVNREP from path";
172 my $msg = $e->{'msg'};
173 $msg =~ s/"/\\"/g; # quote "
174
175 if ($action =~ /M/) {
176 print "svn2cvs: modify $path -- nop\n";
177 } elsif ($action =~ /A/) {
178 log_system("$cvs add -m \"$msg\" $CVSREP/$path", "cvs add of $path failed");
179 } elsif ($action =~ /D/) {
180 log_system("$cvs delete -m \"$msg\" $CVSREP/$path", "cvs delete of $path failed");
181 } else {
182 print "WARNING: action $action not implemented on $path. Bug or missing feature of $0\n";
183 }
184
185 # now commit changes
186 log_system("$cvs commit -m \"$msg\" $CVSREP/$path", "cvs commit of $path failed");
187
188 }
189
190 commit_svnrev($rev);
191 }
192
193 __END__
194
195 svn export --force "$SVNROOT/$SVNREP" "$CVSREP"
196
197 cd dotfiles
198
199 for file in $(find -type f -not -path \*CVS\*); do
200 FILE=$(basename $file)
201 DIR=$(dirname $file)
202 if ! grep -q "^/$FILE/" $DIR/CVS/Entries ; then
203 cvs add $file
204 fi
205 done
206
207 #cvs commit -m "Automatic commit from SVN"
208
209 #rm -rf $TMPDIR
210
211 echo "cvs left in $TMPDIR"

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.26