/[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 14 by dpavlin, Sun Mar 14 21:49:36 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            # create new module
106            log_system("$cvs import -m 'new CVS module' $CVSREP svn2cvs r0", "can't import new module into $CVSREP");
107    
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  # check if svnrev exists          chdir($CVSREP) || die "can't cd to $TMPDIR/$CVSREP: $!";
116  if (! -e ".svnrev") {  
117          print <<_USAGE_;  } 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 158  sub in_entries($) { Line 207  sub in_entries($) {
207                  die "can't split '$path' to dir and file!";                  die "can't split '$path' to dir and file!";
208          } else {          } else {
209                  my ($d,$f) = ($1,$2);                  my ($d,$f) = ($1,$2);
210                  if ($d !~ m,/$,) {                  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  print "## tmppath: $tmppath tmpsvn: $tmpsvn SVNREP: $SVNREP\n";                  if ($tmpsvn =~ s#(/[^/]+)/*$##) {
235                  if ($tmpsvn =~ s,(/\w+/*)$,,) {                          $SVNREP = $1 . $SVNREP;
                         $SVNREP .= $1;  
236                  } else {                  } else {
237                          die "ERROR: can't deduce svn dir from $SVNROOT.\nUsing root of snv repository for current version instead of /trunk/ is not supported.\n";                          print "NOTICE: can't deduce svn dir from $SVNROOT - skipping\n";
238                            next;
239                  }                  }
240          } until ($tmppath =~ m/^$SVNREP/);          } until ($tmppath =~ m/^$SVNREP/);
241    
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  print "## tmppath: $tmppath tmpsvn: $tmp Line 251  print "## tmppath: $tmppath tmpsvn: $tmp
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  print "## tmppath: $tmppath tmpsvn: $tmp Line 268  print "## tmppath: $tmppath tmpsvn: $tmp
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  print "## tmppath: $tmppath tmpsvn: $tmp Line 289  print "## tmppath: $tmppath tmpsvn: $tmp
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 319  B<cvs2svn> L<http://cvs2svn.tigris.org/> Line 393  B<cvs2svn> L<http://cvs2svn.tigris.org/>
393  Subversion repository. It is designed for one-time conversions, not for  Subversion repository. It is designed for one-time conversions, not for
394  repeated synchronizations between CVS and Subversion.  repeated synchronizations between CVS and Subversion.
395    
396    =head1 CHANGES
397    
398    Versions of this utility are actually Subversion repository revisions,
399    so they might not be in sequence.
400    
401    =over 3
402    
403    =item r10
404    
405    First release available to public
406    
407    =item r15
408    
409    Addition of comprehensive documentation, fixes for quoting in commit
410    messages, and support for skipping changes which are not under current
411    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
432    
433  =head1 AUTHOR  =head1 AUTHOR
434    
435  Dobrica Pavlinusic <dpavlin@rot13.org>  Dobrica Pavlinusic <dpavlin@rot13.org>

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

  ViewVC Help
Powered by ViewVC 1.1.26