/[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 5 - (hide annotations)
Tue Mar 9 22:04:14 2004 UTC (20 years ago) by dpavlin
File MIME type: text/plain
File size: 5436 byte(s)
self-hosting

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

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.26