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

Diff of /trunk/svn2cvs.pl

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 17 by dpavlin, Thu Mar 18 12:29:15 2004 UTC revision 21 by dpavlin, Fri Jul 1 19:07:10 2005 UTC
# Line 13  Line 13 
13    
14  use strict;  use strict;
15  use File::Temp qw/ tempdir /;  use File::Temp qw/ tempdir /;
16    use File::Path;
17  use Data::Dumper;  use Data::Dumper;
18  use XML::Simple;  use XML::Simple;
19    
# Line 28  if ($SVNROOT !~ m,^[\w+]+:///*\w+,) { Line 29  if ($SVNROOT !~ m,^[\w+]+:///*\w+,) {
29          exit 1;          exit 1;
30  }  }
31    
32    # Ensure File::Temp::END can clean up:
33    $SIG{__DIE__} = sub { chdir("/tmp"); die @_ };
34    
35  my $TMPDIR=tempdir( "/tmp/checkoutXXXXX", CLEANUP => 1 );  my $TMPDIR=tempdir( "/tmp/checkoutXXXXX", CLEANUP => 1 );
36    
37  chdir($TMPDIR) || die "can't cd to $TMPDIR: $!";  chdir($TMPDIR) || die "can't cd to $TMPDIR: $!";
# Line 68  sub commit_svnrev { Line 72  sub commit_svnrev {
72          }          }
73  }  }
74    
75    # current revision in CVS
76    my $rev;
77    
78  # ok, now do the checkout  # ok, now do the checkout
79    eval {
80            log_system("$cvs -q checkout $CVSREP", "cvs checkout failed");
81    };
82    
83  log_system("$cvs -q checkout $CVSREP", "cvs checkout failed");  if ($@) {
84            print <<_NEW_REP_;
85    
86  chdir($CVSREP) || die "can't cd to $TMPDIR/$CVSREP: $!";  There is no CVS repository '$CVSREP' in your CVS. I will assume that
87    this is import of new module in your CVS and start from revision 0.
88    
89    Press enter to continue importing new CVS repository or CTRL+C to abort.
90    
91  my $rev;  _NEW_REP_
92    
93            print "start import of new module [yes]: ";
94            my $in = <STDIN>;
95            mkdir($CVSREP) || die "can't create $CVSREP: $!";
96    
97            chdir($CVSREP) || die "can't cd to $TMPDIR/$CVSREP: $!";
98    
99            open(SVNREV,"> .svnrev") || die "can't open $CVSREP/.svnrev: $!";
100            print SVNREV "0";
101            close(SVNREV);
102    
103            $rev = 0;
104    
105  # check if svnrev exists          # create new module
106  if (! -e ".svnrev") {          log_system("$cvs import -m 'new CVS module' $CVSREP svn2cvs r0", "can't import new module into $CVSREP");
107          print <<_USAGE_;  
108            unlink ".svnrev" || die "can't remove .svnrev: $!";
109            chdir($TMPDIR) || die "can't cd to $TMPDIR: $!";
110            rmdir $CVSREP || die "can't remove $CVSREP: $!";
111    
112            # and get new changes it
113            log_system("$cvs -q update -d $CVSREP", "cvs update -d failed");
114    
115            chdir($CVSREP) || die "can't cd to $TMPDIR/$CVSREP: $!";
116    
117    } else {
118    
119            # import into existing module directory in CVS
120    
121            chdir($CVSREP) || die "can't cd to $TMPDIR/$CVSREP: $!";
122    
123    
124            # check if svnrev exists
125            if (! -e ".svnrev") {
126                    print <<_USAGE_;
127    
128  Your CVS repository doesn't have .svnrev file!  Your CVS repository doesn't have .svnrev file!
129    
# Line 97  Subversion repository to CVS, correct re Line 141  Subversion repository to CVS, correct re
141    
142  _USAGE_  _USAGE_
143    
144          print "svn revision corresponding to CVS [abort]: ";                  print "svn revision corresponding to CVS [abort]: ";
145          my $in = <STDIN>;                  my $in = <STDIN>;
146          chomp($in);                  chomp($in);
147          if ($in !~ /^\d+$/) {                  if ($in !~ /^\d+$/) {
148                  print "Aborting: revision not a number\n";                          print "Aborting: revision not a number\n";
149                  exit 1;                          exit 1;
150                    } else {
151                            $rev = $in;
152                            commit_svnrev($rev,1);  # create new
153                    }
154          } else {          } else {
155                  $rev = $in;                  open(SVNREV,".svnrev") || die "can't open $TMPDIR/$CVSREP/.svnrev: $!";
156                  commit_svnrev($rev,1);  # create new                  $rev = <SVNREV>;
157                    chomp($rev);
158                    close(SVNREV);
159          }          }
 } else {  
         open(SVNREV,".svnrev") || die "can't open $TMPDIR/$CVSREP/.svnrev: $!";  
         $rev = <SVNREV>;  
         chomp($rev);  
         close(SVNREV);  
 }  
160    
161  print "Starting after revision $rev\n";          print "Starting after revision $rev\n";
162  $rev++;          $rev++;
163    }
164    
165    
166  #  #
# Line 132  while(<LOG>) { Line 177  while(<LOG>) {
177  }  }
178  close(LOG);  close(LOG);
179    
180  my $xml = XMLin($log, ForceArray => [ 'logentry', 'path' ]);  
181    my $xml;
182    eval {
183            $xml = XMLin($log, ForceArray => [ 'logentry', 'path' ]);
184    };
185    
186    
187  #=begin log_example  #=begin log_example
# Line 161  sub in_entries($) { Line 210  sub in_entries($) {
210                  if ($d !~ m,/$, && $d ne "") {                  if ($d !~ m,/$, && $d ne "") {
211                          $d .= "/";                          $d .= "/";
212                  }                  }
213                  open(E, $d."CVS/Entries") || die "can't open ${d}CVS/Entries: $!";                  open(E, $d."CVS/Entries") || return 0;
214                  while(<E>) {                  while(<E>) {
215                          return(1) if (m,^/$f/,);                          return(1) if (m,^/$f/,);
216                  }                  }
# Line 170  sub in_entries($) { Line 219  sub in_entries($) {
219          }          }
220  }  }
221    
222    chdir("$TMPDIR/$CVSREP") || die "can't cd to $TMPDIR/$CVSREP: $!";
223    
224  foreach my $e (@{$xml->{'logentry'}}) {  foreach my $e (@{$xml->{'logentry'}}) {
225          die "BUG: revision from .svnrev ($rev) greater than from subversion (".$e->{'revision'}.")" if ($rev > $e->{'revision'});          die "BUG: revision from .svnrev ($rev) greater than from subversion (".$e->{'revision'}.")" if ($rev > $e->{'revision'});
226          $rev = $e->{'revision'};          $rev = $e->{'revision'};
# Line 180  foreach my $e (@{$xml->{'logentry'}}) { Line 231  foreach my $e (@{$xml->{'logentry'}}) {
231          my $tmpsvn = $SVNROOT || die "BUG: SVNROOT empty!";          my $tmpsvn = $SVNROOT || die "BUG: SVNROOT empty!";
232          my $tmppath = $e->{'paths'}->{'path'}->[0]->{'content'} || die "BUG: tmppath empty!";          my $tmppath = $e->{'paths'}->{'path'}->[0]->{'content'} || die "BUG: tmppath empty!";
233          do {          do {
234                  if ($tmpsvn =~ s,(/\w+/*)$,,) {                  if ($tmpsvn =~ s#(/[^/]+)/*$##) {
235                          $SVNREP .= $1;                          $SVNREP = $1 . $SVNREP;
236                  } else {                  } else {
237                          print "NOTICE: can't deduce svn dir from $SVNROOT - skipping\n";                          print "NOTICE: can't deduce svn dir from $SVNROOT - skipping\n";
238                          next;                          next;
# Line 191  foreach my $e (@{$xml->{'logentry'}}) { Line 242  foreach my $e (@{$xml->{'logentry'}}) {
242          print "NOTICE: using $SVNREP as directory for svn\n";          print "NOTICE: using $SVNREP as directory for svn\n";
243    
244          printf($fmt, $e->{'revision'}, $e->{'author'}, $e->{'date'}, $e->{'msg'});          printf($fmt, $e->{'revision'}, $e->{'author'}, $e->{'date'}, $e->{'msg'});
245            my @commit;
246    
247          foreach my $p (@{$e->{'paths'}->{'path'}}) {          foreach my $p (@{$e->{'paths'}->{'path'}}) {
248                  my ($action,$path) = ($p->{'action'},$p->{'content'});                  my ($action,$path) = ($p->{'action'},$p->{'content'});
249    
# Line 198  foreach my $e (@{$xml->{'logentry'}}) { Line 251  foreach my $e (@{$xml->{'logentry'}}) {
251    
252                  # prepare path and message                  # prepare path and message
253                  my $file = $path;                  my $file = $path;
254                  $path =~ s,^$SVNREP/*,, || die "BUG: can't strip SVNREP from path";                  $path =~ s,^$SVNREP/*,, || die "BUG: can't strip SVNREP '$SVNREP' from path";
255    
256                  if (! $path) {                  if (! $path) {
257                          print "NOTICE: skipped this operation. Probably trunk creation\n";                          print "NOTICE: skipped this operation. Probably trunk creation\n";
# Line 215  foreach my $e (@{$xml->{'logentry'}}) { Line 268  foreach my $e (@{$xml->{'logentry'}}) {
268                                  chdir($path) || die "can't cd into dir $path for import: $!";                                  chdir($path) || die "can't cd into dir $path for import: $!";
269                                  log_system("$cvs import -d -m '$msg' $CVSREP/$path svn r$rev", "cvs import of $path failed");                                  log_system("$cvs import -d -m '$msg' $CVSREP/$path svn r$rev", "cvs import of $path failed");
270                                  chdir("$TMPDIR") || die "can't cd to $TMPDIR/$CVSREP: $!";                                  chdir("$TMPDIR") || die "can't cd to $TMPDIR/$CVSREP: $!";
271                                  log_system("$cvs checkout $CVSREP/$path", "cvs checkout of imported dir $path failed");                                  if (-d "$CVSREP/$path") {
272                                            rmtree "$CVSREP/$path" || die "can't remove $CVSREP/$path: $!";
273                                    } else {
274                                            unlink "$CVSREP/$path" || die "can't remove $CVSREP/$path: $!";
275                                    }
276                                    log_system("$cvs update -d $CVSREP", "cvs update -d of imported dir $path failed");
277                                  chdir("$TMPDIR/$CVSREP") || die "can't cd back to $TMPDIR/$CVSREP: $!";                                  chdir("$TMPDIR/$CVSREP") || die "can't cd back to $TMPDIR/$CVSREP: $!";
278                          } elsif ($path =~ m,^(.+)/[^/]+$, && ! -e "$1/CVS/Root") {                          } elsif ($path =~ m,^(.+)/[^/]+$, && ! -e "$1/CVS/Root") {
279                                  my $dir = $1;                                  my $dir = $1;
# Line 231  foreach my $e (@{$xml->{'logentry'}}) { Line 289  foreach my $e (@{$xml->{'logentry'}}) {
289                          print "WARNING: action $action not implemented on $path. Bug or missing feature of $0\n";                          print "WARNING: action $action not implemented on $path. Bug or missing feature of $0\n";
290                  }                  }
291    
292                  # now commit changes                  # save commits for later
293                  log_system("$cvs commit -m '$msg' $path", "cvs commit of $path failed");                  push @commit, $path;
294    
295          }          }
296    
297            my $msg = $e->{'msg'};
298            $msg =~ s/'/'\\''/g;    # quote "
299    
300            # now commit changes
301            log_system("$cvs commit -m '$msg' ".join(" ",@commit), "cvs commit of ".join(",",@commit)." failed");
302    
303          commit_svnrev($rev);          commit_svnrev($rev);
304  }  }
305    
306    # cd out of $CVSREP before File::Temp::END is called
307    chdir("/tmp") || die "can't cd to /tmp: $!";
308    
309  __END__  __END__
310    
311  =pod  =pod
# Line 258  Usage example (used to self-host this sc Line 325  Usage example (used to self-host this sc
325    
326  =head1 DESCRIPTION  =head1 DESCRIPTION
327    
328  This script will allow you to commit changes made to Subversion repository also to (read-only) CVS repository manually or from Subversion's C<post-commit> hook.  This script will allows you to commit changes made to Subversion repository to
329    (read-only) CVS repository manually or from Subversion's C<post-commit> hook.
330    
331  It's using F<.svnrev> file (which will be created on first run) in  It's using F<.svnrev> file (which will be created on first run) in
332  B<CVSROOT/CVSREPOSITORY> to store last Subversion revision which was  B<CVSROOT/CVSREPOSITORY> to store last Subversion revision which was
# Line 310  again. Line 378  again.
378  "Cheap" copy operations in Subversion are not at all cheap in CVS. They will  "Cheap" copy operations in Subversion are not at all cheap in CVS. They will
379  create multiple copies of files in CVS repository!  create multiple copies of files in CVS repository!
380    
381    This script assume that you want to sync your C<trunk> (or any other
382    directory for that matter) directory with CVS, not root of your subversion.
383    This might be considered bug, but since common practise is to have
384    directories C<trunk> and C<branches> in svn and source code in them, it's
385    not serious limitation.
386    
387  =head1 RELATED PROJECTS  =head1 RELATED PROJECTS
388    
389  B<Subversion> L<http://subversion.tigris.org/> version control system that is a  B<Subversion> L<http://subversion.tigris.org/> version control system that is a
# Line 336  Addition of comprehensive documentation, Line 410  Addition of comprehensive documentation,
410  messages, and support for skipping changes which are not under current  messages, and support for skipping changes which are not under current
411  Subversion checkout root (e.g. branches).  Subversion checkout root (e.g. branches).
412    
413    =item r18
414    
415    Support for importing your svn into empty CVS repository (it will first
416    create module and than dump all revisions).
417    Group commit operations to save round-trips to CVS server.
418    Documentation improvements and other small fixes.
419    
420    =item r20
421    
422    Fixed path deduction (overlap between Subversion reporistory and CVS checkout).
423    
424    =item r21
425    
426    Use C<update -d> instead of checkout after import.
427    Added fixes by Paul Egan <paulegan@mail.com> for XMLin and fixing working
428    directory.
429    
430    
431  =back  =back
432    
433  =head1 AUTHOR  =head1 AUTHOR

Legend:
Removed from v.17  
changed lines
  Added in v.21

  ViewVC Help
Powered by ViewVC 1.1.26