/[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 4 - (hide 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 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     my $CVSROOT="$HOME/x/cvsroot";
22     # name of cvs repository to commit to
23 dpavlin 3 my $CVSREP="svn2cvs";
24 dpavlin 1
25     # svnroot directory
26 dpavlin 3 my $SVNROOT="file://$HOME/private/svn/svn2cvs";
27 dpavlin 1 # name of respository
28     my $SVNREP="trunk";
29    
30 dpavlin 3 # webpac example
31     #$CVSROOT="$HOME/x/cvsroot";
32     #$CVSREP="webpac";
33     #$SVNROOT="file://$HOME/private/svn/webpac/";
34     #$SVNREP="trunk";
35    
36 dpavlin 1 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 dpavlin 3
44 dpavlin 1 #
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 dpavlin 3 #
54     # sub to commit .svn rev file later
55     #
56     sub commit_svnrev {
57     my $rev = shift @_;
58     my $add_new = shift @_;
59 dpavlin 1
60 dpavlin 3 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 dpavlin 4 } 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 dpavlin 3 }
75     }
76    
77    
78 dpavlin 1 # ok, now do the checkout
79    
80 dpavlin 3 log_system("$cvs -q checkout $CVSREP","cvs checkout failed");
81 dpavlin 1
82 dpavlin 3 my $rev;
83    
84 dpavlin 1 # check if svnrev exists
85     if (! -e "$CVSREP/.svnrev") {
86     print <<_USAGE_;
87    
88 dpavlin 3 Your CVS repository doesn't have .svnrev file!
89 dpavlin 1
90 dpavlin 3 This file is used to keep CVS repository and SubVersion in sync, so
91     that only newer changes will be commited.
92 dpavlin 1
93 dpavlin 3 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 dpavlin 1
98 dpavlin 3 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 dpavlin 1
102     _USAGE_
103 dpavlin 3
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 dpavlin 1 }
120    
121     print "Starting after revision $rev\n";
122 dpavlin 2 $rev++;
123 dpavlin 1
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 dpavlin 2 my $xml = XMLin($log, ForceArray => [ 'logentry', 'path' ]);
140 dpavlin 1
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 dpavlin 2 if (! $xml->{'logentry'}) {
154     print "no newer log entries in SubVersion repostory. CVS is current\n";
155     exit 0;
156     }
157    
158 dpavlin 1 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