blob: 1e4e65a45d16cfcc5a36e6855216e9be8fe0e0b4 [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";
604 my $y=$1; $y-=1900 if $y>1900;
605 return timegm($6||0,$5,$4,$3,$2-1,$y);
606}
607
608sub pmode($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800609 my ($mode) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200610 my $m = 0;
611 my $mm = 0;
612 my $um = 0;
613 for my $x(split(//,$mode)) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800614 if ($x eq ",") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200615 $m |= $mm&$um;
616 $mm = 0;
617 $um = 0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800618 } elsif ($x eq "u") { $um |= 0700;
619 } elsif ($x eq "g") { $um |= 0070;
620 } elsif ($x eq "o") { $um |= 0007;
621 } elsif ($x eq "r") { $mm |= 0444;
622 } elsif ($x eq "w") { $mm |= 0222;
623 } elsif ($x eq "x") { $mm |= 0111;
624 } elsif ($x eq "=") { # do nothing
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200625 } else { die "Unknown mode: $mode\n";
626 }
627 }
628 $m |= $mm&$um;
629 return $m;
630}
631
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200632sub getwd() {
633 my $pwd = `pwd`;
634 chomp $pwd;
635 return $pwd;
636}
637
Jeff Kinge73aefe2006-05-23 03:27:46 -0400638sub is_sha1 {
639 my $s = shift;
640 return $s =~ /^[a-f0-9]{40}$/;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200641}
642
Jeff King9da0dab2007-11-28 13:56:11 -0500643sub get_headref ($) {
644 my $name = shift;
645 my $r = `git rev-parse --verify '$name' 2>/dev/null`;
646 return undef unless $? == 0;
647 chomp $r;
648 return $r;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400649}
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200650
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400651my $user_filename_prepend = '';
652sub munge_user_filename {
653 my $name = shift;
654 return File::Spec->file_name_is_absolute($name) ?
655 $name :
656 $user_filename_prepend . $name;
657}
658
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200659-d $git_tree
660 or mkdir($git_tree,0777)
661 or die "Could not create $git_tree: $!";
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400662if ($git_tree ne '.') {
663 $user_filename_prepend = getwd() . '/';
664 chdir($git_tree);
665}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200666
667my $last_branch = "";
Matthias Urlichs46541662005-06-28 21:08:15 +0200668my $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200669my %branch_date;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -0800670my $tip_at_start = undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200671
672my $git_dir = $ENV{"GIT_DIR"} || ".git";
673$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#;
674$ENV{"GIT_DIR"} = $git_dir;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +0200675my $orig_git_index;
676$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE};
Martin Langhoff8f732642006-06-12 23:50:49 +1200677
678my %index; # holds filenames of one index per branch
Johannes Schindelin061303f2006-06-24 21:42:20 +0200679
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800680unless (-d $git_dir) {
Ben Walton91fe7322010-01-19 14:03:10 -0500681 system(qw(git init));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200682 die "Cannot init the GIT db at $git_tree: $?\n" if $?;
Thomas Rast1bb28d82010-10-18 15:11:25 +0200683 system(qw(git read-tree --empty));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200684 die "Cannot init an empty tree: $?\n" if $?;
685
686 $last_branch = $opt_o;
Matthias Urlichs46541662005-06-28 21:08:15 +0200687 $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200688} else {
Ben Waltona12477d2010-01-19 14:03:09 -0500689 open(F, "-|", qw(git symbolic-ref HEAD)) or
Ben Walton640d9d02010-01-19 14:03:08 -0500690 die "Cannot run git symbolic-ref: $!\n";
Pavel Roskin8366a102005-11-16 13:27:28 -0500691 chomp ($last_branch = <F>);
692 $last_branch = basename($last_branch);
693 close(F);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800694 unless ($last_branch) {
Matthias Urlichs46541662005-06-28 21:08:15 +0200695 warn "Cannot read the last branch name: $! -- assuming 'master'\n";
696 $last_branch = "master";
697 }
698 $orig_branch = $last_branch;
Ben Walton640d9d02010-01-19 14:03:08 -0500699 $tip_at_start = `git rev-parse --verify HEAD`;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200700
701 # Get the last import timestamps
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100702 my $fmt = '($ref, $author) = (%(refname), %(author));';
Ben Waltona12477d2010-01-19 14:03:09 -0500703 my @cmd = ('git', 'for-each-ref', '--perl', "--format=$fmt", $remote);
704 open(H, "-|", @cmd) or die "Cannot run git for-each-ref: $!\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800705 while (defined(my $entry = <H>)) {
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100706 my ($ref, $author);
707 eval($entry) || die "cannot eval refs list: $@";
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100708 my ($head) = ($ref =~ m|^$remote/(.*)|);
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100709 $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
710 $branch_date{$head} = $1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200711 }
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100712 close(H);
Stephan Springl7ca055f2007-05-23 12:13:21 +0100713 if (!exists $branch_date{$opt_o}) {
714 die "Branch '$opt_o' does not exist.\n".
715 "Either use the correct '-o branch' option,\n".
716 "or import to a new repository.\n";
717 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200718}
719
720-d $git_dir
721 or die "Could not create git subdir ($git_dir).\n";
722
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100723# now we read (and possibly save) author-info as well
724-f "$git_dir/cvs-authors" and
725 read_author_info("$git_dir/cvs-authors");
726if ($opt_A) {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400727 read_author_info(munge_user_filename($opt_A));
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100728 write_author_info("$git_dir/cvs-authors");
729}
730
Aaron Crane0455ec02010-02-06 18:26:24 +0000731# open .git/cvs-revisions, if requested
732open my $revision_map, '>>', "$git_dir/cvs-revisions"
733 or die "Can't open $git_dir/cvs-revisions for appending: $!\n"
734 if defined $opt_R;
735
Martin Langhoff2f57c692006-06-11 20:12:20 +1200736
737#
738# run cvsps into a file unless we are getting
739# it passed as a file via $opt_P
740#
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300741my $cvspsfile;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200742unless ($opt_P) {
743 print "Running cvsps...\n" if $opt_v;
744 my $pid = open(CVSPS,"-|");
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300745 my $cvspsfh;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200746 die "Cannot fork: $!\n" unless defined $pid;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800747 unless ($pid) {
Martin Langhoff2f57c692006-06-11 20:12:20 +1200748 my @opt;
749 @opt = split(/,/,$opt_p) if defined $opt_p;
750 unshift @opt, '-z', $opt_z if defined $opt_z;
751 unshift @opt, '-q' unless defined $opt_v;
752 unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
753 push @opt, '--cvs-direct';
754 }
755 exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
756 die "Could not start cvsps: $!\n";
Martin Langhoffdf73e9c2005-10-11 21:57:04 -0700757 }
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300758 ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
759 DIR => File::Spec->tmpdir());
Martin Langhoff2f57c692006-06-11 20:12:20 +1200760 while (<CVSPS>) {
761 print $cvspsfh $_;
Martin Langhoff211dcac2005-11-02 13:48:47 +1300762 }
Martin Langhoff2f57c692006-06-11 20:12:20 +1200763 close CVSPS;
Ben Walton640d9d02010-01-19 14:03:08 -0500764 $? == 0 or die "git cvsimport: fatal: cvsps reported error\n";
Martin Langhoff2f57c692006-06-11 20:12:20 +1200765 close $cvspsfh;
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300766} else {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400767 $cvspsfile = munge_user_filename($opt_P);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200768}
769
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300770open(CVS, "<$cvspsfile") or die $!;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200771
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200772## cvsps output:
773#---------------------
774#PatchSet 314
775#Date: 1999/09/18 13:03:59
776#Author: wkoch
777#Branch: STABLE-BRANCH-1-0
778#Ancestor branch: HEAD
779#Tag: (none)
780#Log:
781# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch
782#Members:
783# README:1.57->1.57.2.1
784# VERSION:1.96->1.96.2.1
785#
786#---------------------
787
788my $state = 0;
789
Jeff Kinge73aefe2006-05-23 03:27:46 -0400790sub update_index (\@\@) {
791 my $old = shift;
792 my $new = shift;
Ben Walton640d9d02010-01-19 14:03:08 -0500793 open(my $fh, '|-', qw(git update-index -z --index-info))
794 or die "unable to open git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400795 print $fh
796 (map { "0 0000000000000000000000000000000000000000\t$_\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400797 @$old),
Jeff King6a1871e2006-05-23 03:27:45 -0400798 (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400799 @$new)
Ben Walton640d9d02010-01-19 14:03:08 -0500800 or die "unable to write to git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400801 close $fh
Ben Walton640d9d02010-01-19 14:03:08 -0500802 or die "unable to write to git update-index: $!";
803 $? and die "git update-index reported error: $?";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400804}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200805
Jeff Kinge73aefe2006-05-23 03:27:46 -0400806sub write_tree () {
Ben Waltona12477d2010-01-19 14:03:09 -0500807 open(my $fh, '-|', qw(git write-tree))
Ben Walton640d9d02010-01-19 14:03:08 -0500808 or die "unable to open git write-tree: $!";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400809 chomp(my $tree = <$fh>);
810 is_sha1($tree)
811 or die "Cannot get tree id ($tree): $!";
812 close($fh)
Ben Walton640d9d02010-01-19 14:03:08 -0500813 or die "Error running git write-tree: $?\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200814 print "Tree ID $tree\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400815 return $tree;
816}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200817
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500818my ($patchset,$date,$author_name,$author_email,$author_tz,$branch,$ancestor,$tag,$logmsg);
Aaron Crane0455ec02010-02-06 18:26:24 +0000819my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
Martin Langhoff71b08142006-06-11 20:12:09 +1200820
821# commits that cvsps cannot place anywhere...
822$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
823
Jeff Kinge73aefe2006-05-23 03:27:46 -0400824sub commit {
Jeff King9da0dab2007-11-28 13:56:11 -0500825 if ($branch eq $opt_o && !$index{branch} &&
826 !get_headref("$remote/$branch")) {
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200827 # looks like an initial commit
Ben Walton640d9d02010-01-19 14:03:08 -0500828 # use the index primed by git init
Michael Milligan23fcdc72007-06-05 00:06:30 -0600829 $ENV{GIT_INDEX_FILE} = "$git_dir/index";
830 $index{$branch} = "$git_dir/index";
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200831 } else {
832 # use an index per branch to speed up
833 # imports of projects with many branches
834 unless ($index{$branch}) {
835 $index{$branch} = tmpnam();
836 $ENV{GIT_INDEX_FILE} = $index{$branch};
837 if ($ancestor) {
Ben Walton640d9d02010-01-19 14:03:08 -0500838 system("git", "read-tree", "$remote/$ancestor");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200839 } else {
Ben Walton640d9d02010-01-19 14:03:08 -0500840 system("git", "read-tree", "$remote/$branch");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200841 }
842 die "read-tree failed: $?\n" if $?;
843 }
844 }
845 $ENV{GIT_INDEX_FILE} = $index{$branch};
846
Jeff Kinge73aefe2006-05-23 03:27:46 -0400847 update_index(@old, @new);
848 @old = @new = ();
849 my $tree = write_tree();
Jeff King9da0dab2007-11-28 13:56:11 -0500850 my $parent = get_headref("$remote/$last_branch");
Jeff Kinge73aefe2006-05-23 03:27:46 -0400851 print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200852
Jeff Kinge73aefe2006-05-23 03:27:46 -0400853 my @commit_args;
854 push @commit_args, ("-p", $parent) if $parent;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200855
Jeff Kinge73aefe2006-05-23 03:27:46 -0400856 # loose detection of merges
857 # based on the commit msg
858 foreach my $rx (@mergerx) {
859 next unless $logmsg =~ $rx && $1;
860 my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
Jeff King9da0dab2007-11-28 13:56:11 -0500861 if (my $sha1 = get_headref("$remote/$mparent")) {
Marc-Andre Lureauc36c5b82008-03-12 21:54:21 +0200862 push @commit_args, '-p', "$remote/$mparent";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400863 print "Merge parent branch: $mparent\n" if $opt_v;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200864 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200865 }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400866
Jeff Kingc2b3af02012-11-04 07:25:36 -0500867 set_timezone($author_tz);
Ben Walton48c91622013-02-09 21:46:58 +0000868 # $date is in the seconds since epoch format
869 my $tz_offset = get_tz_offset($date);
870 my $commit_date = "$date $tz_offset";
Jeff Kingc2b3af02012-11-04 07:25:36 -0500871 set_timezone('UTC');
Jeff King62bf0d92006-05-23 16:59:44 -0400872 $ENV{GIT_AUTHOR_NAME} = $author_name;
873 $ENV{GIT_AUTHOR_EMAIL} = $author_email;
874 $ENV{GIT_AUTHOR_DATE} = $commit_date;
875 $ENV{GIT_COMMITTER_NAME} = $author_name;
876 $ENV{GIT_COMMITTER_EMAIL} = $author_email;
877 $ENV{GIT_COMMITTER_DATE} = $commit_date;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400878 my $pid = open2(my $commit_read, my $commit_write,
Ben Walton640d9d02010-01-19 14:03:08 -0500879 'git', 'commit-tree', $tree, @commit_args);
Matthias Urlichse3710462005-06-30 22:09:42 +0200880
881 # compatibility with git2cvs
882 substr($logmsg,32767) = "" if length($logmsg) > 32767;
883 $logmsg =~ s/[\s\n]+\z//;
884
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300885 if (@skipped) {
886 $logmsg .= "\n\n\nSKIPPED:\n\t";
887 $logmsg .= join("\n\t", @skipped) . "\n";
Martin Langhofff396f012006-05-23 00:45:47 +1200888 @skipped = ();
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300889 }
890
Jeff Kinge73aefe2006-05-23 03:27:46 -0400891 print($commit_write "$logmsg\n") && close($commit_write)
Ben Walton640d9d02010-01-19 14:03:08 -0500892 or die "Error writing to git commit-tree: $!\n";
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200893
Jeff Kinge73aefe2006-05-23 03:27:46 -0400894 print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
895 chomp(my $cid = <$commit_read>);
896 is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200897 print "Commit ID $cid\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400898 close($commit_read);
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200899
900 waitpid($pid,0);
Ben Walton640d9d02010-01-19 14:03:08 -0500901 die "Error running git commit-tree: $?\n" if $?;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200902
Ben Walton640d9d02010-01-19 14:03:08 -0500903 system('git' , 'update-ref', "$remote/$branch", $cid) == 0
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200904 or die "Cannot write branch $branch for update: $!\n";
905
Aaron Crane0455ec02010-02-06 18:26:24 +0000906 if ($revision_map) {
907 print $revision_map "@$_ $cid\n" for @commit_revisions;
908 }
909 @commit_revisions = ();
910
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800911 if ($tag) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800912 my ($xtag) = $tag;
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700913 $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
914 $xtag =~ tr/_/\./ if ( $opt_u );
Joe English34c99da2006-01-06 12:52:27 -0800915 $xtag =~ s/[\/]/$opt_s/g;
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700916
Ken Dreyer70b67b02012-09-06 10:36:53 -0600917 # See refs.c for these rules.
918 # Tag cannot contain bad chars. (See bad_ref_char in refs.c.)
919 $xtag =~ s/[ ~\^:\\\*\?\[]//g;
920 # Other bad strings for tags:
921 # (See check_refname_component in refs.c.)
922 1 while $xtag =~ s/
923 (?: \.\. # Tag cannot contain '..'.
Christian Neukirchen16272c72015-06-24 16:04:20 +0200924 | \@\{ # Tag cannot contain '@{'.
Ken Dreyer70b67b02012-09-06 10:36:53 -0600925 | ^ - # Tag cannot begin with '-'.
926 | \.lock $ # Tag cannot end with '.lock'.
927 | ^ \. # Tag cannot begin...
928 | \. $ # ...or end with '.'
929 )//xg;
930 # Tag cannot be empty.
931 if ($xtag eq '') {
932 warn("warning: ignoring tag '$tag'",
933 " with invalid tagname\n");
934 return;
935 }
936
937 if (system('git' , 'tag', '-f', $xtag, $cid) != 0) {
938 # We did our best to sanitize the tag, but still failed
939 # for whatever reason. Bail out, and give the user
940 # enough information to understand if/how we should
941 # improve the translation in the future.
942 if ($tag ne $xtag) {
943 print "Translated '$tag' tag to '$xtag'\n";
944 }
945 die "Cannot create tag $xtag: $!\n";
946 }
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700947
948 print "Created tag '$xtag' on '$branch'\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200949 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200950};
951
Martin Langhoff06918342006-05-22 23:38:08 +1200952my $commitcount = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800953while (<CVS>) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200954 chomp;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800955 if ($state == 0 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200956 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800957 } elsif ($state == 0) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200958 $state = 1;
959 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800960 } elsif (($state==0 or $state==1) and s/^PatchSet\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200961 $patchset = 0+$_;
962 $state=2;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800963 } elsif ($state == 2 and s/^Date:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200964 $date = pdate($_);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800965 unless ($date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200966 print STDERR "Could not parse date: $_\n";
967 $state=0;
968 next;
969 }
970 $state=3;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800971 } elsif ($state == 3 and s/^Author:\s+//) {
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500972 $author_tz = "UTC";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200973 s/\s+$//;
Junio C Hamano94c23342005-09-30 01:48:57 -0700974 if (/^(.*?)\s+<(.*)>/) {
975 ($author_name, $author_email) = ($1, $2);
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100976 } elsif ($conv_author_name{$_}) {
977 $author_name = $conv_author_name{$_};
978 $author_email = $conv_author_email{$_};
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500979 $author_tz = $conv_author_tz{$_} if ($conv_author_tz{$_});
Junio C Hamano94c23342005-09-30 01:48:57 -0700980 } else {
981 $author_name = $author_email = $_;
982 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200983 $state = 4;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800984 } elsif ($state == 4 and s/^Branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200985 s/\s+$//;
Gerrit Papea0554222007-11-03 11:55:02 +0000986 tr/_/\./ if ( $opt_u );
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200987 s/[\/]/$opt_s/g;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200988 $branch = $_;
989 $state = 5;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800990 } elsif ($state == 5 and s/^Ancestor branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200991 s/\s+$//;
992 $ancestor = $_;
Sven Verdoolaege0fa28242005-06-30 17:23:22 +0200993 $ancestor = $opt_o if $ancestor eq "HEAD";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200994 $state = 6;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800995 } elsif ($state == 5) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200996 $ancestor = undef;
997 $state = 6;
998 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800999 } elsif ($state == 6 and s/^Tag:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001000 s/\s+$//;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001001 if ($_ eq "(none)") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001002 $tag = undef;
1003 } else {
1004 $tag = $_;
1005 }
1006 $state = 7;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001007 } elsif ($state == 7 and /^Log:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001008 $logmsg = "";
1009 $state = 8;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001010 } elsif ($state == 8 and /^Members:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001011 $branch = $opt_o if $branch eq "HEAD";
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001012 if (defined $branch_date{$branch} and $branch_date{$branch} >= $date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001013 # skip
Matthias Urlichs9da07f32005-07-03 19:03:30 +02001014 print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001015 $state = 11;
1016 next;
1017 }
Martin Langhoffded9f402007-01-08 19:43:39 +13001018 if (!$opt_a && $starttime - 300 - (defined $opt_z ? $opt_z : 300) <= $date) {
Martin Langhoff62119882007-01-08 14:11:23 +13001019 # skip if the commit is too recent
Stefan Sperling77190eb2007-12-21 16:57:26 +01001020 # given that the cvsps default fuzz is 300s, we give ourselves another
Martin Langhoff62119882007-01-08 14:11:23 +13001021 # 300s just in case -- this also prevents skipping commits
1022 # due to server clock drift
1023 print "skip patchset $patchset: $date too recent\n" if $opt_v;
1024 $state = 11;
1025 next;
1026 }
Martin Langhoff71b08142006-06-11 20:12:09 +12001027 if (exists $ignorebranch{$branch}) {
1028 print STDERR "Skipping $branch\n";
1029 $state = 11;
1030 next;
1031 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001032 if ($ancestor) {
1033 if ($ancestor eq $branch) {
Martin Langhoff71b08142006-06-11 20:12:09 +12001034 print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
1035 $ancestor = $opt_o;
1036 }
Jeff King0750d752007-11-28 13:56:28 -05001037 if (defined get_headref("$remote/$branch")) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001038 print STDERR "Branch $branch already exists!\n";
1039 $state=11;
1040 next;
1041 }
Jeff King0750d752007-11-28 13:56:28 -05001042 my $id = get_headref("$remote/$ancestor");
1043 if (!$id) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001044 print STDERR "Branch $ancestor does not exist!\n";
Martin Langhoff71b08142006-06-11 20:12:09 +12001045 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001046 $state=11;
1047 next;
1048 }
Jeff King0750d752007-11-28 13:56:28 -05001049
1050 system(qw(git update-ref -m cvsimport),
1051 "$remote/$branch", $id);
1052 if($? != 0) {
1053 print STDERR "Could not create branch $branch\n";
Martin Langhoff71b08142006-06-11 20:12:09 +12001054 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001055 $state=11;
1056 next;
1057 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001058 }
Sven Verdoolaege46e63ef2005-07-04 15:28:36 +02001059 $last_branch = $branch if $branch ne $last_branch;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001060 $state = 9;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001061 } elsif ($state == 8) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001062 $logmsg .= "$_\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001063 } elsif ($state == 9 and /^\s+(.+?):(INITIAL|\d+(?:\.\d+)+)->(\d+(?:\.\d+)+)\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001064# VERSION:1.96->1.96.2.1
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +02001065 my $init = ($2 eq "INITIAL");
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001066 my $fn = $1;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001067 my $rev = $3;
1068 $fn =~ s#^/+##;
Martin Langhoff5179c8a2006-01-30 19:12:41 +13001069 if ($opt_S && $fn =~ m/$opt_S/) {
1070 print "SKIPPING $fn v $rev\n";
1071 push(@skipped, $fn);
1072 next;
1073 }
Aaron Crane0455ec02010-02-06 18:26:24 +00001074 push @commit_revisions, [$fn, $rev];
Martin Langhoff5179c8a2006-01-30 19:12:41 +13001075 print "Fetching $fn v $rev\n" if $opt_v;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001076 my ($tmpname, $size) = $cvs->file($fn,$rev);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001077 if ($size == -1) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001078 push(@old,$fn);
1079 print "Drop $fn\n" if $opt_v;
1080 } else {
1081 print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
Junio C Hamanodd274782006-02-20 14:17:28 -08001082 my $pid = open(my $F, '-|');
1083 die $! unless defined $pid;
1084 if (!$pid) {
Ben Walton640d9d02010-01-19 14:03:08 -05001085 exec("git", "hash-object", "-w", $tmpname)
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001086 or die "Cannot create object: $!\n";
Junio C Hamanodd274782006-02-20 14:17:28 -08001087 }
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001088 my $sha = <$F>;
1089 chomp $sha;
1090 close $F;
1091 my $mode = pmode($cvs->{'mode'});
1092 push(@new,[$mode, $sha, $fn]); # may be resurrected!
1093 }
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001094 unlink($tmpname);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001095 } elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001096 my $fn = $1;
Aaron Crane0455ec02010-02-06 18:26:24 +00001097 my $rev = $2;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001098 $fn =~ s#^/+##;
Aaron Crane0455ec02010-02-06 18:26:24 +00001099 push @commit_revisions, [$fn, $rev];
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001100 push(@old,$fn);
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001101 print "Delete $fn\n" if $opt_v;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001102 } elsif ($state == 9 and /^\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001103 $state = 10;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001104 } elsif (($state == 9 or $state == 10) and /^-+$/) {
Linus Torvalds4adcea92006-05-22 19:28:37 -07001105 $commitcount++;
1106 if ($opt_L && $commitcount > $opt_L) {
Martin Langhoff06918342006-05-22 23:38:08 +12001107 last;
1108 }
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001109 commit();
Linus Torvalds4adcea92006-05-22 19:28:37 -07001110 if (($commitcount & 1023) == 0) {
Ben Walton91fe7322010-01-19 14:03:10 -05001111 system(qw(git repack -a -d));
Linus Torvalds4adcea92006-05-22 19:28:37 -07001112 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001113 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001114 } elsif ($state == 11 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001115 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001116 } elsif (/^-+$/) { # end of unknown-line processing
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001117 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001118 } elsif ($state != 11) { # ignore stuff when skipping
Jim Meyering3be39992008-08-05 16:54:42 +02001119 print STDERR "* UNKNOWN LINE * $_\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001120 }
1121}
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001122commit() if $branch and $state != 11;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001123
Martin Langhoff4083c2f2007-01-08 21:08:46 +13001124unless ($opt_P) {
1125 unlink($cvspsfile);
1126}
1127
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001128# The heuristic of repacking every 1024 commits can leave a
1129# lot of unpacked data. If there is more than 1MB worth of
1130# not-packed objects, repack once more.
Ben Walton640d9d02010-01-19 14:03:08 -05001131my $line = `git count-objects`;
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001132if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) {
1133 my ($n_objects, $kb) = ($1, $2);
1134 1024 < $kb
Ben Walton91fe7322010-01-19 14:03:10 -05001135 and system(qw(git repack -a -d));
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001136}
1137
Martin Langhoff8f732642006-06-12 23:50:49 +12001138foreach my $git_index (values %index) {
Michael Milligan23fcdc72007-06-05 00:06:30 -06001139 if ($git_index ne "$git_dir/index") {
Martin Langhoffc5f448b2006-06-28 22:13:23 +12001140 unlink($git_index);
1141 }
Martin Langhoff8f732642006-06-12 23:50:49 +12001142}
Sven Verdoolaege79ee4562005-07-04 13:36:59 +02001143
Sven Verdoolaege210569f2005-07-05 13:19:59 +02001144if (defined $orig_git_index) {
1145 $ENV{GIT_INDEX_FILE} = $orig_git_index;
1146} else {
1147 delete $ENV{GIT_INDEX_FILE};
1148}
1149
Matthias Urlichs46541662005-06-28 21:08:15 +02001150# Now switch back to the branch we were in before all of this happened
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001151if ($orig_branch) {
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001152 print "DONE.\n" if $opt_v;
1153 if ($opt_i) {
1154 exit 0;
1155 }
Ben Walton640d9d02010-01-19 14:03:08 -05001156 my $tip_at_end = `git rev-parse --verify HEAD`;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001157 if ($tip_at_start ne $tip_at_end) {
Junio C Hamanocb9594e2006-03-18 02:05:02 -08001158 for ($tip_at_start, $tip_at_end) { chomp; }
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001159 print "Fetched into the current branch.\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001160 system(qw(git read-tree -u -m),
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001161 $tip_at_start, $tip_at_end);
1162 die "Fast-forward update failed: $?\n" if $?;
1163 }
1164 else {
Junio C Hamanod45366e2015-03-25 21:58:45 -07001165 system(qw(git merge -m cvsimport), "$remote/$opt_o");
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001166 die "Could not merge $opt_o into the current branch.\n" if $?;
1167 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001168} else {
1169 $orig_branch = "master";
1170 print "DONE; creating $orig_branch branch\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001171 system("git", "update-ref", "refs/heads/master", "$remote/$opt_o")
Jeff King0750d752007-11-28 13:56:28 -05001172 unless defined get_headref('refs/heads/master');
Ben Walton640d9d02010-01-19 14:03:08 -05001173 system("git", "symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
Andy Whitcroft06baffd2007-06-04 10:01:49 +01001174 if ($opt_r && $opt_o ne 'HEAD');
Ben Walton640d9d02010-01-19 14:03:08 -05001175 system('git', 'update-ref', 'HEAD', "$orig_branch");
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001176 unless ($opt_i) {
Ben Walton91fe7322010-01-19 14:03:10 -05001177 system(qw(git checkout -f));
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001178 die "checkout failed: $?\n" if $?;
1179 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001180}