blob: 2d8df831722913093a46e9325796b85f67a97073 [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;
Jeff King8c87bdf2017-12-08 04:58:19 -0500645 $name =~ s/'/'\\''/g;
Jeff King9da0dab2007-11-28 13:56:11 -0500646 my $r = `git rev-parse --verify '$name' 2>/dev/null`;
647 return undef unless $? == 0;
648 chomp $r;
649 return $r;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400650}
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200651
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400652my $user_filename_prepend = '';
653sub munge_user_filename {
654 my $name = shift;
655 return File::Spec->file_name_is_absolute($name) ?
656 $name :
657 $user_filename_prepend . $name;
658}
659
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200660-d $git_tree
661 or mkdir($git_tree,0777)
662 or die "Could not create $git_tree: $!";
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400663if ($git_tree ne '.') {
664 $user_filename_prepend = getwd() . '/';
665 chdir($git_tree);
666}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200667
668my $last_branch = "";
Matthias Urlichs46541662005-06-28 21:08:15 +0200669my $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200670my %branch_date;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -0800671my $tip_at_start = undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200672
673my $git_dir = $ENV{"GIT_DIR"} || ".git";
674$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#;
675$ENV{"GIT_DIR"} = $git_dir;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +0200676my $orig_git_index;
677$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE};
Martin Langhoff8f732642006-06-12 23:50:49 +1200678
679my %index; # holds filenames of one index per branch
Johannes Schindelin061303f2006-06-24 21:42:20 +0200680
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800681unless (-d $git_dir) {
Ben Walton91fe7322010-01-19 14:03:10 -0500682 system(qw(git init));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200683 die "Cannot init the GIT db at $git_tree: $?\n" if $?;
Thomas Rast1bb28d82010-10-18 15:11:25 +0200684 system(qw(git read-tree --empty));
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200685 die "Cannot init an empty tree: $?\n" if $?;
686
687 $last_branch = $opt_o;
Matthias Urlichs46541662005-06-28 21:08:15 +0200688 $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200689} else {
Ben Waltona12477d2010-01-19 14:03:09 -0500690 open(F, "-|", qw(git symbolic-ref HEAD)) or
Ben Walton640d9d02010-01-19 14:03:08 -0500691 die "Cannot run git symbolic-ref: $!\n";
Pavel Roskin8366a102005-11-16 13:27:28 -0500692 chomp ($last_branch = <F>);
693 $last_branch = basename($last_branch);
694 close(F);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800695 unless ($last_branch) {
Matthias Urlichs46541662005-06-28 21:08:15 +0200696 warn "Cannot read the last branch name: $! -- assuming 'master'\n";
697 $last_branch = "master";
698 }
699 $orig_branch = $last_branch;
Ben Walton640d9d02010-01-19 14:03:08 -0500700 $tip_at_start = `git rev-parse --verify HEAD`;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200701
702 # Get the last import timestamps
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100703 my $fmt = '($ref, $author) = (%(refname), %(author));';
Ben Waltona12477d2010-01-19 14:03:09 -0500704 my @cmd = ('git', 'for-each-ref', '--perl', "--format=$fmt", $remote);
705 open(H, "-|", @cmd) or die "Cannot run git for-each-ref: $!\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800706 while (defined(my $entry = <H>)) {
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100707 my ($ref, $author);
708 eval($entry) || die "cannot eval refs list: $@";
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100709 my ($head) = ($ref =~ m|^$remote/(.*)|);
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100710 $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
711 $branch_date{$head} = $1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200712 }
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100713 close(H);
Stephan Springl7ca055f2007-05-23 12:13:21 +0100714 if (!exists $branch_date{$opt_o}) {
715 die "Branch '$opt_o' does not exist.\n".
716 "Either use the correct '-o branch' option,\n".
717 "or import to a new repository.\n";
718 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200719}
720
721-d $git_dir
722 or die "Could not create git subdir ($git_dir).\n";
723
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100724# now we read (and possibly save) author-info as well
725-f "$git_dir/cvs-authors" and
726 read_author_info("$git_dir/cvs-authors");
727if ($opt_A) {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400728 read_author_info(munge_user_filename($opt_A));
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100729 write_author_info("$git_dir/cvs-authors");
730}
731
Aaron Crane0455ec02010-02-06 18:26:24 +0000732# open .git/cvs-revisions, if requested
733open my $revision_map, '>>', "$git_dir/cvs-revisions"
734 or die "Can't open $git_dir/cvs-revisions for appending: $!\n"
735 if defined $opt_R;
736
Martin Langhoff2f57c692006-06-11 20:12:20 +1200737
738#
739# run cvsps into a file unless we are getting
740# it passed as a file via $opt_P
741#
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300742my $cvspsfile;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200743unless ($opt_P) {
744 print "Running cvsps...\n" if $opt_v;
745 my $pid = open(CVSPS,"-|");
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300746 my $cvspsfh;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200747 die "Cannot fork: $!\n" unless defined $pid;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800748 unless ($pid) {
Martin Langhoff2f57c692006-06-11 20:12:20 +1200749 my @opt;
750 @opt = split(/,/,$opt_p) if defined $opt_p;
751 unshift @opt, '-z', $opt_z if defined $opt_z;
752 unshift @opt, '-q' unless defined $opt_v;
753 unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
754 push @opt, '--cvs-direct';
755 }
756 exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
757 die "Could not start cvsps: $!\n";
Martin Langhoffdf73e9c2005-10-11 21:57:04 -0700758 }
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300759 ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
760 DIR => File::Spec->tmpdir());
Martin Langhoff2f57c692006-06-11 20:12:20 +1200761 while (<CVSPS>) {
762 print $cvspsfh $_;
Martin Langhoff211dcac2005-11-02 13:48:47 +1300763 }
Martin Langhoff2f57c692006-06-11 20:12:20 +1200764 close CVSPS;
Ben Walton640d9d02010-01-19 14:03:08 -0500765 $? == 0 or die "git cvsimport: fatal: cvsps reported error\n";
Martin Langhoff2f57c692006-06-11 20:12:20 +1200766 close $cvspsfh;
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300767} else {
Jeff Kingf6fdbb62009-10-19 02:49:55 -0400768 $cvspsfile = munge_user_filename($opt_P);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200769}
770
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300771open(CVS, "<$cvspsfile") or die $!;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200772
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200773## cvsps output:
774#---------------------
775#PatchSet 314
776#Date: 1999/09/18 13:03:59
777#Author: wkoch
778#Branch: STABLE-BRANCH-1-0
779#Ancestor branch: HEAD
780#Tag: (none)
781#Log:
782# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch
783#Members:
784# README:1.57->1.57.2.1
785# VERSION:1.96->1.96.2.1
786#
787#---------------------
788
789my $state = 0;
790
Jeff Kinge73aefe2006-05-23 03:27:46 -0400791sub update_index (\@\@) {
792 my $old = shift;
793 my $new = shift;
Ben Walton640d9d02010-01-19 14:03:08 -0500794 open(my $fh, '|-', qw(git update-index -z --index-info))
795 or die "unable to open git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400796 print $fh
797 (map { "0 0000000000000000000000000000000000000000\t$_\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400798 @$old),
Jeff King6a1871e2006-05-23 03:27:45 -0400799 (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400800 @$new)
Ben Walton640d9d02010-01-19 14:03:08 -0500801 or die "unable to write to git update-index: $!";
Jeff King6a1871e2006-05-23 03:27:45 -0400802 close $fh
Ben Walton640d9d02010-01-19 14:03:08 -0500803 or die "unable to write to git update-index: $!";
804 $? and die "git update-index reported error: $?";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400805}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200806
Jeff Kinge73aefe2006-05-23 03:27:46 -0400807sub write_tree () {
Ben Waltona12477d2010-01-19 14:03:09 -0500808 open(my $fh, '-|', qw(git write-tree))
Ben Walton640d9d02010-01-19 14:03:08 -0500809 or die "unable to open git write-tree: $!";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400810 chomp(my $tree = <$fh>);
811 is_sha1($tree)
812 or die "Cannot get tree id ($tree): $!";
813 close($fh)
Ben Walton640d9d02010-01-19 14:03:08 -0500814 or die "Error running git write-tree: $?\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200815 print "Tree ID $tree\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400816 return $tree;
817}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200818
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500819my ($patchset,$date,$author_name,$author_email,$author_tz,$branch,$ancestor,$tag,$logmsg);
Aaron Crane0455ec02010-02-06 18:26:24 +0000820my (@old,@new,@skipped,%ignorebranch,@commit_revisions);
Martin Langhoff71b08142006-06-11 20:12:09 +1200821
822# commits that cvsps cannot place anywhere...
823$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
824
Jeff Kinge73aefe2006-05-23 03:27:46 -0400825sub commit {
Jeff King9da0dab2007-11-28 13:56:11 -0500826 if ($branch eq $opt_o && !$index{branch} &&
827 !get_headref("$remote/$branch")) {
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200828 # looks like an initial commit
Ben Walton640d9d02010-01-19 14:03:08 -0500829 # use the index primed by git init
Michael Milligan23fcdc72007-06-05 00:06:30 -0600830 $ENV{GIT_INDEX_FILE} = "$git_dir/index";
831 $index{$branch} = "$git_dir/index";
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200832 } else {
833 # use an index per branch to speed up
834 # imports of projects with many branches
835 unless ($index{$branch}) {
836 $index{$branch} = tmpnam();
837 $ENV{GIT_INDEX_FILE} = $index{$branch};
838 if ($ancestor) {
Ben Walton640d9d02010-01-19 14:03:08 -0500839 system("git", "read-tree", "$remote/$ancestor");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200840 } else {
Ben Walton640d9d02010-01-19 14:03:08 -0500841 system("git", "read-tree", "$remote/$branch");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200842 }
843 die "read-tree failed: $?\n" if $?;
844 }
845 }
846 $ENV{GIT_INDEX_FILE} = $index{$branch};
847
Jeff Kinge73aefe2006-05-23 03:27:46 -0400848 update_index(@old, @new);
849 @old = @new = ();
850 my $tree = write_tree();
Jeff King9da0dab2007-11-28 13:56:11 -0500851 my $parent = get_headref("$remote/$last_branch");
Jeff Kinge73aefe2006-05-23 03:27:46 -0400852 print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200853
Jeff Kinge73aefe2006-05-23 03:27:46 -0400854 my @commit_args;
855 push @commit_args, ("-p", $parent) if $parent;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200856
Jeff Kinge73aefe2006-05-23 03:27:46 -0400857 # loose detection of merges
858 # based on the commit msg
859 foreach my $rx (@mergerx) {
860 next unless $logmsg =~ $rx && $1;
861 my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
Jeff King9da0dab2007-11-28 13:56:11 -0500862 if (my $sha1 = get_headref("$remote/$mparent")) {
Marc-Andre Lureauc36c5b82008-03-12 21:54:21 +0200863 push @commit_args, '-p', "$remote/$mparent";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400864 print "Merge parent branch: $mparent\n" if $opt_v;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200865 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200866 }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400867
Jeff Kingc2b3af02012-11-04 07:25:36 -0500868 set_timezone($author_tz);
Ben Walton48c91622013-02-09 21:46:58 +0000869 # $date is in the seconds since epoch format
870 my $tz_offset = get_tz_offset($date);
871 my $commit_date = "$date $tz_offset";
Jeff Kingc2b3af02012-11-04 07:25:36 -0500872 set_timezone('UTC');
Jeff King62bf0d92006-05-23 16:59:44 -0400873 $ENV{GIT_AUTHOR_NAME} = $author_name;
874 $ENV{GIT_AUTHOR_EMAIL} = $author_email;
875 $ENV{GIT_AUTHOR_DATE} = $commit_date;
876 $ENV{GIT_COMMITTER_NAME} = $author_name;
877 $ENV{GIT_COMMITTER_EMAIL} = $author_email;
878 $ENV{GIT_COMMITTER_DATE} = $commit_date;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400879 my $pid = open2(my $commit_read, my $commit_write,
Ben Walton640d9d02010-01-19 14:03:08 -0500880 'git', 'commit-tree', $tree, @commit_args);
Matthias Urlichse3710462005-06-30 22:09:42 +0200881
882 # compatibility with git2cvs
883 substr($logmsg,32767) = "" if length($logmsg) > 32767;
884 $logmsg =~ s/[\s\n]+\z//;
885
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300886 if (@skipped) {
887 $logmsg .= "\n\n\nSKIPPED:\n\t";
888 $logmsg .= join("\n\t", @skipped) . "\n";
Martin Langhofff396f012006-05-23 00:45:47 +1200889 @skipped = ();
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300890 }
891
Jeff Kinge73aefe2006-05-23 03:27:46 -0400892 print($commit_write "$logmsg\n") && close($commit_write)
Ben Walton640d9d02010-01-19 14:03:08 -0500893 or die "Error writing to git commit-tree: $!\n";
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200894
Jeff Kinge73aefe2006-05-23 03:27:46 -0400895 print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
896 chomp(my $cid = <$commit_read>);
897 is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200898 print "Commit ID $cid\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400899 close($commit_read);
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200900
901 waitpid($pid,0);
Ben Walton640d9d02010-01-19 14:03:08 -0500902 die "Error running git commit-tree: $?\n" if $?;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200903
Ben Walton640d9d02010-01-19 14:03:08 -0500904 system('git' , 'update-ref', "$remote/$branch", $cid) == 0
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200905 or die "Cannot write branch $branch for update: $!\n";
906
Aaron Crane0455ec02010-02-06 18:26:24 +0000907 if ($revision_map) {
908 print $revision_map "@$_ $cid\n" for @commit_revisions;
909 }
910 @commit_revisions = ();
911
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800912 if ($tag) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800913 my ($xtag) = $tag;
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700914 $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
915 $xtag =~ tr/_/\./ if ( $opt_u );
Joe English34c99da2006-01-06 12:52:27 -0800916 $xtag =~ s/[\/]/$opt_s/g;
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700917
Ken Dreyer70b67b02012-09-06 10:36:53 -0600918 # See refs.c for these rules.
919 # Tag cannot contain bad chars. (See bad_ref_char in refs.c.)
920 $xtag =~ s/[ ~\^:\\\*\?\[]//g;
921 # Other bad strings for tags:
922 # (See check_refname_component in refs.c.)
923 1 while $xtag =~ s/
924 (?: \.\. # Tag cannot contain '..'.
Christian Neukirchen16272c72015-06-24 16:04:20 +0200925 | \@\{ # Tag cannot contain '@{'.
Ken Dreyer70b67b02012-09-06 10:36:53 -0600926 | ^ - # Tag cannot begin with '-'.
927 | \.lock $ # Tag cannot end with '.lock'.
928 | ^ \. # Tag cannot begin...
929 | \. $ # ...or end with '.'
930 )//xg;
931 # Tag cannot be empty.
932 if ($xtag eq '') {
933 warn("warning: ignoring tag '$tag'",
934 " with invalid tagname\n");
935 return;
936 }
937
938 if (system('git' , 'tag', '-f', $xtag, $cid) != 0) {
939 # We did our best to sanitize the tag, but still failed
940 # for whatever reason. Bail out, and give the user
941 # enough information to understand if/how we should
942 # improve the translation in the future.
943 if ($tag ne $xtag) {
944 print "Translated '$tag' tag to '$xtag'\n";
945 }
946 die "Cannot create tag $xtag: $!\n";
947 }
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700948
949 print "Created tag '$xtag' on '$branch'\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200950 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200951};
952
Martin Langhoff06918342006-05-22 23:38:08 +1200953my $commitcount = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800954while (<CVS>) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200955 chomp;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800956 if ($state == 0 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200957 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800958 } elsif ($state == 0) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200959 $state = 1;
960 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800961 } elsif (($state==0 or $state==1) and s/^PatchSet\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200962 $patchset = 0+$_;
963 $state=2;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800964 } elsif ($state == 2 and s/^Date:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200965 $date = pdate($_);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800966 unless ($date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200967 print STDERR "Could not parse date: $_\n";
968 $state=0;
969 next;
970 }
971 $state=3;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800972 } elsif ($state == 3 and s/^Author:\s+//) {
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500973 $author_tz = "UTC";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200974 s/\s+$//;
Junio C Hamano94c23342005-09-30 01:48:57 -0700975 if (/^(.*?)\s+<(.*)>/) {
976 ($author_name, $author_email) = ($1, $2);
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100977 } elsif ($conv_author_name{$_}) {
978 $author_name = $conv_author_name{$_};
979 $author_email = $conv_author_email{$_};
Chris Rorvickfb2c9842012-10-16 22:53:29 -0500980 $author_tz = $conv_author_tz{$_} if ($conv_author_tz{$_});
Junio C Hamano94c23342005-09-30 01:48:57 -0700981 } else {
982 $author_name = $author_email = $_;
983 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200984 $state = 4;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800985 } elsif ($state == 4 and s/^Branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200986 s/\s+$//;
Gerrit Papea0554222007-11-03 11:55:02 +0000987 tr/_/\./ if ( $opt_u );
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200988 s/[\/]/$opt_s/g;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200989 $branch = $_;
990 $state = 5;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800991 } elsif ($state == 5 and s/^Ancestor branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200992 s/\s+$//;
993 $ancestor = $_;
Sven Verdoolaege0fa28242005-06-30 17:23:22 +0200994 $ancestor = $opt_o if $ancestor eq "HEAD";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200995 $state = 6;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800996 } elsif ($state == 5) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200997 $ancestor = undef;
998 $state = 6;
999 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001000 } elsif ($state == 6 and s/^Tag:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001001 s/\s+$//;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001002 if ($_ eq "(none)") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001003 $tag = undef;
1004 } else {
1005 $tag = $_;
1006 }
1007 $state = 7;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001008 } elsif ($state == 7 and /^Log:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001009 $logmsg = "";
1010 $state = 8;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001011 } elsif ($state == 8 and /^Members:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001012 $branch = $opt_o if $branch eq "HEAD";
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001013 if (defined $branch_date{$branch} and $branch_date{$branch} >= $date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001014 # skip
Matthias Urlichs9da07f32005-07-03 19:03:30 +02001015 print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001016 $state = 11;
1017 next;
1018 }
Martin Langhoffded9f402007-01-08 19:43:39 +13001019 if (!$opt_a && $starttime - 300 - (defined $opt_z ? $opt_z : 300) <= $date) {
Martin Langhoff62119882007-01-08 14:11:23 +13001020 # skip if the commit is too recent
Stefan Sperling77190eb2007-12-21 16:57:26 +01001021 # given that the cvsps default fuzz is 300s, we give ourselves another
Martin Langhoff62119882007-01-08 14:11:23 +13001022 # 300s just in case -- this also prevents skipping commits
1023 # due to server clock drift
1024 print "skip patchset $patchset: $date too recent\n" if $opt_v;
1025 $state = 11;
1026 next;
1027 }
Martin Langhoff71b08142006-06-11 20:12:09 +12001028 if (exists $ignorebranch{$branch}) {
1029 print STDERR "Skipping $branch\n";
1030 $state = 11;
1031 next;
1032 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001033 if ($ancestor) {
1034 if ($ancestor eq $branch) {
Martin Langhoff71b08142006-06-11 20:12:09 +12001035 print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
1036 $ancestor = $opt_o;
1037 }
Jeff King0750d752007-11-28 13:56:28 -05001038 if (defined get_headref("$remote/$branch")) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001039 print STDERR "Branch $branch already exists!\n";
1040 $state=11;
1041 next;
1042 }
Jeff King0750d752007-11-28 13:56:28 -05001043 my $id = get_headref("$remote/$ancestor");
1044 if (!$id) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001045 print STDERR "Branch $ancestor does not exist!\n";
Martin Langhoff71b08142006-06-11 20:12:09 +12001046 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001047 $state=11;
1048 next;
1049 }
Jeff King0750d752007-11-28 13:56:28 -05001050
1051 system(qw(git update-ref -m cvsimport),
1052 "$remote/$branch", $id);
1053 if($? != 0) {
1054 print STDERR "Could not create branch $branch\n";
Martin Langhoff71b08142006-06-11 20:12:09 +12001055 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001056 $state=11;
1057 next;
1058 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001059 }
Sven Verdoolaege46e63ef2005-07-04 15:28:36 +02001060 $last_branch = $branch if $branch ne $last_branch;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001061 $state = 9;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001062 } elsif ($state == 8) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001063 $logmsg .= "$_\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001064 } elsif ($state == 9 and /^\s+(.+?):(INITIAL|\d+(?:\.\d+)+)->(\d+(?:\.\d+)+)\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001065# VERSION:1.96->1.96.2.1
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +02001066 my $init = ($2 eq "INITIAL");
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001067 my $fn = $1;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001068 my $rev = $3;
1069 $fn =~ s#^/+##;
Martin Langhoff5179c8a2006-01-30 19:12:41 +13001070 if ($opt_S && $fn =~ m/$opt_S/) {
1071 print "SKIPPING $fn v $rev\n";
1072 push(@skipped, $fn);
1073 next;
1074 }
Aaron Crane0455ec02010-02-06 18:26:24 +00001075 push @commit_revisions, [$fn, $rev];
Martin Langhoff5179c8a2006-01-30 19:12:41 +13001076 print "Fetching $fn v $rev\n" if $opt_v;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001077 my ($tmpname, $size) = $cvs->file($fn,$rev);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001078 if ($size == -1) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001079 push(@old,$fn);
1080 print "Drop $fn\n" if $opt_v;
1081 } else {
1082 print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
Junio C Hamanodd274782006-02-20 14:17:28 -08001083 my $pid = open(my $F, '-|');
1084 die $! unless defined $pid;
1085 if (!$pid) {
Ben Walton640d9d02010-01-19 14:03:08 -05001086 exec("git", "hash-object", "-w", $tmpname)
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001087 or die "Cannot create object: $!\n";
Junio C Hamanodd274782006-02-20 14:17:28 -08001088 }
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001089 my $sha = <$F>;
1090 chomp $sha;
1091 close $F;
1092 my $mode = pmode($cvs->{'mode'});
1093 push(@new,[$mode, $sha, $fn]); # may be resurrected!
1094 }
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +02001095 unlink($tmpname);
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001096 } elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001097 my $fn = $1;
Aaron Crane0455ec02010-02-06 18:26:24 +00001098 my $rev = $2;
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001099 $fn =~ s#^/+##;
Aaron Crane0455ec02010-02-06 18:26:24 +00001100 push @commit_revisions, [$fn, $rev];
Matthias Urlichsf65ae602005-06-28 19:58:40 +02001101 push(@old,$fn);
Matthias Urlichs8b8840e2005-08-15 11:28:19 +02001102 print "Delete $fn\n" if $opt_v;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001103 } elsif ($state == 9 and /^\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001104 $state = 10;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001105 } elsif (($state == 9 or $state == 10) and /^-+$/) {
Linus Torvalds4adcea92006-05-22 19:28:37 -07001106 $commitcount++;
1107 if ($opt_L && $commitcount > $opt_L) {
Martin Langhoff06918342006-05-22 23:38:08 +12001108 last;
1109 }
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001110 commit();
Linus Torvalds4adcea92006-05-22 19:28:37 -07001111 if (($commitcount & 1023) == 0) {
Ben Walton91fe7322010-01-19 14:03:10 -05001112 system(qw(git repack -a -d));
Linus Torvalds4adcea92006-05-22 19:28:37 -07001113 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001114 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001115 } elsif ($state == 11 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001116 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001117 } elsif (/^-+$/) { # end of unknown-line processing
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001118 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001119 } elsif ($state != 11) { # ignore stuff when skipping
Jim Meyering3be39992008-08-05 16:54:42 +02001120 print STDERR "* UNKNOWN LINE * $_\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001121 }
1122}
Martin Langhoffc4b16f82006-05-23 00:45:39 +12001123commit() if $branch and $state != 11;
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001124
Martin Langhoff4083c2f2007-01-08 21:08:46 +13001125unless ($opt_P) {
1126 unlink($cvspsfile);
1127}
1128
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001129# The heuristic of repacking every 1024 commits can leave a
1130# lot of unpacked data. If there is more than 1MB worth of
1131# not-packed objects, repack once more.
Ben Walton640d9d02010-01-19 14:03:08 -05001132my $line = `git count-objects`;
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001133if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) {
1134 my ($n_objects, $kb) = ($1, $2);
1135 1024 < $kb
Ben Walton91fe7322010-01-19 14:03:10 -05001136 and system(qw(git repack -a -d));
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001137}
1138
Martin Langhoff8f732642006-06-12 23:50:49 +12001139foreach my $git_index (values %index) {
Michael Milligan23fcdc72007-06-05 00:06:30 -06001140 if ($git_index ne "$git_dir/index") {
Martin Langhoffc5f448b2006-06-28 22:13:23 +12001141 unlink($git_index);
1142 }
Martin Langhoff8f732642006-06-12 23:50:49 +12001143}
Sven Verdoolaege79ee4562005-07-04 13:36:59 +02001144
Sven Verdoolaege210569f2005-07-05 13:19:59 +02001145if (defined $orig_git_index) {
1146 $ENV{GIT_INDEX_FILE} = $orig_git_index;
1147} else {
1148 delete $ENV{GIT_INDEX_FILE};
1149}
1150
Matthias Urlichs46541662005-06-28 21:08:15 +02001151# Now switch back to the branch we were in before all of this happened
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001152if ($orig_branch) {
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001153 print "DONE.\n" if $opt_v;
1154 if ($opt_i) {
1155 exit 0;
1156 }
Ben Walton640d9d02010-01-19 14:03:08 -05001157 my $tip_at_end = `git rev-parse --verify HEAD`;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001158 if ($tip_at_start ne $tip_at_end) {
Junio C Hamanocb9594e2006-03-18 02:05:02 -08001159 for ($tip_at_start, $tip_at_end) { chomp; }
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001160 print "Fetched into the current branch.\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001161 system(qw(git read-tree -u -m),
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001162 $tip_at_start, $tip_at_end);
1163 die "Fast-forward update failed: $?\n" if $?;
1164 }
1165 else {
Junio C Hamanod45366e2015-03-25 21:58:45 -07001166 system(qw(git merge -m cvsimport), "$remote/$opt_o");
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001167 die "Could not merge $opt_o into the current branch.\n" if $?;
1168 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001169} else {
1170 $orig_branch = "master";
1171 print "DONE; creating $orig_branch branch\n" if $opt_v;
Ben Walton640d9d02010-01-19 14:03:08 -05001172 system("git", "update-ref", "refs/heads/master", "$remote/$opt_o")
Jeff King0750d752007-11-28 13:56:28 -05001173 unless defined get_headref('refs/heads/master');
Ben Walton640d9d02010-01-19 14:03:08 -05001174 system("git", "symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
Andy Whitcroft06baffd2007-06-04 10:01:49 +01001175 if ($opt_r && $opt_o ne 'HEAD');
Ben Walton640d9d02010-01-19 14:03:08 -05001176 system('git', 'update-ref', 'HEAD', "$orig_branch");
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001177 unless ($opt_i) {
Ben Walton91fe7322010-01-19 14:03:10 -05001178 system(qw(git checkout -f));
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001179 die "checkout failed: $?\n" if $?;
1180 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001181}