/[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

Annotation of /trunk/svn2cvs.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8 - (hide annotations)
Thu Mar 11 16:26:49 2004 UTC (20 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 5886 byte(s)
adding of dirs now work, cleanup

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

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.26