/[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 7 - (hide annotations)
Tue Mar 9 22:35:55 2004 UTC (20 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 5556 byte(s)
work in relative directory to checkouted CVS repository, skip trunk
creation (which resulted in additional commit on .svnrev file, making
revision of .svnrev and svn repository out of sync)

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

Properties

Name Value
svn:executable

  ViewVC Help
Powered by ViewVC 1.1.26