blob: b31613cb8aa8decd3f808d5d29e047243fa1eac6 [file] [log] [blame]
Ævar Arnfjörð Bjarmason3328ace2010-09-24 20:00:53 +00001#!/usr/bin/perl
Tommy M. McGuire9718a002005-06-10 01:38:32 -05002
Matthias Urlichsa57a9492005-06-28 16:48:40 +02003# 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
Ævar Arnfjörð Bjarmasond48b2842010-09-24 20:00:52 +000016use 5.008;
Matthias Urlichsa57a9492005-06-28 16:48:40 +020017use strict;
18use warnings;
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +010019use Getopt::Long;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +020020use File::Spec;
Martin Langhoff7ccd9002006-06-24 23:13:08 +120021use File::Temp qw(tempfile tmpnam);
Matthias Urlichsa57a9492005-06-28 16:48:40 +020022use File::Path qw(mkpath);
23use File::Basename qw(basename dirname);
24use Time::Local;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +020025use IO::Socket;
26use IO::Pipe;
Jeff Kingc2b3af02012-11-04 07:25:36 -050027use POSIX qw(strftime tzset dup2 ENOENT);
H. Peter Anvin0d821d42005-09-06 10:36:01 -070028use IPC::Open2;
Ben Walton48c91622013-02-09 21:46:58 +000029use Git qw(get_tz_offset);
Matthias Urlichsa57a9492005-06-28 16:48:40 +020030
31$SIG{'PIPE'}="IGNORE";
Jeff Kingc2b3af02012-11-04 07:25:36 -050032set_timezone('UTC');
Matthias Urlichsa57a9492005-06-28 16:48:40 +020033
Aaron Crane0455ec02010-02-06 18:26:24 +000034our ($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);
Chris Rorvickfb2c9842012-10-16 22:53:29 -050035my (%conv_author_name, %conv_author_email, %conv_author_tz);
Matthias Urlichsa57a9492005-06-28 16:48:40 +020036
Frank Lichtenheld7bf77642007-04-06 23:52:41 +020037sub usage(;$) {
38 my $msg = shift;
39 print(STDERR "Error: $msg\n") if $msg;
Matthias Urlichsa57a9492005-06-28 16:48:40 +020040 print STDERR <<END;
David Aguilarce7f3ca2013-02-23 16:50:15 -080041usage: git cvsimport # fetch/update GIT from CVS
Andreas Ericssonffd97f32006-01-13 00:38:59 +010042 [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
Frank Lichtenheldedbe4462007-04-06 23:52:39 +020043 [-p opts-for-cvsps] [-P file] [-C GIT_repository] [-z fuzz] [-i] [-k]
44 [-u] [-s subst] [-a] [-m] [-M regex] [-S regex] [-L commitlimit]
Aaron Crane0455ec02010-02-06 18:26:24 +000045 [-r remote] [-R] [CVS_module]
Matthias Urlichsa57a9492005-06-28 16:48:40 +020046END
47 exit(1);
Tommy M. McGuire9718a002005-06-10 01:38:32 -050048}
49
Andreas Ericssonffd97f32006-01-13 00:38:59 +010050sub read_author_info($) {
51 my ($file) = @_;
52 my $user;
53 open my $f, '<', "$file" or die("Failed to open $file: $!\n");
54
55 while (<$f>) {
Junio C Hamano8cd16212006-01-15 03:30:30 -080056 # Expected format is this:
Andreas Ericssonffd97f32006-01-13 00:38:59 +010057 # exon=Andreas Ericsson <ae@op5.se>
Junio C Hamano8cd16212006-01-15 03:30:30 -080058 if (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/) {
Andreas Ericssonffd97f32006-01-13 00:38:59 +010059 $user = $1;
Junio C Hamano8cd16212006-01-15 03:30:30 -080060 $conv_author_name{$user} = $2;
61 $conv_author_email{$user} = $3;
Andreas Ericssonffd97f32006-01-13 00:38:59 +010062 }
Chris Rorvickfb2c9842012-10-16 22:53:29 -050063 # or with an optional timezone:
64 # spawn=Simon Pawn <spawn@frog-pond.org> America/Chicago
65 elsif (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*(\S+?)\s*$/) {
66 $user = $1;
67 $conv_author_name{$user} = $2;
68 $conv_author_email{$user} = $3;
69 $conv_author_tz{$user} = $4;
70 }
Junio C Hamano8cd16212006-01-15 03:30:30 -080071 # However, we also read from CVSROOT/users format
72 # to ease migration.
73 elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) {
74 my $mapped;
75 ($user, $mapped) = ($1, $3);
76 if ($mapped =~ /^\s*(.*?)\s*<(.*)>\s*$/) {
77 $conv_author_name{$user} = $1;
78 $conv_author_email{$user} = $2;
79 }
80 elsif ($mapped =~ /^<?(.*)>?$/) {
81 $conv_author_name{$user} = $user;
82 $conv_author_email{$user} = $1;
83 }
84 }
85 # NEEDSWORK: Maybe warn on unrecognized lines?
Andreas Ericssonffd97f32006-01-13 00:38:59 +010086 }
87 close ($f);
88}
89
90sub write_author_info($) {
91 my ($file) = @_;
92 open my $f, '>', $file or
93 die("Failed to open $file for writing: $!");
94
95 foreach (keys %conv_author_name) {
Chris Rorvickfb2c9842012-10-16 22:53:29 -050096 print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>";
97 print $f " $conv_author_tz{$_}" if ($conv_author_tz{$_});
98 print $f "\n";
Andreas Ericssonffd97f32006-01-13 00:38:59 +010099 }
100 close ($f);
101}
102
Jeff Kingc2b3af02012-11-04 07:25:36 -0500103# Versions of perl before 5.10.0 may not automatically check $TZ each
104# time localtime is run (most platforms will do so only the first time).
105# We can work around this by using tzset() to update the internal
106# variable whenever we change the environment.
107sub set_timezone {
108 $ENV{TZ} = shift;
109 tzset();
110}
111
Dan McGeecfc44a12008-01-13 22:51:10 -0600112# convert getopts specs for use by git config
Michael J Gruber60d59852010-12-29 22:55:34 +0100113my %longmap = (
114 'A:' => 'authors-file',
115 'M:' => 'merge-regex',
116 'P:' => undef,
117 'R' => 'track-revisions',
118 'S:' => 'ignore-paths',
119);
120
James Bowesed35dec2007-02-07 17:57:43 -0500121sub read_repo_config {
Michael J Gruber549ad6d2010-11-28 20:39:45 +0100122 # Split the string between characters, unless there is a ':'
123 # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
James Bowesed35dec2007-02-07 17:57:43 -0500124 my @opts = split(/ *(?!:)/, shift);
125 foreach my $o (@opts) {
126 my $key = $o;
127 $key =~ s/://g;
Dan McGeecfc44a12008-01-13 22:51:10 -0600128 my $arg = 'git config';
James Bowesed35dec2007-02-07 17:57:43 -0500129 $arg .= ' --bool' if ($o !~ /:$/);
Michael J Gruber60d59852010-12-29 22:55:34 +0100130 my $ckey = $key;
James Bowesed35dec2007-02-07 17:57:43 -0500131
Michael J Gruber60d59852010-12-29 22:55:34 +0100132 if (exists $longmap{$o}) {
133 # An uppercase option like -R cannot be
134 # expressed in the configuration, as the
135 # variable names are downcased.
136 $ckey = $longmap{$o};
137 next if (! defined $ckey);
138 $ckey =~ s/-//g;
139 }
140 chomp(my $tmp = `$arg --get cvsimport.$ckey`);
James Bowesed35dec2007-02-07 17:57:43 -0500141 if ($tmp && !($arg =~ /--bool/ && $tmp eq 'false')) {
Michael J Gruber549ad6d2010-11-28 20:39:45 +0100142 no strict 'refs';
143 my $opt_name = "opt_" . $key;
144 if (!$$opt_name) {
145 $$opt_name = $tmp;
146 }
James Bowesed35dec2007-02-07 17:57:43 -0500147 }
148 }
James Bowesed35dec2007-02-07 17:57:43 -0500149}
150
Aaron Crane0455ec02010-02-06 18:26:24 +0000151my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:R";
James Bowesed35dec2007-02-07 17:57:43 -0500152read_repo_config($opts);
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +0100153Getopt::Long::Configure( 'no_ignore_case', 'bundling' );
154
155# turn the Getopt::Std specification in a Getopt::Long one,
156# with support for multiple -M options
157GetOptions( map { s/:/=s/; /M/ ? "$_\@" : $_ } split( /(?!:)/, $opts ) )
158 or usage();
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200159usage if $opt_h;
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700160
Jeff King67d23242007-11-30 17:22:12 -0500161if (@ARGV == 0) {
Dan McGeecfc44a12008-01-13 22:51:10 -0600162 chomp(my $module = `git config --get cvsimport.module`);
Jeff King67d23242007-11-30 17:22:12 -0500163 push(@ARGV, $module) if $? == 0;
164}
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200165@ARGV <= 1 or usage("You can't specify more than one CVS module");
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200166
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800167if ($opt_d) {
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200168 $ENV{"CVSROOT"} = $opt_d;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800169} elsif (-f 'CVS/Root') {
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200170 open my $f, '<', 'CVS/Root' or die 'Failed to open CVS/Root';
171 $opt_d = <$f>;
172 chomp $opt_d;
173 close $f;
174 $ENV{"CVSROOT"} = $opt_d;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800175} elsif ($ENV{"CVSROOT"}) {
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200176 $opt_d = $ENV{"CVSROOT"};
177} else {
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200178 usage("CVSROOT needs to be set");
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200179}
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200180$opt_s ||= "-";
Martin Langhoffded9f402007-01-08 19:43:39 +1300181$opt_a ||= 0;
182
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200183my $git_tree = $opt_C;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200184$git_tree ||= ".";
185
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100186my $remote;
187if (defined $opt_r) {
188 $remote = 'refs/remotes/' . $opt_r;
189 $opt_o ||= "master";
190} else {
191 $opt_o ||= "origin";
192 $remote = 'refs/heads';
193}
194
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200195my $cvs_tree;
196if ($#ARGV == 0) {
197 $cvs_tree = $ARGV[0];
198} elsif (-f 'CVS/Repository') {
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700199 open my $f, '<', 'CVS/Repository' or
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200200 die 'Failed to open CVS/Repository';
201 $cvs_tree = <$f>;
202 chomp $cvs_tree;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200203 close $f;
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200204} else {
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200205 usage("CVS module has to be specified");
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200206}
207
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200208our @mergerx = ();
209if ($opt_m) {
Philippe Bruhat (BooKfbbbc362008-02-28 11:18:21 +0100210 @mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i );
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200211}
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +0100212if (@opt_M) {
213 push (@mergerx, map { qr/$_/ } @opt_M);
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200214}
215
Martin Langhoff62119882007-01-08 14:11:23 +1300216# Remember UTC of our starting time
217# we'll want to avoid importing commits
218# that are too recent
219our $starttime = time();
220
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200221select(STDERR); $|=1; select(STDOUT);
222
223
224package CVSconn;
225# Basic CVS dialog.
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200226# We're only interested in connecting and downloading, so ...
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200227
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200228use File::Spec;
229use File::Temp qw(tempfile);
Matthias Urlichsf65ae602005-06-28 19:58:40 +0200230use POSIX qw(strftime dup2);
231
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200232sub new {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800233 my ($what,$repo,$subdir) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200234 $what=ref($what) if ref($what);
235
236 my $self = {};
237 $self->{'buffer'} = "";
238 bless($self,$what);
239
240 $repo =~ s#/+$##;
241 $self->{'fullrep'} = $repo;
242 $self->conn();
243
244 $self->{'subdir'} = $subdir;
245 $self->{'lines'} = undef;
246
247 return $self;
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700248}
249
Guy Rouillier58fdef02011-05-01 01:33:52 -0400250sub find_password_entry {
251 my ($cvspass, @cvsroot) = @_;
252 my ($file, $delim) = @$cvspass;
253 my $pass;
254 local ($_);
255
256 if (open(my $fh, $file)) {
257 # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z
258 CVSPASSFILE:
259 while (<$fh>) {
260 chomp;
261 s/^\/\d+\s+//;
262 my ($w, $p) = split($delim,$_,2);
263 for my $cvsroot (@cvsroot) {
264 if ($w eq $cvsroot) {
265 $pass = $p;
266 last CVSPASSFILE;
267 }
268 }
269 }
270 close($fh);
271 }
272 return $pass;
273}
274
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200275sub conn {
276 my $self = shift;
277 my $repo = $self->{'fullrep'};
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800278 if ($repo =~ s/^:pserver(?:([^:]*)):(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) {
279 my ($param,$user,$pass,$serv,$port) = ($1,$2,$3,$4,$5);
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100280
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800281 my ($proxyhost,$proxyport);
282 if ($param && ($param =~ m/proxy=([^;]+)/)) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100283 $proxyhost = $1;
284 # Default proxyport, if not specified, is 8080.
285 $proxyport = 8080;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800286 if ($ENV{"CVS_PROXY_PORT"}) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100287 $proxyport = $ENV{"CVS_PROXY_PORT"};
288 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800289 if ($param =~ m/proxyport=([^;]+)/) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100290 $proxyport = $1;
291 }
292 }
Philippe Bruhat (BooK)8c372fb2008-06-10 14:32:06 +0200293 $repo ||= '/';
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100294
Gordon Hopper2e458e02007-11-08 13:15:20 -0700295 # if username is not explicit in CVSROOT, then use current user, as cvs would
296 $user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200297 my $rr2 = "-";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800298 unless ($port) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200299 $rr2 = ":pserver:$user\@$serv:$repo";
300 $port=2401;
301 }
302 my $rr = ":pserver:$user\@$serv:$port$repo";
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700303
Pascal Obry3fb9d582009-09-04 13:58:32 +0200304 if ($pass) {
305 $pass = $self->_scramble($pass);
306 } else {
Guy Rouillier58fdef02011-05-01 01:33:52 -0400307 my @cvspass = ([$ENV{'HOME'}."/.cvspass", qr/\s/],
308 [$ENV{'HOME'}."/.cvs/cvspass", qr/=/]);
309 my @loc = ();
310 foreach my $cvspass (@cvspass) {
311 my $p = find_password_entry($cvspass, $rr, $rr2);
312 if ($p) {
313 push @loc, $cvspass->[0];
314 $pass = $p;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200315 }
Guy Rouillier58fdef02011-05-01 01:33:52 -0400316 }
317
318 if (1 < @loc) {
319 die("Multiple cvs password files have ".
320 "entries for CVSROOT $opt_d: @loc");
321 } elsif (!$pass) {
322 $pass = "A";
323 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200324 }
Dirk Hoernerb2139db2009-08-14 08:58:31 +0200325
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100326 my ($s, $rep);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800327 if ($proxyhost) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100328
329 # Use a HTTP Proxy. Only works for HTTP proxies that
330 # don't require user authentication
331 #
332 # See: http://www.ietf.org/rfc/rfc2817.txt
333
334 $s = IO::Socket::INET->new(PeerHost => $proxyhost, PeerPort => $proxyport);
335 die "Socket to $proxyhost: $!\n" unless defined $s;
336 $s->write("CONNECT $serv:$port HTTP/1.1\r\nHost: $serv:$port\r\n\r\n")
337 or die "Write to $proxyhost: $!\n";
338 $s->flush();
339
340 $rep = <$s>;
341
342 # The answer should look like 'HTTP/1.x 2yy ....'
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800343 if (!($rep =~ m#^HTTP/1\.. 2[0-9][0-9]#)) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100344 die "Proxy connect: $rep\n";
345 }
346 # Skip up to the empty line of the proxy server output
347 # including the response headers.
348 while ($rep = <$s>) {
349 last if (!defined $rep ||
350 $rep eq "\n" ||
351 $rep eq "\r\n");
352 }
353 } else {
354 $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port);
355 die "Socket to $serv: $!\n" unless defined $s;
356 }
357
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200358 $s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n")
359 or die "Write to $serv: $!\n";
360 $s->flush();
361
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100362 $rep = <$s>;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200363
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800364 if ($rep ne "I LOVE YOU\n") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200365 $rep="<unknown>" unless $rep;
366 die "AuthReply: $rep\n";
367 }
368 $self->{'socketo'} = $s;
369 $self->{'socketi'} = $s;
Sven Verdoolaege34155392005-07-03 13:02:06 +0200370 } else { # local or ext: Fork off our own cvs server.
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200371 my $pr = IO::Pipe->new();
372 my $pw = IO::Pipe->new();
373 my $pid = fork();
374 die "Fork: $!\n" unless defined $pid;
Sven Verdoolaege8d0ea312005-07-03 12:26:51 +0200375 my $cvs = 'cvs';
376 $cvs = $ENV{CVS_SERVER} if exists $ENV{CVS_SERVER};
Sven Verdoolaege34155392005-07-03 13:02:06 +0200377 my $rsh = 'rsh';
378 $rsh = $ENV{CVS_RSH} if exists $ENV{CVS_RSH};
379
380 my @cvs = ($cvs, 'server');
381 my ($local, $user, $host);
382 $local = $repo =~ s/:local://;
383 if (!$local) {
384 $repo =~ s/:ext://;
385 $local = !($repo =~ s/^(?:([^\@:]+)\@)?([^:]+)://);
386 ($user, $host) = ($1, $2);
387 }
388 if (!$local) {
389 if ($user) {
390 unshift @cvs, $rsh, '-l', $user, $host;
391 } else {
392 unshift @cvs, $rsh, $host;
393 }
394 }
395
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800396 unless ($pid) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200397 $pr->writer();
398 $pw->reader();
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200399 dup2($pw->fileno(),0);
400 dup2($pr->fileno(),1);
401 $pr->close();
402 $pw->close();
Sven Verdoolaege34155392005-07-03 13:02:06 +0200403 exec(@cvs);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200404 }
405 $pw->writer();
406 $pr->reader();
407 $self->{'socketo'} = $pw;
408 $self->{'socketi'} = $pr;
409 }
410 $self->{'socketo'}->write("Root $repo\n");
411
412 # Trial and error says that this probably is the minimum set
iso-8859-1?Q?David_K=E5gedalb0921332005-08-15 20:18:25 +0200413 $self->{'socketo'}->write("Valid-responses ok error Valid-requests Mode M Mbinary E Checked-in Created Updated Merged Removed\n");
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200414
415 $self->{'socketo'}->write("valid-requests\n");
416 $self->{'socketo'}->flush();
417
Fabian Keile7cad3c2011-01-31 20:29:46 +0100418 my $rep=$self->readline();
419 die "Failed to read from server" unless defined $rep;
420 chomp($rep);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800421 if ($rep !~ s/^Valid-requests\s*//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200422 $rep="<unknown>" unless $rep;
423 die "Expected Valid-requests from server, but got: $rep\n";
424 }
425 chomp(my $res=$self->readline());
426 die "validReply: $res\n" if $res ne "ok";
427
428 $self->{'socketo'}->write("UseUnchanged\n") if $rep =~ /\bUseUnchanged\b/;
429 $self->{'repo'} = $repo;
430}
431
432sub readline {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800433 my ($self) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200434 return $self->{'socketi'}->getline();
435}
436
437sub _file {
438 # Request a file with a given revision.
439 # Trial and error says this is a good way to do it. :-/
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800440 my ($self,$fn,$rev) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200441 $self->{'socketo'}->write("Argument -N\n") or return undef;
442 $self->{'socketo'}->write("Argument -P\n") or return undef;
Martin Langhoffabe05822005-08-16 17:39:29 +1200443 # -kk: Linus' version doesn't use it - defaults to off
444 if ($opt_k) {
445 $self->{'socketo'}->write("Argument -kk\n") or return undef;
446 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200447 $self->{'socketo'}->write("Argument -r\n") or return undef;
448 $self->{'socketo'}->write("Argument $rev\n") or return undef;
449 $self->{'socketo'}->write("Argument --\n") or return undef;
450 $self->{'socketo'}->write("Argument $self->{'subdir'}/$fn\n") or return undef;
451 $self->{'socketo'}->write("Directory .\n") or return undef;
452 $self->{'socketo'}->write("$self->{'repo'}\n") or return undef;
Matthias Urlichs4f7c0ca2005-06-30 12:19:48 +0200453 # $self->{'socketo'}->write("Sticky T1.0\n") or return undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200454 $self->{'socketo'}->write("co\n") or return undef;
455 $self->{'socketo'}->flush() or return undef;
456 $self->{'lines'} = 0;
457 return 1;
458}
459sub _line {
460 # Read a line from the server.
461 # ... except that 'line' may be an entire file. ;-)
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800462 my ($self, $fh) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200463 die "Not in lines" unless defined $self->{'lines'};
464
465 my $line;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200466 my $res=0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800467 while (defined($line = $self->readline())) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200468 # M U gnupg-cvs-rep/AUTHORS
469 # Updated gnupg-cvs-rep/
470 # /daten/src/rsync/gnupg-cvs-rep/AUTHORS
471 # /AUTHORS/1.1///T1.1
472 # u=rw,g=rw,o=rw
473 # 0
474 # ok
475
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800476 if ($line =~ s/^(?:Created|Updated) //) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200477 $line = $self->readline(); # path
478 $line = $self->readline(); # Entries line
479 my $mode = $self->readline(); chomp $mode;
480 $self->{'mode'} = $mode;
481 defined (my $cnt = $self->readline())
482 or die "EOF from server after 'Changed'\n";
483 chomp $cnt;
484 die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/;
485 $line="";
Martin Langhoff55cad842006-05-23 20:08:58 +1200486 $res = $self->_fetchfile($fh, $cnt);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800487 } elsif ($line =~ s/^ //) {
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200488 print $fh $line;
489 $res += length($line);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800490 } elsif ($line =~ /^M\b/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200491 # output, do nothing
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800492 } elsif ($line =~ /^Mbinary\b/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200493 my $cnt;
494 die "EOF from server after 'Mbinary'" unless defined ($cnt = $self->readline());
495 chomp $cnt;
496 die "Duh: Mbinary $cnt" if $cnt !~ /^\d+$/ or $cnt<1;
497 $line="";
Martin Langhoff55cad842006-05-23 20:08:58 +1200498 $res += $self->_fetchfile($fh, $cnt);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200499 } else {
500 chomp $line;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800501 if ($line eq "ok") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200502 # print STDERR "S: ok (".length($res).")\n";
503 return $res;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800504 } elsif ($line =~ s/^E //) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200505 # print STDERR "S: $line\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800506 } elsif ($line =~ /^(Remove-entry|Removed) /i) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200507 $line = $self->readline(); # filename
508 $line = $self->readline(); # OK
509 chomp $line;
510 die "Unknown: $line" if $line ne "ok";
511 return -1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200512 } else {
513 die "Unknown: $line\n";
514 }
515 }
516 }
Martin Mares39ba7d52006-02-18 21:44:20 +0100517 return undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200518}
519sub file {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800520 my ($self,$fn,$rev) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200521 my $res;
522
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700523 my ($fh, $name) = tempfile('gitcvs.XXXXXX',
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200524 DIR => File::Spec->tmpdir(), UNLINK => 1);
525
526 $self->_file($fn,$rev) and $res = $self->_line($fh);
527
528 if (!defined $res) {
Martin Mares39ba7d52006-02-18 21:44:20 +0100529 print STDERR "Server has gone away while fetching $fn $rev, retrying...\n";
530 truncate $fh, 0;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200531 $self->conn();
Martin Mares39ba7d52006-02-18 21:44:20 +0100532 $self->_file($fn,$rev) or die "No file command send";
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200533 $res = $self->_line($fh);
Martin Mares39ba7d52006-02-18 21:44:20 +0100534 die "Retry failed" unless defined $res;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200535 }
Sven Verdoolaegec619ad52005-07-06 08:37:12 +0200536 close ($fh);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200537
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200538 return ($name, $res);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200539}
Martin Langhoff55cad842006-05-23 20:08:58 +1200540sub _fetchfile {
541 my ($self, $fh, $cnt) = @_;
Junio C Hamano61efa5e2006-05-23 16:30:39 -0700542 my $res = 0;
Martin Langhoff55cad842006-05-23 20:08:58 +1200543 my $bufsize = 1024 * 1024;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800544 while ($cnt) {
Martin Langhoff55cad842006-05-23 20:08:58 +1200545 if ($bufsize > $cnt) {
546 $bufsize = $cnt;
547 }
548 my $buf;
549 my $num = $self->{'socketi'}->read($buf,$bufsize);
550 die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0;
551 print $fh $buf;
552 $res += $num;
553 $cnt -= $num;
554 }
555 return $res;
556}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200557
Dirk Hoernerb2139db2009-08-14 08:58:31 +0200558sub _scramble {
559 my ($self, $pass) = @_;
560 my $scrambled = "A";
561
562 return $scrambled unless $pass;
563
564 my $pass_len = length($pass);
565 my @pass_arr = split("", $pass);
566 my $i;
567
568 # from cvs/src/scramble.c
569 my @shifts = (
570 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
571 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
572 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
573 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
574 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
575 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
576 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
577 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
578 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
579 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
580 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
581 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
582 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
583 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
584 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
585 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152
586 );
587
588 for ($i = 0; $i < $pass_len; $i++) {
589 $scrambled .= pack("C", $shifts[ord($pass_arr[$i])]);
590 }
591
592 return $scrambled;
593}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200594
595package main;
596
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200597my $cvs = CVSconn->new($opt_d, $cvs_tree);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200598
599
600sub pdate($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800601 my ($d) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200602 m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
603 or die "Unparseable date: $d\n";
Bernhard M. Wiedemanna40e06e2018-02-23 18:20:45 +0100604 my $y=$1;
605 $y+=100 if $y<70;
606 $y+=1900 if $y<1000;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200607 return timegm($6||0,$5,$4,$3,$2-1,$y);
608}
609
610sub pmode($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800611 my ($mode) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200612 my $m = 0;
613 my $mm = 0;
614 my $um = 0;
615 for my $x(split(//,$mode)) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800616 if ($x eq ",") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200617 $m |= $mm&$um;
618 $mm = 0;
619 $um = 0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800620 } elsif ($x eq "u") { $um |= 0700;
621 } elsif ($x eq "g") { $um |= 0070;
622 } elsif ($x eq "o") { $um |= 0007;
623 } elsif ($x eq "r") { $mm |= 0444;
624 } elsif ($x eq "w") { $mm |= 0222;
625 } elsif ($x eq "x") { $mm |= 0111;
626 } elsif ($x eq "=") { # do nothing
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200627 } else { die "Unknown mode: $mode\n";
628 }
629 }
630 $m |= $mm&$um;
631 return $m;
632}
633
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200634sub getwd() {
635 my $pwd = `pwd`;
636 chomp $pwd;
637 return $pwd;
638}
639
Jeff Kinge73aefe2006-05-23 03:27:46 -0400640sub is_sha1 {
641 my $s = shift;
642 return $s =~ /^[a-f0-9]{40}$/;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200643}
644
Jeff King9da0dab2007-11-28 13:56:11 -0500645sub get_headref ($) {
646 my $name = shift;
Jeff King8c87bdf2017-12-08 04:58:19 -0500647 $name =~ s/'/'\\''/g;
Jeff King9da0dab2007-11-28 13:56:11 -0500648 my $r = `git rev-parse --verify '$name' 2>/dev/null`;
649 return undef unless $? == 0;
650 chomp $r;
651 return $r;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400652}
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200653
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400654my $user_filename_prepend = '';
655sub munge_user_filename {
656 my $name = shift;
657 return File::Spec->file_name_is_absolute($name) ?
658 $name :
659 $user_filename_prepend . $name;
660}
661
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200662-d $git_tree
663 or mkdir($git_tree,0777)
664 or die "Could not create $git_tree: $!";
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400665if ($git_tree ne '.') {
666 $user_filename_prepend = getwd() . '/';
667 chdir($git_tree);
668}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200669
670my $last_branch = "";
Matthias Urlichs46541662005-06-28 21:08:15 +0200671my $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200672my %branch_date;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -0800673my $tip_at_start = undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200674
675my $git_dir = $ENV{"GIT_DIR"} || ".git";
676$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#;
677$ENV{"GIT_DIR"} = $git_dir;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +0200678my $orig_git_index;
679$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE};
Martin Langhoff8f732642006-06-12 23:50:49 +1200680
681my %index; # holds filenames of one index per branch
Johannes Schindelin061303f2006-06-24 21:42:20 +0200682
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800683unless (-d $git_dir) {
Ben Walton91fe7322010-01-19 14:03:10 -0500684 system(qw(git init));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200685 die "Cannot init the GIT db at $git_tree: $?\n" if $?;
Thomas Rast1bb28d82010-10-18 15:11:25 +0200686 system(qw(git read-tree --empty));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200687 die "Cannot init an empty tree: $?\n" if $?;
688
689 $last_branch = $opt_o;
Matthias Urlichs46541662005-06-28 21:08:15 +0200690 $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200691} else {
Ben Waltona12477d2010-01-19 14:03:09 -0500692 open(F, "-|", qw(git symbolic-ref HEAD)) or
Ben Walton640d9d02010-01-19 14:03:08 -0500693 die "Cannot run git symbolic-ref: $!\n";
Pavel Roskin8366a102005-11-16 13:27:28 -0500694 chomp ($last_branch = <F>);
695 $last_branch = basename($last_branch);
696 close(F);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800697 unless ($last_branch) {
Matthias Urlichs46541662005-06-28 21:08:15 +0200698 warn "Cannot read the last branch name: $! -- assuming 'master'\n";
699 $last_branch = "master";
700 }
701 $orig_branch = $last_branch;
Ben Walton640d9d02010-01-19 14:03:08 -0500702 $tip_at_start = `git rev-parse --verify HEAD`;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200703
704 # Get the last import timestamps
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100705 my $fmt = '($ref, $author) = (%(refname), %(author));';
Ben Waltona12477d2010-01-19 14:03:09 -0500706 my @cmd = ('git', 'for-each-ref', '--perl', "--format=$fmt", $remote);
707 open(H, "-|", @cmd) or die "Cannot run git for-each-ref: $!\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800708 while (defined(my $entry = <H>)) {
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100709 my ($ref, $author);
710 eval($entry) || die "cannot eval refs list: $@";
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100711 my ($head) = ($ref =~ m|^$remote/(.*)|);
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100712 $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
713 $branch_date{$head} = $1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200714 }
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100715 close(H);
Stephan Springl7ca055f2007-05-23 12:13:21 +0100716 if (!exists $branch_date{$opt_o}) {
717 die "Branch '$opt_o' does not exist.\n".
718 "Either use the correct '-o branch' option,\n".
719 "or import to a new repository.\n";
720 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200721}
722
723-d $git_dir
724 or die "Could not create git subdir ($git_dir).\n";
725
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100726# now we read (and possibly save) author-info as well
727-f "$git_dir/cvs-authors" and
728 read_author_info("$git_dir/cvs-authors");
729if ($opt_A) {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400730 read_author_info(munge_user_filename($opt_A));
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100731 write_author_info("$git_dir/cvs-authors");
732}
733
Aaron Crane0455ec02010-02-06 18:26:24 +0000734# open .git/cvs-revisions, if requested
735open my $revision_map, '>>', "$git_dir/cvs-revisions"
736 or die "Can't open $git_dir/cvs-revisions for appending: $!\n"
737 if defined $opt_R;
738
Martin Langhoff2f57c692006-06-11 20:12:20 +1200739
740#
741# run cvsps into a file unless we are getting
742# it passed as a file via $opt_P
743#
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300744my $cvspsfile;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200745unless ($opt_P) {
746 print "Running cvsps...\n" if $opt_v;
747 my $pid = open(CVSPS,"-|");
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300748 my $cvspsfh;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200749 die "Cannot fork: $!\n" unless defined $pid;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800750 unless ($pid) {
Martin Langhoff2f57c692006-06-11 20:12:20 +1200751 my @opt;
752 @opt = split(/,/,$opt_p) if defined $opt_p;
753 unshift @opt, '-z', $opt_z if defined $opt_z;
754 unshift @opt, '-q' unless defined $opt_v;
755 unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
756 push @opt, '--cvs-direct';
757 }
758 exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
759 die "Could not start cvsps: $!\n";
Martin Langhoffdf73e9c2005-10-11 21:57:04 -0700760 }
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300761 ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
762 DIR => File::Spec->tmpdir());
Martin Langhoff2f57c692006-06-11 20:12:20 +1200763 while (<CVSPS>) {
764 print $cvspsfh $_;
Martin Langhoff211dcac2005-11-02 13:48:47 +1300765 }
Martin Langhoff2f57c692006-06-11 20:12:20 +1200766 close CVSPS;
Ben Walton640d9d02010-01-19 14:03:08 -0500767 $? == 0 or die "git cvsimport: fatal: cvsps reported error\n";
Martin Langhoff2f57c692006-06-11 20:12:20 +1200768 close $cvspsfh;
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300769} else {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400770 $cvspsfile = munge_user_filename($opt_P);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200771}
772
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300773open(CVS, "<$cvspsfile") or die $!;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200774
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200775## cvsps output:
776#---------------------
777#PatchSet 314
778#Date: 1999/09/18 13:03:59
779#Author: wkoch
780#Branch: STABLE-BRANCH-1-0
781#Ancestor branch: HEAD
782#Tag: (none)
783#Log:
784# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch
785#Members:
786# README:1.57->1.57.2.1
787# VERSION:1.96->1.96.2.1
788#
789#---------------------
790
791my $state = 0;
792
Jeff Kinge73aefe2006-05-23 03:27:46 -0400793sub update_index (\@\@) {
794 my $old = shift;
795 my $new = shift;
Ben Walton640d9d02010-01-19 14:03:08 -0500796 open(my $fh, '|-', qw(git update-index -z --index-info))
797 or die "unable to open git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400798 print $fh
799 (map { "0 0000000000000000000000000000000000000000\t$_\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400800 @$old),
Jeff King6a1871e2006-05-23 03:27:45 -0400801 (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400802 @$new)
Ben Walton640d9d02010-01-19 14:03:08 -0500803 or die "unable to write to git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400804 close $fh
Ben Walton640d9d02010-01-19 14:03:08 -0500805 or die "unable to write to git update-index: $!";
806 $? and die "git update-index reported error: $?";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400807}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200808
Jeff Kinge73aefe2006-05-23 03:27:46 -0400809sub write_tree () {
Ben Waltona12477d2010-01-19 14:03:09 -0500810 open(my $fh, '-|', qw(git write-tree))
Ben Walton640d9d02010-01-19 14:03:08 -0500811 or die "unable to open git write-tree: $!";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400812 chomp(my $tree = <$fh>);
813 is_sha1($tree)
814 or die "Cannot get tree id ($tree): $!";
815 close($fh)
Ben Walton640d9d02010-01-19 14:03:08 -0500816 or die "Error running git write-tree: $?\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200817 print "Tree ID $tree\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400818 return $tree;
819}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200820
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500821my ($patchset,$date,$author_name,$author_email,$author_tz,$branch,$ancestor,$tag,$logmsg);
Aaron Crane0455ec02010-02-06 18:26:24 +0000822my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
Martin Langhoff71b08142006-06-11 20:12:09 +1200823
824# commits that cvsps cannot place anywhere...
825$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
826
Jeff Kinge73aefe2006-05-23 03:27:46 -0400827sub commit {
Jeff King9da0dab2007-11-28 13:56:11 -0500828 if ($branch eq $opt_o && !$index{branch} &&
829 !get_headref("$remote/$branch")) {
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200830 # looks like an initial commit
Ben Walton640d9d02010-01-19 14:03:08 -0500831 # use the index primed by git init
Michael Milligan23fcdc72007-06-05 00:06:30 -0600832 $ENV{GIT_INDEX_FILE} = "$git_dir/index";
833 $index{$branch} = "$git_dir/index";
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200834 } else {
835 # use an index per branch to speed up
836 # imports of projects with many branches
837 unless ($index{$branch}) {
838 $index{$branch} = tmpnam();
839 $ENV{GIT_INDEX_FILE} = $index{$branch};
840 if ($ancestor) {
Ben Walton640d9d02010-01-19 14:03:08 -0500841 system("git", "read-tree", "$remote/$ancestor");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200842 } else {
Ben Walton640d9d02010-01-19 14:03:08 -0500843 system("git", "read-tree", "$remote/$branch");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200844 }
845 die "read-tree failed: $?\n" if $?;
846 }
847 }
848 $ENV{GIT_INDEX_FILE} = $index{$branch};
849
Jeff Kinge73aefe2006-05-23 03:27:46 -0400850 update_index(@old, @new);
851 @old = @new = ();
852 my $tree = write_tree();
Jeff King9da0dab2007-11-28 13:56:11 -0500853 my $parent = get_headref("$remote/$last_branch");
Jeff Kinge73aefe2006-05-23 03:27:46 -0400854 print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200855
Jeff Kinge73aefe2006-05-23 03:27:46 -0400856 my @commit_args;
857 push @commit_args, ("-p", $parent) if $parent;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200858
Jeff Kinge73aefe2006-05-23 03:27:46 -0400859 # loose detection of merges
860 # based on the commit msg
861 foreach my $rx (@mergerx) {
862 next unless $logmsg =~ $rx && $1;
863 my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
Jeff King9da0dab2007-11-28 13:56:11 -0500864 if (my $sha1 = get_headref("$remote/$mparent")) {
Marc-Andre Lureauc36c5b82008-03-12 21:54:21 +0200865 push @commit_args, '-p', "$remote/$mparent";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400866 print "Merge parent branch: $mparent\n" if $opt_v;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200867 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200868 }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400869
Jeff Kingc2b3af02012-11-04 07:25:36 -0500870 set_timezone($author_tz);
Ben Walton48c91622013-02-09 21:46:58 +0000871 # $date is in the seconds since epoch format
872 my $tz_offset = get_tz_offset($date);
873 my $commit_date = "$date $tz_offset";
Jeff Kingc2b3af02012-11-04 07:25:36 -0500874 set_timezone('UTC');
Jeff King62bf0d92006-05-23 16:59:44 -0400875 $ENV{GIT_AUTHOR_NAME} = $author_name;
876 $ENV{GIT_AUTHOR_EMAIL} = $author_email;
877 $ENV{GIT_AUTHOR_DATE} = $commit_date;
878 $ENV{GIT_COMMITTER_NAME} = $author_name;
879 $ENV{GIT_COMMITTER_EMAIL} = $author_email;
880 $ENV{GIT_COMMITTER_DATE} = $commit_date;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400881 my $pid = open2(my $commit_read, my $commit_write,
Ben Walton640d9d02010-01-19 14:03:08 -0500882 'git', 'commit-tree', $tree, @commit_args);
Matthias Urlichse3710462005-06-30 22:09:42 +0200883
884 # compatibility with git2cvs
885 substr($logmsg,32767) = "" if length($logmsg) > 32767;
886 $logmsg =~ s/[\s\n]+\z//;
887
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300888 if (@skipped) {
889 $logmsg .= "\n\n\nSKIPPED:\n\t";
890 $logmsg .= join("\n\t", @skipped) . "\n";
Martin Langhofff396f012006-05-23 00:45:47 +1200891 @skipped = ();
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300892 }
893
Jeff Kinge73aefe2006-05-23 03:27:46 -0400894 print($commit_write "$logmsg\n") && close($commit_write)
Ben Walton640d9d02010-01-19 14:03:08 -0500895 or die "Error writing to git commit-tree: $!\n";
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200896
Jeff Kinge73aefe2006-05-23 03:27:46 -0400897 print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
898 chomp(my $cid = <$commit_read>);
899 is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200900 print "Commit ID $cid\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400901 close($commit_read);
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200902
903 waitpid($pid,0);
Ben Walton640d9d02010-01-19 14:03:08 -0500904 die "Error running git commit-tree: $?\n" if $?;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200905
Ben Walton640d9d02010-01-19 14:03:08 -0500906 system('git' , 'update-ref', "$remote/$branch", $cid) == 0
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200907 or die "Cannot write branch $branch for update: $!\n";
908
Aaron Crane0455ec02010-02-06 18:26:24 +0000909 if ($revision_map) {
910 print $revision_map "@$_ $cid\n" for @commit_revisions;
911 }
912 @commit_revisions = ();
913
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800914 if ($tag) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800915 my ($xtag) = $tag;
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700916 $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
917 $xtag =~ tr/_/\./ if ( $opt_u );
Joe English34c99da2006-01-06 12:52:27 -0800918 $xtag =~ s/[\/]/$opt_s/g;
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700919
Ken Dreyer70b67b02012-09-06 10:36:53 -0600920 # See refs.c for these rules.
921 # Tag cannot contain bad chars. (See bad_ref_char in refs.c.)
922 $xtag =~ s/[ ~\^:\\\*\?\[]//g;
923 # Other bad strings for tags:
924 # (See check_refname_component in refs.c.)
925 1 while $xtag =~ s/
926 (?: \.\. # Tag cannot contain '..'.
Christian Neukirchen16272c72015-06-24 16:04:20 +0200927 | \@\{ # Tag cannot contain '@{'.
Ken Dreyer70b67b02012-09-06 10:36:53 -0600928 | ^ - # Tag cannot begin with '-'.
929 | \.lock $ # Tag cannot end with '.lock'.
930 | ^ \. # Tag cannot begin...
931 | \. $ # ...or end with '.'
932 )//xg;
933 # Tag cannot be empty.
934 if ($xtag eq '') {
935 warn("warning: ignoring tag '$tag'",
936 " with invalid tagname\n");
937 return;
938 }
939
940 if (system('git' , 'tag', '-f', $xtag, $cid) != 0) {
941 # We did our best to sanitize the tag, but still failed
942 # for whatever reason. Bail out, and give the user
943 # enough information to understand if/how we should
944 # improve the translation in the future.
945 if ($tag ne $xtag) {
946 print "Translated '$tag' tag to '$xtag'\n";
947 }
948 die "Cannot create tag $xtag: $!\n";
949 }
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700950
951 print "Created tag '$xtag' on '$branch'\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200952 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200953};
954
Martin Langhoff06918342006-05-22 23:38:08 +1200955my $commitcount = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800956while (<CVS>) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200957 chomp;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800958 if ($state == 0 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200959 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800960 } elsif ($state == 0) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200961 $state = 1;
962 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800963 } elsif (($state==0 or $state==1) and s/^PatchSet\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200964 $patchset = 0+$_;
965 $state=2;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800966 } elsif ($state == 2 and s/^Date:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200967 $date = pdate($_);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800968 unless ($date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200969 print STDERR "Could not parse date: $_\n";
970 $state=0;
971 next;
972 }
973 $state=3;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800974 } elsif ($state == 3 and s/^Author:\s+//) {
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500975 $author_tz = "UTC";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200976 s/\s+$//;
Junio C Hamano94c23342005-09-30 01:48:57 -0700977 if (/^(.*?)\s+<(.*)>/) {
978 ($author_name, $author_email) = ($1, $2);
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100979 } elsif ($conv_author_name{$_}) {
980 $author_name = $conv_author_name{$_};
981 $author_email = $conv_author_email{$_};
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500982 $author_tz = $conv_author_tz{$_} if ($conv_author_tz{$_});
Junio C Hamano94c23342005-09-30 01:48:57 -0700983 } else {
984 $author_name = $author_email = $_;
985 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200986 $state = 4;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800987 } elsif ($state == 4 and s/^Branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200988 s/\s+$//;
Gerrit Papea0554222007-11-03 11:55:02 +0000989 tr/_/\./ if ( $opt_u );
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200990 s/[\/]/$opt_s/g;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200991 $branch = $_;
992 $state = 5;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800993 } elsif ($state == 5 and s/^Ancestor branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200994 s/\s+$//;
995 $ancestor = $_;
Sven Verdoolaege0fa28242005-06-30 17:23:22 +0200996 $ancestor = $opt_o if $ancestor eq "HEAD";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200997 $state = 6;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800998 } elsif ($state == 5) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200999 $ancestor = undef;
1000 $state = 6;
1001 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001002 } elsif ($state == 6 and s/^Tag:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001003 s/\s+$//;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001004 if ($_ eq "(none)") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001005 $tag = undef;
1006 } else {
1007 $tag = $_;
1008 }
1009 $state = 7;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001010 } elsif ($state == 7 and /^Log:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001011 $logmsg = "";
1012 $state = 8;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001013 } elsif ($state == 8 and /^Members:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001014 $branch = $opt_o if $branch eq "HEAD";
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001015 if (defined $branch_date{$branch} and $branch_date{$branch} >= $date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001016 # skip
Matthias Urlichs9da07f32005-07-03 19:03:30 +02001017 print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001018 $state = 11;
1019 next;
1020 }
Martin Langhoffded9f402007-01-08 19:43:39 +13001021 if (!$opt_a && $starttime - 300 - (defined $opt_z ? $opt_z : 300) <= $date) {
Martin Langhoff62119882007-01-08 14:11:23 +13001022 # skip if the commit is too recent
Stefan Sperling77190eb2007-12-21 16:57:26 +01001023 # given that the cvsps default fuzz is 300s, we give ourselves another
Martin Langhoff62119882007-01-08 14:11:23 +13001024 # 300s just in case -- this also prevents skipping commits
1025 # due to server clock drift
1026 print "skip patchset $patchset: $date too recent\n" if $opt_v;
1027 $state = 11;
1028 next;
1029 }
Martin Langhoff71b08142006-06-11 20:12:09 +12001030 if (exists $ignorebranch{$branch}) {
1031 print STDERR "Skipping $branch\n";
1032 $state = 11;
1033 next;
1034 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001035 if ($ancestor) {
1036 if ($ancestor eq $branch) {
Martin Langhoff71b08142006-06-11 20:12:09 +12001037 print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
1038 $ancestor = $opt_o;
1039 }
Jeff King0750d752007-11-28 13:56:28 -05001040 if (defined get_headref("$remote/$branch")) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001041 print STDERR "Branch $branch already exists!\n";
1042 $state=11;
1043 next;
1044 }
Jeff King0750d752007-11-28 13:56:28 -05001045 my $id = get_headref("$remote/$ancestor");
1046 if (!$id) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001047 print STDERR "Branch $ancestor does not exist!\n";
Martin Langhoff71b08142006-06-11 20:12:09 +12001048 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001049 $state=11;
1050 next;
1051 }
Jeff King0750d752007-11-28 13:56:28 -05001052
1053 system(qw(git update-ref -m cvsimport),
1054 "$remote/$branch", $id);
1055 if($? != 0) {
1056 print STDERR "Could not create branch $branch\n";
Martin Langhoff71b08142006-06-11 20:12:09 +12001057 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001058 $state=11;
1059 next;
1060 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001061 }
Sven Verdoolaege46e63ef2005-07-04 15:28:36 +02001062 $last_branch = $branch if $branch ne $last_branch;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001063 $state = 9;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001064 } elsif ($state == 8) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001065 $logmsg .= "$_\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001066 } elsif ($state == 9 and /^\s+(.+?):(INITIAL|\d+(?:\.\d+)+)->(\d+(?:\.\d+)+)\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001067# VERSION:1.96->1.96.2.1
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +02001068 my $init = ($2 eq "INITIAL");
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001069 my $fn = $1;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001070 my $rev = $3;
1071 $fn =~ s#^/+##;
Martin Langhoff5179c8a2006-01-30 19:12:41 +13001072 if ($opt_S && $fn =~ m/$opt_S/) {
1073 print "SKIPPING $fn v $rev\n";
1074 push(@skipped, $fn);
1075 next;
1076 }
Aaron Crane0455ec02010-02-06 18:26:24 +00001077 push @commit_revisions, [$fn, $rev];
Martin Langhoff5179c8a2006-01-30 19:12:41 +13001078 print "Fetching $fn v $rev\n" if $opt_v;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001079 my ($tmpname, $size) = $cvs->file($fn,$rev);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001080 if ($size == -1) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001081 push(@old,$fn);
1082 print "Drop $fn\n" if $opt_v;
1083 } else {
1084 print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
Junio C Hamanodd274782006-02-20 14:17:28 -08001085 my $pid = open(my $F, '-|');
1086 die $! unless defined $pid;
1087 if (!$pid) {
Ben Walton640d9d02010-01-19 14:03:08 -05001088 exec("git", "hash-object", "-w", $tmpname)
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001089 or die "Cannot create object: $!\n";
Junio C Hamanodd274782006-02-20 14:17:28 -08001090 }
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001091 my $sha = <$F>;
1092 chomp $sha;
1093 close $F;
1094 my $mode = pmode($cvs->{'mode'});
1095 push(@new,[$mode, $sha, $fn]); # may be resurrected!
1096 }
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001097 unlink($tmpname);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001098 } elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001099 my $fn = $1;
Aaron Crane0455ec02010-02-06 18:26:24 +00001100 my $rev = $2;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001101 $fn =~ s#^/+##;
Aaron Crane0455ec02010-02-06 18:26:24 +00001102 push @commit_revisions, [$fn, $rev];
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001103 push(@old,$fn);
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001104 print "Delete $fn\n" if $opt_v;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001105 } elsif ($state == 9 and /^\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001106 $state = 10;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001107 } elsif (($state == 9 or $state == 10) and /^-+$/) {
Linus Torvalds4adcea92006-05-22 19:28:37 -07001108 $commitcount++;
1109 if ($opt_L && $commitcount > $opt_L) {
Martin Langhoff06918342006-05-22 23:38:08 +12001110 last;
1111 }
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001112 commit();
Linus Torvalds4adcea92006-05-22 19:28:37 -07001113 if (($commitcount & 1023) == 0) {
Ben Walton91fe7322010-01-19 14:03:10 -05001114 system(qw(git repack -a -d));
Linus Torvalds4adcea92006-05-22 19:28:37 -07001115 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001116 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001117 } elsif ($state == 11 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001118 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001119 } elsif (/^-+$/) { # end of unknown-line processing
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001120 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001121 } elsif ($state != 11) { # ignore stuff when skipping
Jim Meyering3be39992008-08-05 16:54:42 +02001122 print STDERR "* UNKNOWN LINE * $_\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001123 }
1124}
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001125commit() if $branch and $state != 11;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001126
Martin Langhoff4083c2f2007-01-08 21:08:46 +13001127unless ($opt_P) {
1128 unlink($cvspsfile);
1129}
1130
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001131# The heuristic of repacking every 1024 commits can leave a
1132# lot of unpacked data. If there is more than 1MB worth of
1133# not-packed objects, repack once more.
Ben Walton640d9d02010-01-19 14:03:08 -05001134my $line = `git count-objects`;
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001135if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) {
1136 my ($n_objects, $kb) = ($1, $2);
1137 1024 < $kb
Ben Walton91fe7322010-01-19 14:03:10 -05001138 and system(qw(git repack -a -d));
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001139}
1140
Martin Langhoff8f732642006-06-12 23:50:49 +12001141foreach my $git_index (values %index) {
Michael Milligan23fcdc72007-06-05 00:06:30 -06001142 if ($git_index ne "$git_dir/index") {
Martin Langhoffc5f448b2006-06-28 22:13:23 +12001143 unlink($git_index);
1144 }
Martin Langhoff8f732642006-06-12 23:50:49 +12001145}
Sven Verdoolaege79ee4562005-07-04 13:36:59 +02001146
Sven Verdoolaege210569f2005-07-05 13:19:59 +02001147if (defined $orig_git_index) {
1148 $ENV{GIT_INDEX_FILE} = $orig_git_index;
1149} else {
1150 delete $ENV{GIT_INDEX_FILE};
1151}
1152
Matthias Urlichs46541662005-06-28 21:08:15 +02001153# Now switch back to the branch we were in before all of this happened
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001154if ($orig_branch) {
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001155 print "DONE.\n" if $opt_v;
1156 if ($opt_i) {
1157 exit 0;
1158 }
Ben Walton640d9d02010-01-19 14:03:08 -05001159 my $tip_at_end = `git rev-parse --verify HEAD`;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001160 if ($tip_at_start ne $tip_at_end) {
Junio C Hamanocb9594e2006-03-18 02:05:02 -08001161 for ($tip_at_start, $tip_at_end) { chomp; }
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001162 print "Fetched into the current branch.\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001163 system(qw(git read-tree -u -m),
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001164 $tip_at_start, $tip_at_end);
1165 die "Fast-forward update failed: $?\n" if $?;
1166 }
1167 else {
Junio C Hamanod45366e2015-03-25 21:58:45 -07001168 system(qw(git merge -m cvsimport), "$remote/$opt_o");
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001169 die "Could not merge $opt_o into the current branch.\n" if $?;
1170 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001171} else {
1172 $orig_branch = "master";
1173 print "DONE; creating $orig_branch branch\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001174 system("git", "update-ref", "refs/heads/master", "$remote/$opt_o")
Jeff King0750d752007-11-28 13:56:28 -05001175 unless defined get_headref('refs/heads/master');
Ben Walton640d9d02010-01-19 14:03:08 -05001176 system("git", "symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
Andy Whitcroft06baffd2007-06-04 10:01:49 +01001177 if ($opt_r && $opt_o ne 'HEAD');
Ben Walton640d9d02010-01-19 14:03:08 -05001178 system('git', 'update-ref', 'HEAD', "$orig_branch");
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001179 unless ($opt_i) {
Ben Walton91fe7322010-01-19 14:03:10 -05001180 system(qw(git checkout -f));
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001181 die "checkout failed: $?\n" if $?;
1182 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001183}