blob: 1ad20ac96450d100fbce7e992ec65972a8c0a7ba [file] [log] [blame]
Matthias Urlichsa57a9492005-06-28 16:48:40 +02001#!/usr/bin/perl -w
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
16use strict;
17use warnings;
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +010018use Getopt::Long;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +020019use File::Spec;
Martin Langhoff7ccd9002006-06-24 23:13:08 +120020use File::Temp qw(tempfile tmpnam);
Matthias Urlichsa57a9492005-06-28 16:48:40 +020021use File::Path qw(mkpath);
22use File::Basename qw(basename dirname);
23use Time::Local;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +020024use IO::Socket;
25use IO::Pipe;
Jeff Kinge49289d2006-05-24 09:58:28 -040026use POSIX qw(strftime dup2 ENOENT);
H. Peter Anvin0d821d42005-09-06 10:36:01 -070027use IPC::Open2;
Matthias Urlichsa57a9492005-06-28 16:48:40 +020028
29$SIG{'PIPE'}="IGNORE";
30$ENV{'TZ'}="UTC";
31
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +010032our ($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);
Andreas Ericssonffd97f32006-01-13 00:38:59 +010033my (%conv_author_name, %conv_author_email);
Matthias Urlichsa57a9492005-06-28 16:48:40 +020034
Frank Lichtenheld7bf77642007-04-06 23:52:41 +020035sub usage(;$) {
36 my $msg = shift;
37 print(STDERR "Error: $msg\n") if $msg;
Matthias Urlichsa57a9492005-06-28 16:48:40 +020038 print STDERR <<END;
Stephan Beyer1b1dd232008-07-13 15:36:15 +020039Usage: git cvsimport # fetch/update GIT from CVS
Andreas Ericssonffd97f32006-01-13 00:38:59 +010040 [-o branch-for-HEAD] [-h] [-v] [-d CVSROOT] [-A author-conv-file]
Frank Lichtenheldedbe4462007-04-06 23:52:39 +020041 [-p opts-for-cvsps] [-P file] [-C GIT_repository] [-z fuzz] [-i] [-k]
42 [-u] [-s subst] [-a] [-m] [-M regex] [-S regex] [-L commitlimit]
Andy Whitcroftcbc9be52007-06-04 10:01:34 +010043 [-r remote] [CVS_module]
Matthias Urlichsa57a9492005-06-28 16:48:40 +020044END
45 exit(1);
Tommy M. McGuire9718a002005-06-10 01:38:32 -050046}
47
Andreas Ericssonffd97f32006-01-13 00:38:59 +010048sub read_author_info($) {
49 my ($file) = @_;
50 my $user;
51 open my $f, '<', "$file" or die("Failed to open $file: $!\n");
52
53 while (<$f>) {
Junio C Hamano8cd16212006-01-15 03:30:30 -080054 # Expected format is this:
Andreas Ericssonffd97f32006-01-13 00:38:59 +010055 # exon=Andreas Ericsson <ae@op5.se>
Junio C Hamano8cd16212006-01-15 03:30:30 -080056 if (m/^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/) {
Andreas Ericssonffd97f32006-01-13 00:38:59 +010057 $user = $1;
Junio C Hamano8cd16212006-01-15 03:30:30 -080058 $conv_author_name{$user} = $2;
59 $conv_author_email{$user} = $3;
Andreas Ericssonffd97f32006-01-13 00:38:59 +010060 }
Junio C Hamano8cd16212006-01-15 03:30:30 -080061 # However, we also read from CVSROOT/users format
62 # to ease migration.
63 elsif (/^(\w+):(['"]?)(.+?)\2\s*$/) {
64 my $mapped;
65 ($user, $mapped) = ($1, $3);
66 if ($mapped =~ /^\s*(.*?)\s*<(.*)>\s*$/) {
67 $conv_author_name{$user} = $1;
68 $conv_author_email{$user} = $2;
69 }
70 elsif ($mapped =~ /^<?(.*)>?$/) {
71 $conv_author_name{$user} = $user;
72 $conv_author_email{$user} = $1;
73 }
74 }
75 # NEEDSWORK: Maybe warn on unrecognized lines?
Andreas Ericssonffd97f32006-01-13 00:38:59 +010076 }
77 close ($f);
78}
79
80sub write_author_info($) {
81 my ($file) = @_;
82 open my $f, '>', $file or
83 die("Failed to open $file for writing: $!");
84
85 foreach (keys %conv_author_name) {
Junio C Hamano8cd16212006-01-15 03:30:30 -080086 print $f "$_=$conv_author_name{$_} <$conv_author_email{$_}>\n";
Andreas Ericssonffd97f32006-01-13 00:38:59 +010087 }
88 close ($f);
89}
90
Dan McGeecfc44a12008-01-13 22:51:10 -060091# convert getopts specs for use by git config
James Bowesed35dec2007-02-07 17:57:43 -050092sub read_repo_config {
93 # Split the string between characters, unless there is a ':'
94 # So "abc:de" becomes ["a", "b", "c:", "d", "e"]
95 my @opts = split(/ *(?!:)/, shift);
96 foreach my $o (@opts) {
97 my $key = $o;
98 $key =~ s/://g;
Dan McGeecfc44a12008-01-13 22:51:10 -060099 my $arg = 'git config';
James Bowesed35dec2007-02-07 17:57:43 -0500100 $arg .= ' --bool' if ($o !~ /:$/);
101
102 chomp(my $tmp = `$arg --get cvsimport.$key`);
103 if ($tmp && !($arg =~ /--bool/ && $tmp eq 'false')) {
104 no strict 'refs';
105 my $opt_name = "opt_" . $key;
106 if (!$$opt_name) {
107 $$opt_name = $tmp;
108 }
109 }
110 }
James Bowesed35dec2007-02-07 17:57:43 -0500111}
112
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100113my $opts = "haivmkuo:d:p:r:C:z:s:M:P:A:S:L:";
James Bowesed35dec2007-02-07 17:57:43 -0500114read_repo_config($opts);
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +0100115Getopt::Long::Configure( 'no_ignore_case', 'bundling' );
116
117# turn the Getopt::Std specification in a Getopt::Long one,
118# with support for multiple -M options
119GetOptions( map { s/:/=s/; /M/ ? "$_\@" : $_ } split( /(?!:)/, $opts ) )
120 or usage();
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200121usage if $opt_h;
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700122
Jeff King67d23242007-11-30 17:22:12 -0500123if (@ARGV == 0) {
Dan McGeecfc44a12008-01-13 22:51:10 -0600124 chomp(my $module = `git config --get cvsimport.module`);
Jeff King67d23242007-11-30 17:22:12 -0500125 push(@ARGV, $module) if $? == 0;
126}
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200127@ARGV <= 1 or usage("You can't specify more than one CVS module");
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200128
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800129if ($opt_d) {
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200130 $ENV{"CVSROOT"} = $opt_d;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800131} elsif (-f 'CVS/Root') {
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200132 open my $f, '<', 'CVS/Root' or die 'Failed to open CVS/Root';
133 $opt_d = <$f>;
134 chomp $opt_d;
135 close $f;
136 $ENV{"CVSROOT"} = $opt_d;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800137} elsif ($ENV{"CVSROOT"}) {
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200138 $opt_d = $ENV{"CVSROOT"};
139} else {
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200140 usage("CVSROOT needs to be set");
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200141}
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200142$opt_s ||= "-";
Martin Langhoffded9f402007-01-08 19:43:39 +1300143$opt_a ||= 0;
144
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200145my $git_tree = $opt_C;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200146$git_tree ||= ".";
147
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100148my $remote;
149if (defined $opt_r) {
150 $remote = 'refs/remotes/' . $opt_r;
151 $opt_o ||= "master";
152} else {
153 $opt_o ||= "origin";
154 $remote = 'refs/heads';
155}
156
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200157my $cvs_tree;
158if ($#ARGV == 0) {
159 $cvs_tree = $ARGV[0];
160} elsif (-f 'CVS/Repository') {
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700161 open my $f, '<', 'CVS/Repository' or
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200162 die 'Failed to open CVS/Repository';
163 $cvs_tree = <$f>;
164 chomp $cvs_tree;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200165 close $f;
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200166} else {
Frank Lichtenheld7bf77642007-04-06 23:52:41 +0200167 usage("CVS module has to be specified");
Sven Verdoolaegef9714a42005-07-03 11:34:59 +0200168}
169
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200170our @mergerx = ();
171if ($opt_m) {
Philippe Bruhat (BooKfbbbc362008-02-28 11:18:21 +0100172 @mergerx = ( qr/\b(?:from|of|merge|merging|merged) ([-\w]+)/i );
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200173}
Philippe Bruhat (BooKbc434e82008-02-28 11:18:22 +0100174if (@opt_M) {
175 push (@mergerx, map { qr/$_/ } @opt_M);
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200176}
177
Martin Langhoff62119882007-01-08 14:11:23 +1300178# Remember UTC of our starting time
179# we'll want to avoid importing commits
180# that are too recent
181our $starttime = time();
182
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200183select(STDERR); $|=1; select(STDOUT);
184
185
186package CVSconn;
187# Basic CVS dialog.
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200188# We're only interested in connecting and downloading, so ...
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200189
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200190use File::Spec;
191use File::Temp qw(tempfile);
Matthias Urlichsf65ae602005-06-28 19:58:40 +0200192use POSIX qw(strftime dup2);
193
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200194sub new {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800195 my ($what,$repo,$subdir) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200196 $what=ref($what) if ref($what);
197
198 my $self = {};
199 $self->{'buffer'} = "";
200 bless($self,$what);
201
202 $repo =~ s#/+$##;
203 $self->{'fullrep'} = $repo;
204 $self->conn();
205
206 $self->{'subdir'} = $subdir;
207 $self->{'lines'} = undef;
208
209 return $self;
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700210}
211
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200212sub conn {
213 my $self = shift;
214 my $repo = $self->{'fullrep'};
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800215 if ($repo =~ s/^:pserver(?:([^:]*)):(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) {
216 my ($param,$user,$pass,$serv,$port) = ($1,$2,$3,$4,$5);
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100217
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800218 my ($proxyhost,$proxyport);
219 if ($param && ($param =~ m/proxy=([^;]+)/)) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100220 $proxyhost = $1;
221 # Default proxyport, if not specified, is 8080.
222 $proxyport = 8080;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800223 if ($ENV{"CVS_PROXY_PORT"}) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100224 $proxyport = $ENV{"CVS_PROXY_PORT"};
225 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800226 if ($param =~ m/proxyport=([^;]+)/) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100227 $proxyport = $1;
228 }
229 }
Philippe Bruhat (BooK)8c372fb2008-06-10 14:32:06 +0200230 $repo ||= '/';
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100231
Gordon Hopper2e458e02007-11-08 13:15:20 -0700232 # if username is not explicit in CVSROOT, then use current user, as cvs would
233 $user=(getlogin() || $ENV{'LOGNAME'} || $ENV{'USER'} || "anonymous") unless $user;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200234 my $rr2 = "-";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800235 unless ($port) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200236 $rr2 = ":pserver:$user\@$serv:$repo";
237 $port=2401;
238 }
239 my $rr = ":pserver:$user\@$serv:$port$repo";
Linus Torvaldsd4f8b392005-06-07 15:11:28 -0700240
Pascal Obry3fb9d582009-09-04 13:58:32 +0200241 if ($pass) {
242 $pass = $self->_scramble($pass);
243 } else {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200244 open(H,$ENV{'HOME'}."/.cvspass") and do {
245 # :pserver:cvs@mea.tmt.tele.fi:/cvsroot/zmailer Ah<Z
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800246 while (<H>) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200247 chomp;
248 s/^\/\d+\s+//;
249 my ($w,$p) = split(/\s/,$_,2);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800250 if ($w eq $rr or $w eq $rr2) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200251 $pass = $p;
252 last;
253 }
254 }
255 };
Clemens Buchachere481b1d2009-09-17 09:21:02 +0200256 $pass = "A" unless $pass;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200257 }
Dirk Hoernerb2139db2009-08-14 08:58:31 +0200258
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100259 my ($s, $rep);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800260 if ($proxyhost) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100261
262 # Use a HTTP Proxy. Only works for HTTP proxies that
263 # don't require user authentication
264 #
265 # See: http://www.ietf.org/rfc/rfc2817.txt
266
267 $s = IO::Socket::INET->new(PeerHost => $proxyhost, PeerPort => $proxyport);
268 die "Socket to $proxyhost: $!\n" unless defined $s;
269 $s->write("CONNECT $serv:$port HTTP/1.1\r\nHost: $serv:$port\r\n\r\n")
270 or die "Write to $proxyhost: $!\n";
271 $s->flush();
272
273 $rep = <$s>;
274
275 # The answer should look like 'HTTP/1.x 2yy ....'
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800276 if (!($rep =~ m#^HTTP/1\.. 2[0-9][0-9]#)) {
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100277 die "Proxy connect: $rep\n";
278 }
279 # Skip up to the empty line of the proxy server output
280 # including the response headers.
281 while ($rep = <$s>) {
282 last if (!defined $rep ||
283 $rep eq "\n" ||
284 $rep eq "\r\n");
285 }
286 } else {
287 $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port);
288 die "Socket to $serv: $!\n" unless defined $s;
289 }
290
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200291 $s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n")
292 or die "Write to $serv: $!\n";
293 $s->flush();
294
Iñaki Arenaza73bcf532006-11-22 23:26:57 +0100295 $rep = <$s>;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200296
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800297 if ($rep ne "I LOVE YOU\n") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200298 $rep="<unknown>" unless $rep;
299 die "AuthReply: $rep\n";
300 }
301 $self->{'socketo'} = $s;
302 $self->{'socketi'} = $s;
Sven Verdoolaege34155392005-07-03 13:02:06 +0200303 } else { # local or ext: Fork off our own cvs server.
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200304 my $pr = IO::Pipe->new();
305 my $pw = IO::Pipe->new();
306 my $pid = fork();
307 die "Fork: $!\n" unless defined $pid;
Sven Verdoolaege8d0ea312005-07-03 12:26:51 +0200308 my $cvs = 'cvs';
309 $cvs = $ENV{CVS_SERVER} if exists $ENV{CVS_SERVER};
Sven Verdoolaege34155392005-07-03 13:02:06 +0200310 my $rsh = 'rsh';
311 $rsh = $ENV{CVS_RSH} if exists $ENV{CVS_RSH};
312
313 my @cvs = ($cvs, 'server');
314 my ($local, $user, $host);
315 $local = $repo =~ s/:local://;
316 if (!$local) {
317 $repo =~ s/:ext://;
318 $local = !($repo =~ s/^(?:([^\@:]+)\@)?([^:]+)://);
319 ($user, $host) = ($1, $2);
320 }
321 if (!$local) {
322 if ($user) {
323 unshift @cvs, $rsh, '-l', $user, $host;
324 } else {
325 unshift @cvs, $rsh, $host;
326 }
327 }
328
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800329 unless ($pid) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200330 $pr->writer();
331 $pw->reader();
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200332 dup2($pw->fileno(),0);
333 dup2($pr->fileno(),1);
334 $pr->close();
335 $pw->close();
Sven Verdoolaege34155392005-07-03 13:02:06 +0200336 exec(@cvs);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200337 }
338 $pw->writer();
339 $pr->reader();
340 $self->{'socketo'} = $pw;
341 $self->{'socketi'} = $pr;
342 }
343 $self->{'socketo'}->write("Root $repo\n");
344
345 # Trial and error says that this probably is the minimum set
iso-8859-1?Q?David_K=E5gedalb0921332005-08-15 20:18:25 +0200346 $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 +0200347
348 $self->{'socketo'}->write("valid-requests\n");
349 $self->{'socketo'}->flush();
350
351 chomp(my $rep=$self->readline());
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800352 if ($rep !~ s/^Valid-requests\s*//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200353 $rep="<unknown>" unless $rep;
354 die "Expected Valid-requests from server, but got: $rep\n";
355 }
356 chomp(my $res=$self->readline());
357 die "validReply: $res\n" if $res ne "ok";
358
359 $self->{'socketo'}->write("UseUnchanged\n") if $rep =~ /\bUseUnchanged\b/;
360 $self->{'repo'} = $repo;
361}
362
363sub readline {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800364 my ($self) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200365 return $self->{'socketi'}->getline();
366}
367
368sub _file {
369 # Request a file with a given revision.
370 # Trial and error says this is a good way to do it. :-/
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800371 my ($self,$fn,$rev) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200372 $self->{'socketo'}->write("Argument -N\n") or return undef;
373 $self->{'socketo'}->write("Argument -P\n") or return undef;
Martin Langhoffabe05822005-08-16 17:39:29 +1200374 # -kk: Linus' version doesn't use it - defaults to off
375 if ($opt_k) {
376 $self->{'socketo'}->write("Argument -kk\n") or return undef;
377 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200378 $self->{'socketo'}->write("Argument -r\n") or return undef;
379 $self->{'socketo'}->write("Argument $rev\n") or return undef;
380 $self->{'socketo'}->write("Argument --\n") or return undef;
381 $self->{'socketo'}->write("Argument $self->{'subdir'}/$fn\n") or return undef;
382 $self->{'socketo'}->write("Directory .\n") or return undef;
383 $self->{'socketo'}->write("$self->{'repo'}\n") or return undef;
Matthias Urlichs4f7c0ca2005-06-30 12:19:48 +0200384 # $self->{'socketo'}->write("Sticky T1.0\n") or return undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200385 $self->{'socketo'}->write("co\n") or return undef;
386 $self->{'socketo'}->flush() or return undef;
387 $self->{'lines'} = 0;
388 return 1;
389}
390sub _line {
391 # Read a line from the server.
392 # ... except that 'line' may be an entire file. ;-)
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800393 my ($self, $fh) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200394 die "Not in lines" unless defined $self->{'lines'};
395
396 my $line;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200397 my $res=0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800398 while (defined($line = $self->readline())) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200399 # M U gnupg-cvs-rep/AUTHORS
400 # Updated gnupg-cvs-rep/
401 # /daten/src/rsync/gnupg-cvs-rep/AUTHORS
402 # /AUTHORS/1.1///T1.1
403 # u=rw,g=rw,o=rw
404 # 0
405 # ok
406
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800407 if ($line =~ s/^(?:Created|Updated) //) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200408 $line = $self->readline(); # path
409 $line = $self->readline(); # Entries line
410 my $mode = $self->readline(); chomp $mode;
411 $self->{'mode'} = $mode;
412 defined (my $cnt = $self->readline())
413 or die "EOF from server after 'Changed'\n";
414 chomp $cnt;
415 die "Duh: Filesize $cnt" if $cnt !~ /^\d+$/;
416 $line="";
Martin Langhoff55cad842006-05-23 20:08:58 +1200417 $res = $self->_fetchfile($fh, $cnt);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800418 } elsif ($line =~ s/^ //) {
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200419 print $fh $line;
420 $res += length($line);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800421 } elsif ($line =~ /^M\b/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200422 # output, do nothing
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800423 } elsif ($line =~ /^Mbinary\b/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200424 my $cnt;
425 die "EOF from server after 'Mbinary'" unless defined ($cnt = $self->readline());
426 chomp $cnt;
427 die "Duh: Mbinary $cnt" if $cnt !~ /^\d+$/ or $cnt<1;
428 $line="";
Martin Langhoff55cad842006-05-23 20:08:58 +1200429 $res += $self->_fetchfile($fh, $cnt);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200430 } else {
431 chomp $line;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800432 if ($line eq "ok") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200433 # print STDERR "S: ok (".length($res).")\n";
434 return $res;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800435 } elsif ($line =~ s/^E //) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200436 # print STDERR "S: $line\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800437 } elsif ($line =~ /^(Remove-entry|Removed) /i) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200438 $line = $self->readline(); # filename
439 $line = $self->readline(); # OK
440 chomp $line;
441 die "Unknown: $line" if $line ne "ok";
442 return -1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200443 } else {
444 die "Unknown: $line\n";
445 }
446 }
447 }
Martin Mares39ba7d52006-02-18 21:44:20 +0100448 return undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200449}
450sub file {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800451 my ($self,$fn,$rev) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200452 my $res;
453
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700454 my ($fh, $name) = tempfile('gitcvs.XXXXXX',
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200455 DIR => File::Spec->tmpdir(), UNLINK => 1);
456
457 $self->_file($fn,$rev) and $res = $self->_line($fh);
458
459 if (!defined $res) {
Martin Mares39ba7d52006-02-18 21:44:20 +0100460 print STDERR "Server has gone away while fetching $fn $rev, retrying...\n";
461 truncate $fh, 0;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200462 $self->conn();
Martin Mares39ba7d52006-02-18 21:44:20 +0100463 $self->_file($fn,$rev) or die "No file command send";
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200464 $res = $self->_line($fh);
Martin Mares39ba7d52006-02-18 21:44:20 +0100465 die "Retry failed" unless defined $res;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200466 }
Sven Verdoolaegec619ad52005-07-06 08:37:12 +0200467 close ($fh);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200468
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200469 return ($name, $res);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200470}
Martin Langhoff55cad842006-05-23 20:08:58 +1200471sub _fetchfile {
472 my ($self, $fh, $cnt) = @_;
Junio C Hamano61efa5e2006-05-23 16:30:39 -0700473 my $res = 0;
Martin Langhoff55cad842006-05-23 20:08:58 +1200474 my $bufsize = 1024 * 1024;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800475 while ($cnt) {
Martin Langhoff55cad842006-05-23 20:08:58 +1200476 if ($bufsize > $cnt) {
477 $bufsize = $cnt;
478 }
479 my $buf;
480 my $num = $self->{'socketi'}->read($buf,$bufsize);
481 die "Server: Filesize $cnt: $num: $!\n" if not defined $num or $num<=0;
482 print $fh $buf;
483 $res += $num;
484 $cnt -= $num;
485 }
486 return $res;
487}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200488
Dirk Hoernerb2139db2009-08-14 08:58:31 +0200489sub _scramble {
490 my ($self, $pass) = @_;
491 my $scrambled = "A";
492
493 return $scrambled unless $pass;
494
495 my $pass_len = length($pass);
496 my @pass_arr = split("", $pass);
497 my $i;
498
499 # from cvs/src/scramble.c
500 my @shifts = (
501 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
502 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
503 114,120, 53, 79, 96,109, 72,108, 70, 64, 76, 67,116, 74, 68, 87,
504 111, 52, 75,119, 49, 34, 82, 81, 95, 65,112, 86,118,110,122,105,
505 41, 57, 83, 43, 46,102, 40, 89, 38,103, 45, 50, 42,123, 91, 35,
506 125, 55, 54, 66,124,126, 59, 47, 92, 71,115, 78, 88,107,106, 56,
507 36,121,117,104,101,100, 69, 73, 99, 63, 94, 93, 39, 37, 61, 48,
508 58,113, 32, 90, 44, 98, 60, 51, 33, 97, 62, 77, 84, 80, 85,223,
509 225,216,187,166,229,189,222,188,141,249,148,200,184,136,248,190,
510 199,170,181,204,138,232,218,183,255,234,220,247,213,203,226,193,
511 174,172,228,252,217,201,131,230,197,211,145,238,161,179,160,212,
512 207,221,254,173,202,146,224,151,140,196,205,130,135,133,143,246,
513 192,159,244,239,185,168,215,144,139,165,180,157,147,186,214,176,
514 227,231,219,169,175,156,206,198,129,164,150,210,154,177,134,127,
515 182,128,158,208,162,132,167,209,149,241,153,251,237,236,171,195,
516 243,233,253,240,194,250,191,155,142,137,245,235,163,242,178,152
517 );
518
519 for ($i = 0; $i < $pass_len; $i++) {
520 $scrambled .= pack("C", $shifts[ord($pass_arr[$i])]);
521 }
522
523 return $scrambled;
524}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200525
526package main;
527
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200528my $cvs = CVSconn->new($opt_d, $cvs_tree);
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200529
530
531sub pdate($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800532 my ($d) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200533 m#(\d{2,4})/(\d\d)/(\d\d)\s(\d\d):(\d\d)(?::(\d\d))?#
534 or die "Unparseable date: $d\n";
535 my $y=$1; $y-=1900 if $y>1900;
536 return timegm($6||0,$5,$4,$3,$2-1,$y);
537}
538
539sub pmode($) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800540 my ($mode) = @_;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200541 my $m = 0;
542 my $mm = 0;
543 my $um = 0;
544 for my $x(split(//,$mode)) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800545 if ($x eq ",") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200546 $m |= $mm&$um;
547 $mm = 0;
548 $um = 0;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800549 } elsif ($x eq "u") { $um |= 0700;
550 } elsif ($x eq "g") { $um |= 0070;
551 } elsif ($x eq "o") { $um |= 0007;
552 } elsif ($x eq "r") { $mm |= 0444;
553 } elsif ($x eq "w") { $mm |= 0222;
554 } elsif ($x eq "x") { $mm |= 0111;
555 } elsif ($x eq "=") { # do nothing
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200556 } else { die "Unknown mode: $mode\n";
557 }
558 }
559 $m |= $mm&$um;
560 return $m;
561}
562
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200563sub getwd() {
564 my $pwd = `pwd`;
565 chomp $pwd;
566 return $pwd;
567}
568
Jeff Kinge73aefe2006-05-23 03:27:46 -0400569sub is_sha1 {
570 my $s = shift;
571 return $s =~ /^[a-f0-9]{40}$/;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200572}
573
Jeff King9da0dab2007-11-28 13:56:11 -0500574sub get_headref ($) {
575 my $name = shift;
576 my $r = `git rev-parse --verify '$name' 2>/dev/null`;
577 return undef unless $? == 0;
578 chomp $r;
579 return $r;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400580}
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200581
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200582-d $git_tree
583 or mkdir($git_tree,0777)
584 or die "Could not create $git_tree: $!";
585chdir($git_tree);
586
587my $last_branch = "";
Matthias Urlichs46541662005-06-28 21:08:15 +0200588my $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200589my %branch_date;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -0800590my $tip_at_start = undef;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200591
592my $git_dir = $ENV{"GIT_DIR"} || ".git";
593$git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#;
594$ENV{"GIT_DIR"} = $git_dir;
Sven Verdoolaege79ee4562005-07-04 13:36:59 +0200595my $orig_git_index;
596$orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE};
Martin Langhoff8f732642006-06-12 23:50:49 +1200597
598my %index; # holds filenames of one index per branch
Johannes Schindelin061303f2006-06-24 21:42:20 +0200599
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800600unless (-d $git_dir) {
Nicolas Pitre5c94f872007-01-12 16:01:46 -0500601 system("git-init");
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200602 die "Cannot init the GIT db at $git_tree: $?\n" if $?;
603 system("git-read-tree");
604 die "Cannot init an empty tree: $?\n" if $?;
605
606 $last_branch = $opt_o;
Matthias Urlichs46541662005-06-28 21:08:15 +0200607 $orig_branch = "";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200608} else {
Pavel Roskin8366a102005-11-16 13:27:28 -0500609 open(F, "git-symbolic-ref HEAD |") or
610 die "Cannot run git-symbolic-ref: $!\n";
611 chomp ($last_branch = <F>);
612 $last_branch = basename($last_branch);
613 close(F);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800614 unless ($last_branch) {
Matthias Urlichs46541662005-06-28 21:08:15 +0200615 warn "Cannot read the last branch name: $! -- assuming 'master'\n";
616 $last_branch = "master";
617 }
618 $orig_branch = $last_branch;
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -0800619 $tip_at_start = `git-rev-parse --verify HEAD`;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200620
621 # Get the last import timestamps
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100622 my $fmt = '($ref, $author) = (%(refname), %(author));';
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100623 open(H, "git-for-each-ref --perl --format='$fmt' $remote |") or
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100624 die "Cannot run git-for-each-ref: $!\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800625 while (defined(my $entry = <H>)) {
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100626 my ($ref, $author);
627 eval($entry) || die "cannot eval refs list: $@";
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100628 my ($head) = ($ref =~ m|^$remote/(.*)|);
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100629 $author =~ /^.*\s(\d+)\s[-+]\d{4}$/;
630 $branch_date{$head} = $1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200631 }
Andy Whitcroft1f24c582006-09-20 17:37:04 +0100632 close(H);
Stephan Springl7ca055f2007-05-23 12:13:21 +0100633 if (!exists $branch_date{$opt_o}) {
634 die "Branch '$opt_o' does not exist.\n".
635 "Either use the correct '-o branch' option,\n".
636 "or import to a new repository.\n";
637 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200638}
639
640-d $git_dir
641 or die "Could not create git subdir ($git_dir).\n";
642
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100643# now we read (and possibly save) author-info as well
644-f "$git_dir/cvs-authors" and
645 read_author_info("$git_dir/cvs-authors");
646if ($opt_A) {
647 read_author_info($opt_A);
648 write_author_info("$git_dir/cvs-authors");
649}
650
Martin Langhoff2f57c692006-06-11 20:12:20 +1200651
652#
653# run cvsps into a file unless we are getting
654# it passed as a file via $opt_P
655#
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300656my $cvspsfile;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200657unless ($opt_P) {
658 print "Running cvsps...\n" if $opt_v;
659 my $pid = open(CVSPS,"-|");
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300660 my $cvspsfh;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200661 die "Cannot fork: $!\n" unless defined $pid;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800662 unless ($pid) {
Martin Langhoff2f57c692006-06-11 20:12:20 +1200663 my @opt;
664 @opt = split(/,/,$opt_p) if defined $opt_p;
665 unshift @opt, '-z', $opt_z if defined $opt_z;
666 unshift @opt, '-q' unless defined $opt_v;
667 unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) {
668 push @opt, '--cvs-direct';
669 }
670 exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree);
671 die "Could not start cvsps: $!\n";
Martin Langhoffdf73e9c2005-10-11 21:57:04 -0700672 }
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300673 ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps',
674 DIR => File::Spec->tmpdir());
Martin Langhoff2f57c692006-06-11 20:12:20 +1200675 while (<CVSPS>) {
676 print $cvspsfh $_;
Martin Langhoff211dcac2005-11-02 13:48:47 +1300677 }
Martin Langhoff2f57c692006-06-11 20:12:20 +1200678 close CVSPS;
Jeff King3a969ef2007-12-23 22:08:19 -0500679 $? == 0 or die "git-cvsimport: fatal: cvsps reported error\n";
Martin Langhoff2f57c692006-06-11 20:12:20 +1200680 close $cvspsfh;
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300681} else {
682 $cvspsfile = $opt_P;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200683}
684
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300685open(CVS, "<$cvspsfile") or die $!;
Martin Langhoff2f57c692006-06-11 20:12:20 +1200686
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200687## cvsps output:
688#---------------------
689#PatchSet 314
690#Date: 1999/09/18 13:03:59
691#Author: wkoch
692#Branch: STABLE-BRANCH-1-0
693#Ancestor branch: HEAD
694#Tag: (none)
695#Log:
696# See ChangeLog: Sat Sep 18 13:03:28 CEST 1999 Werner Koch
697#Members:
698# README:1.57->1.57.2.1
699# VERSION:1.96->1.96.2.1
700#
701#---------------------
702
703my $state = 0;
704
Jeff Kinge73aefe2006-05-23 03:27:46 -0400705sub update_index (\@\@) {
706 my $old = shift;
707 my $new = shift;
Jeff King6a1871e2006-05-23 03:27:45 -0400708 open(my $fh, '|-', qw(git-update-index -z --index-info))
709 or die "unable to open git-update-index: $!";
710 print $fh
711 (map { "0 0000000000000000000000000000000000000000\t$_\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400712 @$old),
Jeff King6a1871e2006-05-23 03:27:45 -0400713 (map { '100' . sprintf('%o', $_->[0]) . " $_->[1]\t$_->[2]\0" }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400714 @$new)
Jeff King6a1871e2006-05-23 03:27:45 -0400715 or die "unable to write to git-update-index: $!";
716 close $fh
717 or die "unable to write to git-update-index: $!";
718 $? and die "git-update-index reported error: $?";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400719}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200720
Jeff Kinge73aefe2006-05-23 03:27:46 -0400721sub write_tree () {
722 open(my $fh, '-|', qw(git-write-tree))
723 or die "unable to open git-write-tree: $!";
724 chomp(my $tree = <$fh>);
725 is_sha1($tree)
726 or die "Cannot get tree id ($tree): $!";
727 close($fh)
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200728 or die "Error running git-write-tree: $?\n";
729 print "Tree ID $tree\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400730 return $tree;
731}
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200732
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800733my ($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg);
734my (@old,@new,@skipped,%ignorebranch);
Martin Langhoff71b08142006-06-11 20:12:09 +1200735
736# commits that cvsps cannot place anywhere...
737$ignorebranch{'#CVSPS_NO_BRANCH'} = 1;
738
Jeff Kinge73aefe2006-05-23 03:27:46 -0400739sub commit {
Jeff King9da0dab2007-11-28 13:56:11 -0500740 if ($branch eq $opt_o && !$index{branch} &&
741 !get_headref("$remote/$branch")) {
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200742 # looks like an initial commit
Nicolas Pitre5c94f872007-01-12 16:01:46 -0500743 # use the index primed by git-init
Michael Milligan23fcdc72007-06-05 00:06:30 -0600744 $ENV{GIT_INDEX_FILE} = "$git_dir/index";
745 $index{$branch} = "$git_dir/index";
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200746 } else {
747 # use an index per branch to speed up
748 # imports of projects with many branches
749 unless ($index{$branch}) {
750 $index{$branch} = tmpnam();
751 $ENV{GIT_INDEX_FILE} = $index{$branch};
752 if ($ancestor) {
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100753 system("git-read-tree", "$remote/$ancestor");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200754 } else {
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +0100755 system("git-read-tree", "$remote/$branch");
Martin Langhoffc5f448b2006-06-28 22:13:23 +1200756 }
757 die "read-tree failed: $?\n" if $?;
758 }
759 }
760 $ENV{GIT_INDEX_FILE} = $index{$branch};
761
Jeff Kinge73aefe2006-05-23 03:27:46 -0400762 update_index(@old, @new);
763 @old = @new = ();
764 my $tree = write_tree();
Jeff King9da0dab2007-11-28 13:56:11 -0500765 my $parent = get_headref("$remote/$last_branch");
Jeff Kinge73aefe2006-05-23 03:27:46 -0400766 print "Parent ID " . ($parent ? $parent : "(empty)") . "\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200767
Jeff Kinge73aefe2006-05-23 03:27:46 -0400768 my @commit_args;
769 push @commit_args, ("-p", $parent) if $parent;
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200770
Jeff Kinge73aefe2006-05-23 03:27:46 -0400771 # loose detection of merges
772 # based on the commit msg
773 foreach my $rx (@mergerx) {
774 next unless $logmsg =~ $rx && $1;
775 my $mparent = $1 eq 'HEAD' ? $opt_o : $1;
Jeff King9da0dab2007-11-28 13:56:11 -0500776 if (my $sha1 = get_headref("$remote/$mparent")) {
Marc-Andre Lureauc36c5b82008-03-12 21:54:21 +0200777 push @commit_args, '-p', "$remote/$mparent";
Jeff Kinge73aefe2006-05-23 03:27:46 -0400778 print "Merge parent branch: $mparent\n" if $opt_v;
Martin Langhoffdb4b6582005-08-16 22:35:27 +1200779 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200780 }
Jeff Kinge73aefe2006-05-23 03:27:46 -0400781
782 my $commit_date = strftime("+0000 %Y-%m-%d %H:%M:%S",gmtime($date));
Jeff King62bf0d92006-05-23 16:59:44 -0400783 $ENV{GIT_AUTHOR_NAME} = $author_name;
784 $ENV{GIT_AUTHOR_EMAIL} = $author_email;
785 $ENV{GIT_AUTHOR_DATE} = $commit_date;
786 $ENV{GIT_COMMITTER_NAME} = $author_name;
787 $ENV{GIT_COMMITTER_EMAIL} = $author_email;
788 $ENV{GIT_COMMITTER_DATE} = $commit_date;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400789 my $pid = open2(my $commit_read, my $commit_write,
Jeff Kinge73aefe2006-05-23 03:27:46 -0400790 'git-commit-tree', $tree, @commit_args);
Matthias Urlichse3710462005-06-30 22:09:42 +0200791
792 # compatibility with git2cvs
793 substr($logmsg,32767) = "" if length($logmsg) > 32767;
794 $logmsg =~ s/[\s\n]+\z//;
795
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300796 if (@skipped) {
797 $logmsg .= "\n\n\nSKIPPED:\n\t";
798 $logmsg .= join("\n\t", @skipped) . "\n";
Martin Langhofff396f012006-05-23 00:45:47 +1200799 @skipped = ();
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300800 }
801
Jeff Kinge73aefe2006-05-23 03:27:46 -0400802 print($commit_write "$logmsg\n") && close($commit_write)
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200803 or die "Error writing to git-commit-tree: $!\n";
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200804
Jeff Kinge73aefe2006-05-23 03:27:46 -0400805 print "Committed patch $patchset ($branch $commit_date)\n" if $opt_v;
806 chomp(my $cid = <$commit_read>);
807 is_sha1($cid) or die "Cannot get commit id ($cid): $!\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200808 print "Commit ID $cid\n" if $opt_v;
Jeff Kinge73aefe2006-05-23 03:27:46 -0400809 close($commit_read);
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200810
811 waitpid($pid,0);
812 die "Error running git-commit-tree: $?\n" if $?;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200813
Jeff Kingb3bb5f72008-04-30 00:36:14 -0400814 system('git-update-ref', "$remote/$branch", $cid) == 0
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200815 or die "Cannot write branch $branch for update: $!\n";
816
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800817 if ($tag) {
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800818 my ($xtag) = $tag;
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700819 $xtag =~ s/\s+\*\*.*$//; # Remove stuff like ** INVALID ** and ** FUNKY **
820 $xtag =~ tr/_/\./ if ( $opt_u );
Joe English34c99da2006-01-06 12:52:27 -0800821 $xtag =~ s/[\/]/$opt_s/g;
Paul Oliver509792b2008-05-23 19:29:22 +0100822 $xtag =~ s/\[//g;
Junio C Hamanoa6080a02007-06-07 00:04:01 -0700823
Michael Smithee834cf2007-09-07 17:35:07 -0400824 system('git-tag', '-f', $xtag, $cid) == 0
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700825 or die "Cannot create tag $xtag: $!\n";
H. Peter Anvin0d821d42005-09-06 10:36:01 -0700826
827 print "Created tag '$xtag' on '$branch'\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200828 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200829};
830
Martin Langhoff06918342006-05-22 23:38:08 +1200831my $commitcount = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800832while (<CVS>) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200833 chomp;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800834 if ($state == 0 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200835 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800836 } elsif ($state == 0) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200837 $state = 1;
838 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800839 } elsif (($state==0 or $state==1) and s/^PatchSet\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200840 $patchset = 0+$_;
841 $state=2;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800842 } elsif ($state == 2 and s/^Date:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200843 $date = pdate($_);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800844 unless ($date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200845 print STDERR "Could not parse date: $_\n";
846 $state=0;
847 next;
848 }
849 $state=3;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800850 } elsif ($state == 3 and s/^Author:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200851 s/\s+$//;
Junio C Hamano94c23342005-09-30 01:48:57 -0700852 if (/^(.*?)\s+<(.*)>/) {
853 ($author_name, $author_email) = ($1, $2);
Andreas Ericssonffd97f32006-01-13 00:38:59 +0100854 } elsif ($conv_author_name{$_}) {
855 $author_name = $conv_author_name{$_};
856 $author_email = $conv_author_email{$_};
Junio C Hamano94c23342005-09-30 01:48:57 -0700857 } else {
858 $author_name = $author_email = $_;
859 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200860 $state = 4;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800861 } elsif ($state == 4 and s/^Branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200862 s/\s+$//;
Gerrit Papea0554222007-11-03 11:55:02 +0000863 tr/_/\./ if ( $opt_u );
Johannes Schindelinfbfd60d2005-08-17 11:19:20 +0200864 s/[\/]/$opt_s/g;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200865 $branch = $_;
866 $state = 5;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800867 } elsif ($state == 5 and s/^Ancestor branch:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200868 s/\s+$//;
869 $ancestor = $_;
Sven Verdoolaege0fa28242005-06-30 17:23:22 +0200870 $ancestor = $opt_o if $ancestor eq "HEAD";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200871 $state = 6;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800872 } elsif ($state == 5) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200873 $ancestor = undef;
874 $state = 6;
875 redo;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800876 } elsif ($state == 6 and s/^Tag:\s+//) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200877 s/\s+$//;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800878 if ($_ eq "(none)") {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200879 $tag = undef;
880 } else {
881 $tag = $_;
882 }
883 $state = 7;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800884 } elsif ($state == 7 and /^Log:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200885 $logmsg = "";
886 $state = 8;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800887 } elsif ($state == 8 and /^Members:/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200888 $branch = $opt_o if $branch eq "HEAD";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800889 if (defined $branch_date{$branch} and $branch_date{$branch} >= $date) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200890 # skip
Matthias Urlichs9da07f32005-07-03 19:03:30 +0200891 print "skip patchset $patchset: $date before $branch_date{$branch}\n" if $opt_v;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200892 $state = 11;
893 next;
894 }
Martin Langhoffded9f402007-01-08 19:43:39 +1300895 if (!$opt_a && $starttime - 300 - (defined $opt_z ? $opt_z : 300) <= $date) {
Martin Langhoff62119882007-01-08 14:11:23 +1300896 # skip if the commit is too recent
Stefan Sperling77190eb2007-12-21 16:57:26 +0100897 # given that the cvsps default fuzz is 300s, we give ourselves another
Martin Langhoff62119882007-01-08 14:11:23 +1300898 # 300s just in case -- this also prevents skipping commits
899 # due to server clock drift
900 print "skip patchset $patchset: $date too recent\n" if $opt_v;
901 $state = 11;
902 next;
903 }
Martin Langhoff71b08142006-06-11 20:12:09 +1200904 if (exists $ignorebranch{$branch}) {
905 print STDERR "Skipping $branch\n";
906 $state = 11;
907 next;
908 }
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800909 if ($ancestor) {
910 if ($ancestor eq $branch) {
Martin Langhoff71b08142006-06-11 20:12:09 +1200911 print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n";
912 $ancestor = $opt_o;
913 }
Jeff King0750d752007-11-28 13:56:28 -0500914 if (defined get_headref("$remote/$branch")) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200915 print STDERR "Branch $branch already exists!\n";
916 $state=11;
917 next;
918 }
Jeff King0750d752007-11-28 13:56:28 -0500919 my $id = get_headref("$remote/$ancestor");
920 if (!$id) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200921 print STDERR "Branch $ancestor does not exist!\n";
Martin Langhoff71b08142006-06-11 20:12:09 +1200922 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200923 $state=11;
924 next;
925 }
Jeff King0750d752007-11-28 13:56:28 -0500926
927 system(qw(git update-ref -m cvsimport),
928 "$remote/$branch", $id);
929 if($? != 0) {
930 print STDERR "Could not create branch $branch\n";
Martin Langhoff71b08142006-06-11 20:12:09 +1200931 $ignorebranch{$branch} = 1;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200932 $state=11;
933 next;
934 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200935 }
Sven Verdoolaege46e63ef2005-07-04 15:28:36 +0200936 $last_branch = $branch if $branch ne $last_branch;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200937 $state = 9;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800938 } elsif ($state == 8) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200939 $logmsg .= "$_\n";
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800940 } elsif ($state == 9 and /^\s+(.+?):(INITIAL|\d+(?:\.\d+)+)->(\d+(?:\.\d+)+)\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200941# VERSION:1.96->1.96.2.1
Matthias Urlichs2a3e1a82005-06-28 19:49:19 +0200942 my $init = ($2 eq "INITIAL");
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200943 my $fn = $1;
Matthias Urlichsf65ae602005-06-28 19:58:40 +0200944 my $rev = $3;
945 $fn =~ s#^/+##;
Martin Langhoff5179c8a2006-01-30 19:12:41 +1300946 if ($opt_S && $fn =~ m/$opt_S/) {
947 print "SKIPPING $fn v $rev\n";
948 push(@skipped, $fn);
949 next;
950 }
951 print "Fetching $fn v $rev\n" if $opt_v;
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200952 my ($tmpname, $size) = $cvs->file($fn,$rev);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800953 if ($size == -1) {
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200954 push(@old,$fn);
955 print "Drop $fn\n" if $opt_v;
956 } else {
957 print "".($init ? "New" : "Update")." $fn: $size bytes\n" if $opt_v;
Junio C Hamanodd274782006-02-20 14:17:28 -0800958 my $pid = open(my $F, '-|');
959 die $! unless defined $pid;
960 if (!$pid) {
961 exec("git-hash-object", "-w", $tmpname)
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200962 or die "Cannot create object: $!\n";
Junio C Hamanodd274782006-02-20 14:17:28 -0800963 }
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200964 my $sha = <$F>;
965 chomp $sha;
966 close $F;
967 my $mode = pmode($cvs->{'mode'});
968 push(@new,[$mode, $sha, $fn]); # may be resurrected!
969 }
Sven Verdoolaege2eb6d822005-07-04 00:43:26 +0200970 unlink($tmpname);
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800971 } elsif ($state == 9 and /^\s+(.+?):\d+(?:\.\d+)+->(\d+(?:\.\d+)+)\(DEAD\)\s*$/) {
Matthias Urlichsf65ae602005-06-28 19:58:40 +0200972 my $fn = $1;
973 $fn =~ s#^/+##;
974 push(@old,$fn);
Matthias Urlichs8b8840e2005-08-15 11:28:19 +0200975 print "Delete $fn\n" if $opt_v;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800976 } elsif ($state == 9 and /^\s*$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200977 $state = 10;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800978 } elsif (($state == 9 or $state == 10) and /^-+$/) {
Linus Torvalds4adcea92006-05-22 19:28:37 -0700979 $commitcount++;
980 if ($opt_L && $commitcount > $opt_L) {
Martin Langhoff06918342006-05-22 23:38:08 +1200981 last;
982 }
Martin Langhoffc4b16f82006-05-23 00:45:39 +1200983 commit();
Linus Torvalds4adcea92006-05-22 19:28:37 -0700984 if (($commitcount & 1023) == 0) {
985 system("git repack -a -d");
986 }
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200987 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800988 } elsif ($state == 11 and /^-+$/) {
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200989 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800990 } elsif (/^-+$/) { # end of unknown-line processing
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200991 $state = 1;
Junio C Hamano86d11cf2006-11-27 14:21:30 -0800992 } elsif ($state != 11) { # ignore stuff when skipping
Jim Meyering3be39992008-08-05 16:54:42 +0200993 print STDERR "* UNKNOWN LINE * $_\n";
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200994 }
995}
Martin Langhoffc4b16f82006-05-23 00:45:39 +1200996commit() if $branch and $state != 11;
Matthias Urlichsa57a9492005-06-28 16:48:40 +0200997
Martin Langhoff4083c2f2007-01-08 21:08:46 +1300998unless ($opt_P) {
999 unlink($cvspsfile);
1000}
1001
Jim Meyeringefe4abd2006-11-15 21:15:44 +01001002# The heuristic of repacking every 1024 commits can leave a
1003# lot of unpacked data. If there is more than 1MB worth of
1004# not-packed objects, repack once more.
1005my $line = `git-count-objects`;
1006if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) {
1007 my ($n_objects, $kb) = ($1, $2);
1008 1024 < $kb
1009 and system("git repack -a -d");
1010}
1011
Martin Langhoff8f732642006-06-12 23:50:49 +12001012foreach my $git_index (values %index) {
Michael Milligan23fcdc72007-06-05 00:06:30 -06001013 if ($git_index ne "$git_dir/index") {
Martin Langhoffc5f448b2006-06-28 22:13:23 +12001014 unlink($git_index);
1015 }
Martin Langhoff8f732642006-06-12 23:50:49 +12001016}
Sven Verdoolaege79ee4562005-07-04 13:36:59 +02001017
Sven Verdoolaege210569f2005-07-05 13:19:59 +02001018if (defined $orig_git_index) {
1019 $ENV{GIT_INDEX_FILE} = $orig_git_index;
1020} else {
1021 delete $ENV{GIT_INDEX_FILE};
1022}
1023
Matthias Urlichs46541662005-06-28 21:08:15 +02001024# Now switch back to the branch we were in before all of this happened
Junio C Hamano86d11cf2006-11-27 14:21:30 -08001025if ($orig_branch) {
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001026 print "DONE.\n" if $opt_v;
1027 if ($opt_i) {
1028 exit 0;
1029 }
1030 my $tip_at_end = `git-rev-parse --verify HEAD`;
1031 if ($tip_at_start ne $tip_at_end) {
Junio C Hamanocb9594e2006-03-18 02:05:02 -08001032 for ($tip_at_start, $tip_at_end) { chomp; }
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001033 print "Fetched into the current branch.\n" if $opt_v;
1034 system(qw(git-read-tree -u -m),
1035 $tip_at_start, $tip_at_end);
1036 die "Fast-forward update failed: $?\n" if $?;
1037 }
1038 else {
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +01001039 system(qw(git-merge cvsimport HEAD), "$remote/$opt_o");
Junio C Hamano8a5f2ea2006-03-17 14:08:39 -08001040 die "Could not merge $opt_o into the current branch.\n" if $?;
1041 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001042} else {
1043 $orig_branch = "master";
1044 print "DONE; creating $orig_branch branch\n" if $opt_v;
Andy Whitcroft8b7f5fc2007-05-30 01:56:41 +01001045 system("git-update-ref", "refs/heads/master", "$remote/$opt_o")
Jeff King0750d752007-11-28 13:56:28 -05001046 unless defined get_headref('refs/heads/master');
Andy Whitcroft06baffd2007-06-04 10:01:49 +01001047 system("git-symbolic-ref", "$remote/HEAD", "$remote/$opt_o")
1048 if ($opt_r && $opt_o ne 'HEAD');
Pavel Roskin8366a102005-11-16 13:27:28 -05001049 system('git-update-ref', 'HEAD', "$orig_branch");
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001050 unless ($opt_i) {
Gerrit Pape7051c3b2007-06-28 11:12:07 +00001051 system('git checkout -f');
Sven Verdoolaegec1c774e2005-07-11 16:57:49 +02001052 die "checkout failed: $?\n" if $?;
1053 }
Matthias Urlichs46541662005-06-28 21:08:15 +02001054}