]> git.ipfire.org Git - thirdparty/git.git/blame - git-cvsimport.perl
Merge branch 'maint'
[thirdparty/git.git] / git-cvsimport.perl
CommitLineData
3328aced 1#!/usr/bin/perl
9718a00b 2
a57a9493
MU
3# This tool is copyright (c) 2005, Matthias Urlichs.
4# It is released under the Gnu Public License, version 2.
5#
6# The basic idea is to aggregate CVS check-ins into related changes.
7# Fortunately, "cvsps" does that for us; all we have to do is to parse
8# its output.
9#
10# Checking out the files is done by a single long-running CVS connection
11# / server process.
12#
13# The head revision is on branch "origin" by default.
14# You can change that with the '-o' option.
15
d48b2841 16use 5.008;
a57a9493
MU
17use strict;
18use warnings;
bc434e82 19use Getopt::Long;
79ee456c 20use File::Spec;
7ccd9009 21use File::Temp qw(tempfile tmpnam);
a57a9493
MU
22use File::Path qw(mkpath);
23use File::Basename qw(basename dirname);
24use Time::Local;
2a3e1a85
MU
25use IO::Socket;
26use IO::Pipe;
e49289df 27use POSIX qw(strftime dup2 ENOENT);
0d821d4d 28use IPC::Open2;
a57a9493
MU
29
30$SIG{'PIPE'}="IGNORE";
31$ENV{'TZ'}="UTC";
32
0455ec03 33our ($opt_h,$opt_o,$opt_v,$opt_k,$opt_u,$opt_d,$opt_p,$opt_C,$opt_z,$opt_i,$opt_P, $opt_s,$opt_m,@opt_M,$opt_A,$opt_S,$opt_L, $opt_a, $opt_r, $opt_R);
ffd97f3a 34my (%conv_author_name, %conv_author_email);
a57a9493 35
7bf77644
FL
36sub usage(;$) {
37 my $msg = shift;
38 print(STDERR "Error: $msg\n") if $msg;
a57a9493 39 print STDERR <<END;
1b1dd23f 40Usage: git cvsimport # fetch/update GIT from CVS
ffd97f3a 41 [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
edbe4466
FL
42 [-p opts-for-cvsps] [-P file] [-C GIT_repository] [-z fuzz] [-i] [-k]
43 [-u] [-s subst] [-a] [-m] [-M regex] [-S regex] [-L commitlimit]
0455ec03 44 [-r remote] [-R] [CVS_module]
a57a9493
MU
45END
46 exit(1);
47}
48
ffd97f3a
AE
49sub read_author_info($) {
50 my ($file) = @_;
51 my $user;
52 open my $f, '<', "$file" or die("Failed to open $file: $!\n");
53
54 while (<$f>) {
8cd16211 55 # Expected format is this:
ffd97f3a 56 # exon=Andreas Ericsson <ae@op5.se>
8cd16211 57 if (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/) {
ffd97f3a 58 $user = $1;
8cd16211
JH
59 $conv_author_name{$user} = $2;
60 $conv_author_email{$user} = $3;
ffd97f3a 61 }
8cd16211
JH
62 # However, we also read from CVSROOT/users format
63 # to ease migration.
64 elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) {
65 my $mapped;
66 ($user, $mapped) = ($1, $3);
67 if ($mapped =~ /^\s*(.*?)\s*<(.*)>\s*$/) {
68 $conv_author_name{$user} = $1;
69 $conv_author_email{$user} = $2;
70 }
71 elsif ($mapped =~ /^<?(.*)>?$/) {
72 $conv_author_name{$user} = $user;
73 $conv_author_email{$user} = $1;
74 }
75 }
76 # NEEDSWORK: Maybe warn on unrecognized lines?
ffd97f3a
AE
77 }
78 close ($f);
79}
80
81sub write_author_info($) {
82 my ($file) = @_;
83 open my $f, '>', $file or
84 die("Failed to open $file for writing: $!");
85
86 foreach (keys %conv_author_name) {
8cd16211 87 print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n";
ffd97f3a
AE
88 }
89 close ($f);
90}
91
cfc44a12 92# convert getopts specs for use by git config
60d5985d
MG
93my %longmap = (
94 'A:' => 'authors-file',
95 'M:' => 'merge-regex',
96 'P:' => undef,
97 'R' => 'track-revisions',
98 'S:' => 'ignore-paths',
99);
100
ed35dece 101sub read_repo_config {
549ad6d2
MG
102 # Split the string between characters, unless there is a ':'
103 # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
ed35dece
JB
104 my @opts = split(/ *(?!:)/, shift);
105 foreach my $o (@opts) {
106 my $key = $o;
107 $key =~ s/://g;
cfc44a12 108 my $arg = 'git config';
ed35dece 109 $arg .= ' --bool' if ($o !~ /:$/);
60d5985d 110 my $ckey = $key;
ed35dece 111
60d5985d
MG
112 if (exists $longmap{$o}) {
113 # An uppercase option like -R cannot be
114 # expressed in the configuration, as the
115 # variable names are downcased.
116 $ckey = $longmap{$o};
117 next if (! defined $ckey);
118 $ckey =~ s/-//g;
119 }
120 chomp(my $tmp = `$arg --get cvsimport.$ckey`);
ed35dece 121 if ($tmp && !($arg =~ /--bool/ && $tmp eq 'false')) {
549ad6d2
MG
122 no strict 'refs';
123 my $opt_name = "opt_" . $key;
124 if (!$$opt_name) {
125 $$opt_name = $tmp;
126 }
ed35dece
JB
127 }
128 }
ed35dece
JB
129}
130
0455ec03 131my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:R";
ed35dece 132read_repo_config($opts);
bc434e82
PB
133Getopt::Long::Configure( 'no_ignore_case', 'bundling' );
134
135# turn the Getopt::Std specification in a Getopt::Long one,
136# with support for multiple -M options
137GetOptions( map { s/:/=s/; /M/ ? "$_\@" : $_ } split( /(?!:)/, $opts ) )
138 or usage();
a57a9493
MU
139usage if $opt_h;
140
67d23242 141if (@ARGV == 0) {
cfc44a12 142 chomp(my $module = `git config --get cvsimport.module`);
67d23242
JK
143 push(@ARGV, $module) if $? == 0;
144}
7bf77644 145@ARGV <= 1 or usage("You can't specify more than one CVS module");
a57a9493 146
86d11cf2 147if ($opt_d) {
2a3e1a85 148 $ENV{"CVSROOT"} = $opt_d;
86d11cf2 149} elsif (-f 'CVS/Root') {
f9714a4a
SV
150 open my $f, '<', 'CVS/Root' or die 'Failed to open CVS/Root';
151 $opt_d = <$f>;
152 chomp $opt_d;
153 close $f;
154 $ENV{"CVSROOT"} = $opt_d;
86d11cf2 155} elsif ($ENV{"CVSROOT"}) {
2a3e1a85
MU
156 $opt_d = $ENV{"CVSROOT"};
157} else {
7bf77644 158 usage("CVSROOT needs to be set");
2a3e1a85 159}
fbfd60d6 160$opt_s ||= "-";
ded9f400
ML
161$opt_a ||= 0;
162
f9714a4a 163my $git_tree = $opt_C;
2a3e1a85
MU
164$git_tree ||= ".";
165
8b7f5fc1
AW
166my $remote;
167if (defined $opt_r) {
168 $remote = 'refs/remotes/' . $opt_r;
169 $opt_o ||= "master";
170} else {
171 $opt_o ||= "origin";
172 $remote = 'refs/heads';
173}
174
f9714a4a
SV
175my $cvs_tree;
176if ($#ARGV == 0) {
177 $cvs_tree = $ARGV[0];
178} elsif (-f 'CVS/Repository') {
a6080a0a 179 open my $f, '<', 'CVS/Repository' or
f9714a4a
SV
180 die 'Failed to open CVS/Repository';
181 $cvs_tree = <$f>;
182 chomp $cvs_tree;
db4b6582 183 close $f;
f9714a4a 184} else {
7bf77644 185 usage("CVS module has to be specified");
f9714a4a
SV
186}
187
db4b6582
ML
188our @mergerx = ();
189if ($opt_m) {
fbbbc362 190 @mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i );
db4b6582 191}
bc434e82
PB
192if (@opt_M) {
193 push (@mergerx, map { qr/$_/ } @opt_M);
db4b6582
ML
194}
195
6211988f
ML
196# Remember UTC of our starting time
197# we'll want to avoid importing commits
198# that are too recent
199our $starttime = time();
200
a57a9493
MU
201select(STDERR); $|=1; select(STDOUT);
202
203
204package CVSconn;
205# Basic CVS dialog.
2a3e1a85 206# We're only interested in connecting and downloading, so ...
a57a9493 207
2eb6d82e
SV
208use File::Spec;
209use File::Temp qw(tempfile);
f65ae603
MU
210use POSIX qw(strftime dup2);
211
a57a9493 212sub new {
86d11cf2 213 my ($what,$repo,$subdir) = @_;
a57a9493
MU
214 $what=ref($what) if ref($what);
215
216 my $self = {};
217 $self->{'buffer'} = "";
218 bless($self,$what);
219
220 $repo =~ s#/+$##;
221 $self->{'fullrep'} = $repo;
222 $self->conn();
223
224 $self->{'subdir'} = $subdir;
225 $self->{'lines'} = undef;
226
227 return $self;
228}
229
58fdef0c
GR
230sub find_password_entry {
231 my ($cvspass, @cvsroot) = @_;
232 my ($file, $delim) = @$cvspass;
233 my $pass;
234 local ($_);
235
236 if (open(my $fh, $file)) {
237 # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z
238 CVSPASSFILE:
239 while (<$fh>) {
240 chomp;
241 s/^\/\d+\s+//;
242 my ($w, $p) = split($delim,$_,2);
243 for my $cvsroot (@cvsroot) {
244 if ($w eq $cvsroot) {
245 $pass = $p;
246 last CVSPASSFILE;
247 }
248 }
249 }
250 close($fh);
251 }
252 return $pass;
253}
254
a57a9493
MU
255sub conn {
256 my $self = shift;
257 my $repo = $self->{'fullrep'};
86d11cf2
JH
258 if ($repo =~ s/^:pserver(?:([^:]*)):(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) {
259 my ($param,$user,$pass,$serv,$port) = ($1,$2,$3,$4,$5);
73bcf533 260
86d11cf2
JH
261 my ($proxyhost,$proxyport);
262 if ($param && ($param =~ m/proxy=([^;]+)/)) {
73bcf533
IA
263 $proxyhost = $1;
264 # Default proxyport, if not specified, is 8080.
265 $proxyport = 8080;
86d11cf2 266 if ($ENV{"CVS_PROXY_PORT"}) {
73bcf533
IA
267 $proxyport = $ENV{"CVS_PROXY_PORT"};
268 }
86d11cf2 269 if ($param =~ m/proxyport=([^;]+)/) {
73bcf533
IA
270 $proxyport = $1;
271 }
272 }
8c372fb0 273 $repo ||= '/';
73bcf533 274
2e458e05
GH
275 # if username is not explicit in CVSROOT, then use current user, as cvs would
276 $user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
2a3e1a85 277 my $rr2 = "-";
86d11cf2 278 unless ($port) {
a57a9493
MU
279 $rr2 = ":pserver:$user\@$serv:$repo";
280 $port=2401;
281 }
282 my $rr = ":pserver:$user\@$serv:$port$repo";
283
3fb9d582
PO
284 if ($pass) {
285 $pass = $self->_scramble($pass);
286 } else {
58fdef0c
GR
287 my @cvspass = ([$ENV{'HOME'}."/.cvspass", qr/\s/],
288 [$ENV{'HOME'}."/.cvs/cvspass", qr/=/]);
289 my @loc = ();
290 foreach my $cvspass (@cvspass) {
291 my $p = find_password_entry($cvspass, $rr, $rr2);
292 if ($p) {
293 push @loc, $cvspass->[0];
294 $pass = $p;
a57a9493 295 }
58fdef0c
GR
296 }
297
298 if (1 < @loc) {
299 die("Multiple cvs password files have ".
300 "entries for CVSROOT $opt_d: @loc");
301 } elsif (!$pass) {
302 $pass = "A";
303 }
a57a9493 304 }
b2139dbd 305
73bcf533 306 my ($s, $rep);
86d11cf2 307 if ($proxyhost) {
73bcf533
IA
308
309 # Use a HTTP Proxy. Only works for HTTP proxies that
310 # don't require user authentication
311 #
312 # See: http://www.ietf.org/rfc/rfc2817.txt
313
314 $s = IO::Socket::INET->new(PeerHost => $proxyhost, PeerPort => $proxyport);
315 die "Socket to $proxyhost: $!\n" unless defined $s;
316 $s->write("CONNECT $serv:$port HTTP/1.1\r\nHost: $serv:$port\r\n\r\n")
317 or die "Write to $proxyhost: $!\n";
318 $s->flush();
319
320 $rep = <$s>;
321
322 # The answer should look like 'HTTP/1.x 2yy ....'
86d11cf2 323 if (!($rep =~ m#^HTTP/1\.. 2[0-9][0-9]#)) {
73bcf533
IA
324 die "Proxy connect: $rep\n";
325 }
326 # Skip up to the empty line of the proxy server output
327 # including the response headers.
328 while ($rep = <$s>) {
329 last if (!defined $rep ||
330 $rep eq "\n" ||
331 $rep eq "\r\n");
332 }
333 } else {
334 $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port);
335 die "Socket to $serv: $!\n" unless defined $s;
336 }
337
a57a9493
MU
338 $s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n")
339 or die "Write to $serv: $!\n";
340 $s->flush();
341
73bcf533 342 $rep = <$s>;
a57a9493 343
86d11cf2 344 if ($rep ne "I LOVE YOU\n") {
a57a9493
MU
345 $rep="<unknown>" unless $rep;
346 die "AuthReply: $rep\n";
347 }
348 $self->{'socketo'} = $s;
349 $self->{'socketi'} = $s;
34155390 350 } else { # local or ext: Fork off our own cvs server.
a57a9493
MU
351 my $pr = IO::Pipe->new();
352 my $pw = IO::Pipe->new();
353 my $pid = fork();
354 die "Fork: $!\n" unless defined $pid;
8d0ea311
SV
355 my $cvs = 'cvs';
356 $cvs = $ENV{CVS_SERVER} if exists $ENV{CVS_SERVER};
34155390
SV
357 my $rsh = 'rsh';
358 $rsh = $ENV{CVS_RSH} if exists $ENV{CVS_RSH};
359
360 my @cvs = ($cvs, 'server');
361 my ($local, $user, $host);
362 $local = $repo =~ s/:local://;
363 if (!$local) {
364 $repo =~ s/:ext://;
365 $local = !($repo =~ s/^(?:([^\@:]+)\@)?([^:]+)://);
366 ($user, $host) = ($1, $2);
367 }
368 if (!$local) {
369 if ($user) {
370 unshift @cvs, $rsh, '-l', $user, $host;
371 } else {
372 unshift @cvs, $rsh, $host;
373 }
374 }
375
86d11cf2 376 unless ($pid) {
a57a9493
MU
377 $pr->writer();
378 $pw->reader();
a57a9493
MU
379 dup2($pw->fileno(),0);
380 dup2($pr->fileno(),1);
381 $pr->close();
382 $pw->close();
34155390 383 exec(@cvs);
a57a9493
MU
384 }
385 $pw->writer();
386 $pr->reader();
387 $self->{'socketo'} = $pw;
388 $self->{'socketi'} = $pr;
389 }
390 $self->{'socketo'}->write("Root $repo\n");
391
392 # Trial and error says that this probably is the minimum set
b0921331 393 $self->{'socketo'}->write("Valid-responses ok error Valid-requests Mode M Mbinary E Checked-in Created Updated Merged Removed\n");
a57a9493
MU
394
395 $self->{'socketo'}->write("valid-requests\n");
396 $self->{'socketo'}->flush();
397
e7cad3cc
FK
398 my $rep=$self->readline();
399 die "Failed to read from server" unless defined $rep;
400 chomp($rep);
86d11cf2 401 if ($rep !~ s/^Valid-requests\s*//) {
a57a9493
MU
402 $rep="<unknown>" unless $rep;
403 die "Expected Valid-requests from server, but got: $rep\n";
404 }
405 chomp(my $res=$self->readline());
406 die "validReply: $res\n" if $res ne "ok";
407
408 $self->{'socketo'}->write("UseUnchanged\n") if $rep =~ /\bUseUnchanged\b/;
409 $self->{'repo'} = $repo;
410}
411
412sub readline {
86d11cf2 413 my ($self) = @_;
a57a9493
MU
414 return $self->{'socketi'}->getline();
415}
416
417sub _file {
418 # Request a file with a given revision.
419 # Trial and error says this is a good way to do it. :-/
86d11cf2 420 my ($self,$fn,$rev) = @_;
a57a9493
MU
421 $self->{'socketo'}->write("Argument -N\n") or return undef;
422 $self->{'socketo'}->write("Argument -P\n") or return undef;
abe05822
ML
423 # -kk: Linus' version doesn't use it - defaults to off
424 if ($opt_k) {
425 $self->{'socketo'}->write("Argument -kk\n") or return undef;
426 }
a57a9493
MU
427 $self->{'socketo'}->write("Argument -r\n") or return undef;
428 $self->{'socketo'}->write("Argument $rev\n") or return undef;
429 $self->{'socketo'}->write("Argument --\n") or return undef;
430 $self->{'socketo'}->write("Argument $self->{'subdir'}/$fn\n") or return undef;
431 $self->{'socketo'}->write("Directory .\n") or return undef;
432 $self->{'socketo'}->write("$self->{'repo'}\n") or return undef;
4f7c0caa 433 # $self->{'socketo'}->write("Sticky T1.0\n") or return undef;
a57a9493
MU
434 $self->{'socketo'}->write("co\n") or return undef;
435 $self->{'socketo'}->flush() or return undef;
436 $self->{'lines'} = 0;
437 return 1;
438}
439sub _line {
440 # Read a line from the server.
441 # ... except that 'line' may be an entire file. ;-)
86d11cf2 442 my ($self, $fh) = @_;
a57a9493
MU
443 die "Not in lines" unless defined $self->{'lines'};
444
445 my $line;
2eb6d82e 446 my $res=0;
86d11cf2 447 while (defined($line = $self->readline())) {
a57a9493
MU
448 # M U gnupg-cvs-rep/AUTHORS
449 # Updated gnupg-cvs-rep/
450 # /daten/src/rsync/gnupg-cvs-rep/AUTHORS
451 # /AUTHORS/1.1///T1.1
452 # u=rw,g=rw,o=rw
453 # 0
454 # ok
455
86d11cf2 456 if ($line =~ s/^(?:Created|Updated) //) {
a57a9493
MU
457 $line = $self->readline(); # path
458 $line = $self->readline(); # Entries line
459 my $mode = $self->readline(); chomp $mode;
460 $self->{'mode'} = $mode;
461 defined (my $cnt = $self->readline())
462 or die "EOF from server after 'Changed'\n";
463 chomp $cnt;
464 die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/;
465 $line="";
55cad842 466 $res = $self->_fetchfile($fh, $cnt);
86d11cf2 467 } elsif ($line =~ s/^ //) {
2eb6d82e
SV
468 print $fh $line;
469 $res += length($line);
86d11cf2 470 } elsif ($line =~ /^M\b/) {
a57a9493 471 # output, do nothing
86d11cf2 472 } elsif ($line =~ /^Mbinary\b/) {
a57a9493
MU
473 my $cnt;
474 die "EOF from server after 'Mbinary'" unless defined ($cnt = $self->readline());
475 chomp $cnt;
476 die "Duh: Mbinary $cnt" if $cnt !~ /^\d+$/ or $cnt<1;
477 $line="";
55cad842 478 $res += $self->_fetchfile($fh, $cnt);
a57a9493
MU
479 } else {
480 chomp $line;
86d11cf2 481 if ($line eq "ok") {
a57a9493
MU
482 # print STDERR "S: ok (".length($res).")\n";
483 return $res;
86d11cf2 484 } elsif ($line =~ s/^E //) {
a57a9493 485 # print STDERR "S: $line\n";
86d11cf2 486 } elsif ($line =~ /^(Remove-entry|Removed) /i) {
8b8840e0
MU
487 $line = $self->readline(); # filename
488 $line = $self->readline(); # OK
489 chomp $line;
490 die "Unknown: $line" if $line ne "ok";
491 return -1;
a57a9493
MU
492 } else {
493 die "Unknown: $line\n";
494 }
495 }
496 }
39ba7d54 497 return undef;
a57a9493
MU
498}
499sub file {
86d11cf2 500 my ($self,$fn,$rev) = @_;
a57a9493
MU
501 my $res;
502
a6080a0a 503 my ($fh, $name) = tempfile('gitcvs.XXXXXX',
2eb6d82e
SV
504 DIR => File::Spec->tmpdir(), UNLINK => 1);
505
506 $self->_file($fn,$rev) and $res = $self->_line($fh);
507
508 if (!defined $res) {
39ba7d54
MM
509 print STDERR "Server has gone away while fetching $fn $rev, retrying...\n";
510 truncate $fh, 0;
2eb6d82e 511 $self->conn();
39ba7d54 512 $self->_file($fn,$rev) or die "No file command send";
2eb6d82e 513 $res = $self->_line($fh);
39ba7d54 514 die "Retry failed" unless defined $res;
a57a9493 515 }
c619ad51 516 close ($fh);
a57a9493 517
2eb6d82e 518 return ($name, $res);
a57a9493 519}
55cad842
ML
520sub _fetchfile {
521 my ($self, $fh, $cnt) = @_;
61efa5e3 522 my $res = 0;
55cad842 523 my $bufsize = 1024 * 1024;
86d11cf2 524 while ($cnt) {
55cad842
ML
525 if ($bufsize > $cnt) {
526 $bufsize = $cnt;
527 }
528 my $buf;
529 my $num = $self->{'socketi'}->read($buf,$bufsize);
530 die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0;
531 print $fh $buf;
532 $res += $num;
533 $cnt -= $num;
534 }
535 return $res;
536}
a57a9493 537
b2139dbd
DH
538sub _scramble {
539 my ($self, $pass) = @_;
540 my $scrambled = "A";
541
542 return $scrambled unless $pass;
543
544 my $pass_len = length($pass);
545 my @pass_arr = split("", $pass);
546 my $i;
547
548 # from cvs/src/scramble.c
549 my @shifts = (
550 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
551 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
552 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
553 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
554 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
555 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
556 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
557 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
558 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
559 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
560 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
561 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
562 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
563 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
564 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
565 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152
566 );
567
568 for ($i = 0; $i < $pass_len; $i++) {
569 $scrambled .= pack("C", $shifts[ord($pass_arr[$i])]);
570 }
571
572 return $scrambled;
573}
a57a9493
MU
574
575package main;
576
2a3e1a85 577my $cvs = CVSconn->new($opt_d, $cvs_tree);
a57a9493
MU
578
579
580sub pdate($) {
86d11cf2 581 my ($d) = @_;
a57a9493
MU
582 m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
583 or die "Unparseable date: $d\n";
584 my $y=$1; $y-=1900 if $y>1900;
585 return timegm($6||0,$5,$4,$3,$2-1,$y);
9718a00b
TM
586}
587
a57a9493 588sub pmode($) {
86d11cf2 589 my ($mode) = @_;
a57a9493
MU
590 my $m = 0;
591 my $mm = 0;
592 my $um = 0;
593 for my $x(split(//,$mode)) {
86d11cf2 594 if ($x eq ",") {
a57a9493
MU
595 $m |= $mm&$um;
596 $mm = 0;
597 $um = 0;
86d11cf2
JH
598 } elsif ($x eq "u") { $um |= 0700;
599 } elsif ($x eq "g") { $um |= 0070;
600 } elsif ($x eq "o") { $um |= 0007;
601 } elsif ($x eq "r") { $mm |= 0444;
602 } elsif ($x eq "w") { $mm |= 0222;
603 } elsif ($x eq "x") { $mm |= 0111;
604 } elsif ($x eq "=") { # do nothing
a57a9493
MU
605 } else { die "Unknown mode: $mode\n";
606 }
607 }
608 $m |= $mm&$um;
609 return $m;
610}
d4f8b390 611
a57a9493
MU
612sub getwd() {
613 my $pwd = `pwd`;
614 chomp $pwd;
615 return $pwd;
d4f8b390
LT
616}
617
e73aefe4
JK
618sub is_sha1 {
619 my $s = shift;
620 return $s =~ /^[a-f0-9]{40}$/;
621}
db4b6582 622
9da0dabc
JK
623sub get_headref ($) {
624 my $name = shift;
625 my $r = `git rev-parse --verify '$name' 2>/dev/null`;
626 return undef unless $? == 0;
627 chomp $r;
628 return $r;
db4b6582
ML
629}
630
f6fdbb68
JK
631my $user_filename_prepend = '';
632sub munge_user_filename {
633 my $name = shift;
634 return File::Spec->file_name_is_absolute($name) ?
635 $name :
636 $user_filename_prepend . $name;
637}
638
a57a9493
MU
639-d $git_tree
640 or mkdir($git_tree,0777)
641 or die "Could not create $git_tree: $!";
f6fdbb68
JK
642if ($git_tree ne '.') {
643 $user_filename_prepend = getwd() . '/';
644 chdir($git_tree);
645}
d4f8b390 646
a57a9493 647my $last_branch = "";
46541669 648my $orig_branch = "";
a57a9493 649my %branch_date;
8a5f2eac 650my $tip_at_start = undef;
a57a9493
MU
651
652my $git_dir = $ENV{"GIT_DIR"} || ".git";
653$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#;
654$ENV{"GIT_DIR"} = $git_dir;
79ee456c
SV
655my $orig_git_index;
656$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE};
8f732649
ML
657
658my %index; # holds filenames of one index per branch
061303f0 659
86d11cf2 660unless (-d $git_dir) {
91fe7324 661 system(qw(git init));
a57a9493 662 die "Cannot init the GIT db at $git_tree: $?\n" if $?;
1bb28d87 663 system(qw(git read-tree --empty));
a57a9493
MU
664 die "Cannot init an empty tree: $?\n" if $?;
665
666 $last_branch = $opt_o;
46541669 667 $orig_branch = "";
a57a9493 668} else {
a12477db 669 open(F, "-|", qw(git symbolic-ref HEAD)) or
640d9d08 670 die "Cannot run git symbolic-ref: $!\n";
8366a10a
PR
671 chomp ($last_branch = <F>);
672 $last_branch = basename($last_branch);
673 close(F);
86d11cf2 674 unless ($last_branch) {
46541669
MU
675 warn "Cannot read the last branch name: $! -- assuming 'master'\n";
676 $last_branch = "master";
677 }
678 $orig_branch = $last_branch;
640d9d08 679 $tip_at_start = `git rev-parse --verify HEAD`;
a57a9493
MU
680
681 # Get the last import timestamps
1f24c587 682 my $fmt = '($ref, $author) = (%(refname), %(author));';
a12477db
BW
683 my @cmd = ('git', 'for-each-ref', '--perl', "--format=$fmt", $remote);
684 open(H, "-|", @cmd) or die "Cannot run git for-each-ref: $!\n";
86d11cf2 685 while (defined(my $entry = <H>)) {
1f24c587
AW
686 my ($ref, $author);
687 eval($entry) || die "cannot eval refs list: $@";
8b7f5fc1 688 my ($head) = ($ref =~ m|^$remote/(.*)|);
1f24c587
AW
689 $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
690 $branch_date{$head} = $1;
a57a9493 691 }
1f24c587 692 close(H);
7ca055f7
SS
693 if (!exists $branch_date{$opt_o}) {
694 die "Branch '$opt_o' does not exist.\n".
695 "Either use the correct '-o branch' option,\n".
696 "or import to a new repository.\n";
697 }
a57a9493
MU
698}
699
700-d $git_dir
701 or die "Could not create git subdir ($git_dir).\n";
702
ffd97f3a
AE
703# now we read (and possibly save) author-info as well
704-f "$git_dir/cvs-authors" and
705 read_author_info("$git_dir/cvs-authors");
706if ($opt_A) {
f6fdbb68 707 read_author_info(munge_user_filename($opt_A));
ffd97f3a
AE
708 write_author_info("$git_dir/cvs-authors");
709}
710
0455ec03
AC
711# open .git/cvs-revisions, if requested
712open my $revision_map, '>>', "$git_dir/cvs-revisions"
713 or die "Can't open $git_dir/cvs-revisions for appending: $!\n"
714 if defined $opt_R;
715
2f57c697
ML
716
717#
718# run cvsps into a file unless we are getting
719# it passed as a file via $opt_P
720#
4083c2fc 721my $cvspsfile;
2f57c697
ML
722unless ($opt_P) {
723 print "Running cvsps...\n" if $opt_v;
724 my $pid = open(CVSPS,"-|");
4083c2fc 725 my $cvspsfh;
2f57c697 726 die "Cannot fork: $!\n" unless defined $pid;
86d11cf2 727 unless ($pid) {
2f57c697
ML
728 my @opt;
729 @opt = split(/,/,$opt_p) if defined $opt_p;
730 unshift @opt, '-z', $opt_z if defined $opt_z;
731 unshift @opt, '-q' unless defined $opt_v;
732 unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
733 push @opt, '--cvs-direct';
734 }
735 exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
736 die "Could not start cvsps: $!\n";
df73e9c6 737 }
4083c2fc
ML
738 ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
739 DIR => File::Spec->tmpdir());
2f57c697
ML
740 while (<CVSPS>) {
741 print $cvspsfh $_;
211dcac6 742 }
2f57c697 743 close CVSPS;
640d9d08 744 $? == 0 or die "git cvsimport: fatal: cvsps reported error\n";
2f57c697 745 close $cvspsfh;
4083c2fc 746} else {
f6fdbb68 747 $cvspsfile = munge_user_filename($opt_P);
a57a9493
MU
748}
749
4083c2fc 750open(CVS, "<$cvspsfile") or die $!;
2f57c697 751
a57a9493
MU
752## cvsps output:
753#---------------------
754#PatchSet 314
755#Date: 1999/09/18 13:03:59
756#Author: wkoch
757#Branch: STABLE-BRANCH-1-0
758#Ancestor branch: HEAD
759#Tag: (none)
760#Log:
761# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch
762#Members:
763# README:1.57->1.57.2.1
764# VERSION:1.96->1.96.2.1
765#
766#---------------------
767
768my $state = 0;
769
e73aefe4
JK
770sub update_index (\@\@) {
771 my $old = shift;
772 my $new = shift;
640d9d08
BW
773 open(my $fh, '|-', qw(git update-index -z --index-info))
774 or die "unable to open git update-index: $!";
6a1871e1
JK
775 print $fh
776 (map { "0 0000000000000000000000000000000000000000\t$_\0" }
e73aefe4 777 @$old),
6a1871e1 778 (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
e73aefe4 779 @$new)
640d9d08 780 or die "unable to write to git update-index: $!";
6a1871e1 781 close $fh
640d9d08
BW
782 or die "unable to write to git update-index: $!";
783 $? and die "git update-index reported error: $?";
e73aefe4 784}
a57a9493 785
e73aefe4 786sub write_tree () {
a12477db 787 open(my $fh, '-|', qw(git write-tree))
640d9d08 788 or die "unable to open git write-tree: $!";
e73aefe4
JK
789 chomp(my $tree = <$fh>);
790 is_sha1($tree)
791 or die "Cannot get tree id ($tree): $!";
792 close($fh)
640d9d08 793 or die "Error running git write-tree: $?\n";
a57a9493 794 print "Tree ID $tree\n" if $opt_v;
e73aefe4
JK
795 return $tree;
796}
a57a9493 797
86d11cf2 798my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
0455ec03 799my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
71b08148
ML
800
801# commits that cvsps cannot place anywhere...
802$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
803
e73aefe4 804sub commit {
9da0dabc
JK
805 if ($branch eq $opt_o && !$index{branch} &&
806 !get_headref("$remote/$branch")) {
c5f448b0 807 # looks like an initial commit
640d9d08 808 # use the index primed by git init
23fcdc79
MM
809 $ENV{GIT_INDEX_FILE} = "$git_dir/index";
810 $index{$branch} = "$git_dir/index";
c5f448b0
ML
811 } else {
812 # use an index per branch to speed up
813 # imports of projects with many branches
814 unless ($index{$branch}) {
815 $index{$branch} = tmpnam();
816 $ENV{GIT_INDEX_FILE} = $index{$branch};
817 if ($ancestor) {
640d9d08 818 system("git", "read-tree", "$remote/$ancestor");
c5f448b0 819 } else {
640d9d08 820 system("git", "read-tree", "$remote/$branch");
c5f448b0
ML
821 }
822 die "read-tree failed: $?\n" if $?;
823 }
824 }
825 $ENV{GIT_INDEX_FILE} = $index{$branch};
826
e73aefe4
JK
827 update_index(@old, @new);
828 @old = @new = ();
829 my $tree = write_tree();
9da0dabc 830 my $parent = get_headref("$remote/$last_branch");
e73aefe4
JK
831 print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
832
833 my @commit_args;
834 push @commit_args, ("-p", $parent) if $parent;
835
836 # loose detection of merges
837 # based on the commit msg
838 foreach my $rx (@mergerx) {
839 next unless $logmsg =~ $rx && $1;
840 my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
9da0dabc 841 if (my $sha1 = get_headref("$remote/$mparent")) {
c36c5b84 842 push @commit_args, '-p', "$remote/$mparent";
e73aefe4 843 print "Merge parent branch: $mparent\n" if $opt_v;
db4b6582 844 }
a57a9493 845 }
e73aefe4
JK
846
847 my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date));
62bf0d96
JK
848 $ENV{GIT_AUTHOR_NAME} = $author_name;
849 $ENV{GIT_AUTHOR_EMAIL} = $author_email;
850 $ENV{GIT_AUTHOR_DATE} = $commit_date;
851 $ENV{GIT_COMMITTER_NAME} = $author_name;
852 $ENV{GIT_COMMITTER_EMAIL} = $author_email;
853 $ENV{GIT_COMMITTER_DATE} = $commit_date;
e73aefe4 854 my $pid = open2(my $commit_read, my $commit_write,
640d9d08 855 'git', 'commit-tree', $tree, @commit_args);
e371046b
MU
856
857 # compatibility with git2cvs
858 substr($logmsg,32767) = "" if length($logmsg) > 32767;
859 $logmsg =~ s/[\s\n]+\z//;
860
5179c8a5
ML
861 if (@skipped) {
862 $logmsg .= "\n\n\nSKIPPED:\n\t";
863 $logmsg .= join("\n\t", @skipped) . "\n";
f396f01f 864 @skipped = ();
5179c8a5
ML
865 }
866
e73aefe4 867 print($commit_write "$logmsg\n") && close($commit_write)
640d9d08 868 or die "Error writing to git commit-tree: $!\n";
2a3e1a85 869
e73aefe4
JK
870 print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
871 chomp(my $cid = <$commit_read>);
872 is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
a57a9493 873 print "Commit ID $cid\n" if $opt_v;
e73aefe4 874 close($commit_read);
2a3e1a85
MU
875
876 waitpid($pid,0);
640d9d08 877 die "Error running git commit-tree: $?\n" if $?;
a57a9493 878
640d9d08 879 system('git' , 'update-ref', "$remote/$branch", $cid) == 0
a57a9493
MU
880 or die "Cannot write branch $branch for update: $!\n";
881
0455ec03
AC
882 if ($revision_map) {
883 print $revision_map "@$_ $cid\n" for @commit_revisions;
884 }
885 @commit_revisions = ();
886
86d11cf2 887 if ($tag) {
86d11cf2 888 my ($xtag) = $tag;
0d821d4d
PA
889 $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
890 $xtag =~ tr/_/\./ if ( $opt_u );
34c99da2 891 $xtag =~ s/[\/]/$opt_s/g;
a6080a0a 892
70b67b07
KD
893 # See refs.c for these rules.
894 # Tag cannot contain bad chars. (See bad_ref_char in refs.c.)
895 $xtag =~ s/[ ~\^:\\\*\?\[]//g;
896 # Other bad strings for tags:
897 # (See check_refname_component in refs.c.)
898 1 while $xtag =~ s/
899 (?: \.\. # Tag cannot contain '..'.
900 | \@{ # Tag cannot contain '@{'.
901 | ^ - # Tag cannot begin with '-'.
902 | \.lock $ # Tag cannot end with '.lock'.
903 | ^ \. # Tag cannot begin...
904 | \. $ # ...or end with '.'
905 )//xg;
906 # Tag cannot be empty.
907 if ($xtag eq '') {
908 warn("warning: ignoring tag '$tag'",
909 " with invalid tagname\n");
910 return;
911 }
912
913 if (system('git' , 'tag', '-f', $xtag, $cid) != 0) {
914 # We did our best to sanitize the tag, but still failed
915 # for whatever reason. Bail out, and give the user
916 # enough information to understand if/how we should
917 # improve the translation in the future.
918 if ($tag ne $xtag) {
919 print "Translated '$tag' tag to '$xtag'\n";
920 }
921 die "Cannot create tag $xtag: $!\n";
922 }
0d821d4d
PA
923
924 print "Created tag '$xtag' on '$branch'\n" if $opt_v;
a57a9493 925 }
a57a9493
MU
926};
927
06918348 928my $commitcount = 1;
86d11cf2 929while (<CVS>) {
a57a9493 930 chomp;
86d11cf2 931 if ($state == 0 and /^-+$/) {
a57a9493 932 $state = 1;
86d11cf2 933 } elsif ($state == 0) {
a57a9493
MU
934 $state = 1;
935 redo;
86d11cf2 936 } elsif (($state==0 or $state==1) and s/^PatchSet\s+//) {
a57a9493
MU
937 $patchset = 0+$_;
938 $state=2;
86d11cf2 939 } elsif ($state == 2 and s/^Date:\s+//) {
a57a9493 940 $date = pdate($_);
86d11cf2 941 unless ($date) {
a57a9493
MU
942 print STDERR "Could not parse date: $_\n";
943 $state=0;
944 next;
945 }
946 $state=3;
86d11cf2 947 } elsif ($state == 3 and s/^Author:\s+//) {
a57a9493 948 s/\s+$//;
94c23343
JH
949 if (/^(.*?)\s+<(.*)>/) {
950 ($author_name, $author_email) = ($1, $2);
ffd97f3a
AE
951 } elsif ($conv_author_name{$_}) {
952 $author_name = $conv_author_name{$_};
953 $author_email = $conv_author_email{$_};
94c23343
JH
954 } else {
955 $author_name = $author_email = $_;
956 }
a57a9493 957 $state = 4;
86d11cf2 958 } elsif ($state == 4 and s/^Branch:\s+//) {
a57a9493 959 s/\s+$//;
a0554224 960 tr/_/\./ if ( $opt_u );
fbfd60d6 961 s/[\/]/$opt_s/g;
a57a9493
MU
962 $branch = $_;
963 $state = 5;
86d11cf2 964 } elsif ($state == 5 and s/^Ancestor branch:\s+//) {
a57a9493
MU
965 s/\s+$//;
966 $ancestor = $_;
0fa2824f 967 $ancestor = $opt_o if $ancestor eq "HEAD";
a57a9493 968 $state = 6;
86d11cf2 969 } elsif ($state == 5) {
a57a9493
MU
970 $ancestor = undef;
971 $state = 6;
972 redo;
86d11cf2 973 } elsif ($state == 6 and s/^Tag:\s+//) {
a57a9493 974 s/\s+$//;
86d11cf2 975 if ($_ eq "(none)") {
a57a9493
MU
976 $tag = undef;
977 } else {
978 $tag = $_;
979 }
980 $state = 7;
86d11cf2 981 } elsif ($state == 7 and /^Log:/) {
a57a9493
MU
982 $logmsg = "";
983 $state = 8;
86d11cf2 984 } elsif ($state == 8 and /^Members:/) {
a57a9493 985 $branch = $opt_o if $branch eq "HEAD";
86d11cf2 986 if (defined $branch_date{$branch} and $branch_date{$branch} >= $date) {
a57a9493 987 # skip
9da07f34 988 print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v;
a57a9493
MU
989 $state = 11;
990 next;
991 }
ded9f400 992 if (!$opt_a && $starttime - 300 - (defined $opt_z ? $opt_z : 300) <= $date) {
6211988f 993 # skip if the commit is too recent
77190eb9 994 # given that the cvsps default fuzz is 300s, we give ourselves another
6211988f
ML
995 # 300s just in case -- this also prevents skipping commits
996 # due to server clock drift
997 print "skip patchset $patchset: $date too recent\n" if $opt_v;
998 $state = 11;
999 next;
1000 }
71b08148
ML
1001 if (exists $ignorebranch{$branch}) {
1002 print STDERR "Skipping $branch\n";
1003 $state = 11;
1004 next;
1005 }
86d11cf2
JH
1006 if ($ancestor) {
1007 if ($ancestor eq $branch) {
71b08148
ML
1008 print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
1009 $ancestor = $opt_o;
1010 }
0750d751 1011 if (defined get_headref("$remote/$branch")) {
a57a9493
MU
1012 print STDERR "Branch $branch already exists!\n";
1013 $state=11;
1014 next;
1015 }
0750d751
JK
1016 my $id = get_headref("$remote/$ancestor");
1017 if (!$id) {
a57a9493 1018 print STDERR "Branch $ancestor does not exist!\n";
71b08148 1019 $ignorebranch{$branch} = 1;
a57a9493
MU
1020 $state=11;
1021 next;
1022 }
0750d751
JK
1023
1024 system(qw(git update-ref -m cvsimport),
1025 "$remote/$branch", $id);
1026 if($? != 0) {
1027 print STDERR "Could not create branch $branch\n";
71b08148 1028 $ignorebranch{$branch} = 1;
a57a9493
MU
1029 $state=11;
1030 next;
1031 }
a57a9493 1032 }
46e63efc 1033 $last_branch = $branch if $branch ne $last_branch;
a57a9493 1034 $state = 9;
86d11cf2 1035 } elsif ($state == 8) {
a57a9493 1036 $logmsg .= "$_\n";
86d11cf2 1037 } elsif ($state == 9 and /^\s+(.+?):(INITIAL|\d+(?:\.\d+)+)->(\d+(?:\.\d+)+)\s*$/) {
a57a9493 1038# VERSION:1.96->1.96.2.1
2a3e1a85 1039 my $init = ($2 eq "INITIAL");
a57a9493 1040 my $fn = $1;
f65ae603
MU
1041 my $rev = $3;
1042 $fn =~ s#^/+##;
5179c8a5
ML
1043 if ($opt_S && $fn =~ m/$opt_S/) {
1044 print "SKIPPING $fn v $rev\n";
1045 push(@skipped, $fn);
1046 next;
1047 }
0455ec03 1048 push @commit_revisions, [$fn, $rev];
5179c8a5 1049 print "Fetching $fn v $rev\n" if $opt_v;
2eb6d82e 1050 my ($tmpname, $size) = $cvs->file($fn,$rev);
86d11cf2 1051 if ($size == -1) {
8b8840e0
MU
1052 push(@old,$fn);
1053 print "Drop $fn\n" if $opt_v;
1054 } else {
1055 print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
dd27478f
JH
1056 my $pid = open(my $F, '-|');
1057 die $! unless defined $pid;
1058 if (!$pid) {
640d9d08 1059 exec("git", "hash-object", "-w", $tmpname)
8b8840e0 1060 or die "Cannot create object: $!\n";
dd27478f 1061 }
8b8840e0
MU
1062 my $sha = <$F>;
1063 chomp $sha;
1064 close $F;
1065 my $mode = pmode($cvs->{'mode'});
1066 push(@new,[$mode, $sha, $fn]); # may be resurrected!
1067 }
2eb6d82e 1068 unlink($tmpname);
86d11cf2 1069 } elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
f65ae603 1070 my $fn = $1;
0455ec03 1071 my $rev = $2;
f65ae603 1072 $fn =~ s#^/+##;
0455ec03 1073 push @commit_revisions, [$fn, $rev];
f65ae603 1074 push(@old,$fn);
8b8840e0 1075 print "Delete $fn\n" if $opt_v;
86d11cf2 1076 } elsif ($state == 9 and /^\s*$/) {
a57a9493 1077 $state = 10;
86d11cf2 1078 } elsif (($state == 9 or $state == 10) and /^-+$/) {
4adcea99
LT
1079 $commitcount++;
1080 if ($opt_L && $commitcount > $opt_L) {
06918348
ML
1081 last;
1082 }
c4b16f8d 1083 commit();
4adcea99 1084 if (($commitcount & 1023) == 0) {
91fe7324 1085 system(qw(git repack -a -d));
4adcea99 1086 }
a57a9493 1087 $state = 1;
86d11cf2 1088 } elsif ($state == 11 and /^-+$/) {
a57a9493 1089 $state = 1;
86d11cf2 1090 } elsif (/^-+$/) { # end of unknown-line processing
a57a9493 1091 $state = 1;
86d11cf2 1092 } elsif ($state != 11) { # ignore stuff when skipping
3be39998 1093 print STDERR "* UNKNOWN LINE * $_\n";
a57a9493
MU
1094 }
1095}
c4b16f8d 1096commit() if $branch and $state != 11;
d4f8b390 1097
4083c2fc
ML
1098unless ($opt_P) {
1099 unlink($cvspsfile);
1100}
1101
efe4abd1
JM
1102# The heuristic of repacking every 1024 commits can leave a
1103# lot of unpacked data. If there is more than 1MB worth of
1104# not-packed objects, repack once more.
640d9d08 1105my $line = `git count-objects`;
efe4abd1
JM
1106if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) {
1107 my ($n_objects, $kb) = ($1, $2);
1108 1024 < $kb
91fe7324 1109 and system(qw(git repack -a -d));
efe4abd1
JM
1110}
1111
8f732649 1112foreach my $git_index (values %index) {
23fcdc79 1113 if ($git_index ne "$git_dir/index") {
c5f448b0
ML
1114 unlink($git_index);
1115 }
8f732649 1116}
79ee456c 1117
210569f9
SV
1118if (defined $orig_git_index) {
1119 $ENV{GIT_INDEX_FILE} = $orig_git_index;
1120} else {
1121 delete $ENV{GIT_INDEX_FILE};
1122}
1123
46541669 1124# Now switch back to the branch we were in before all of this happened
86d11cf2 1125if ($orig_branch) {
8a5f2eac
JH
1126 print "DONE.\n" if $opt_v;
1127 if ($opt_i) {
1128 exit 0;
1129 }
640d9d08 1130 my $tip_at_end = `git rev-parse --verify HEAD`;
8a5f2eac 1131 if ($tip_at_start ne $tip_at_end) {
cb9594e2 1132 for ($tip_at_start, $tip_at_end) { chomp; }
8a5f2eac 1133 print "Fetched into the current branch.\n" if $opt_v;
640d9d08 1134 system(qw(git read-tree -u -m),
8a5f2eac
JH
1135 $tip_at_start, $tip_at_end);
1136 die "Fast-forward update failed: $?\n" if $?;
1137 }
1138 else {
640d9d08 1139 system(qw(git merge cvsimport HEAD), "$remote/$opt_o");
8a5f2eac
JH
1140 die "Could not merge $opt_o into the current branch.\n" if $?;
1141 }
46541669
MU
1142} else {
1143 $orig_branch = "master";
1144 print "DONE; creating $orig_branch branch\n" if $opt_v;
640d9d08 1145 system("git", "update-ref", "refs/heads/master", "$remote/$opt_o")
0750d751 1146 unless defined get_headref('refs/heads/master');
640d9d08 1147 system("git", "symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
06baffd3 1148 if ($opt_r && $opt_o ne 'HEAD');
640d9d08 1149 system('git', 'update-ref', 'HEAD', "$orig_branch");
c1c774e7 1150 unless ($opt_i) {
91fe7324 1151 system(qw(git checkout -f));
c1c774e7
SV
1152 die "checkout failed: $?\n" if $?;
1153 }
46541669 1154}