X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-cvsimport.perl;h=4310dea1320efa47eee2861b4f886197ca713a2e;hb=747fa12cef73b6ca04fffaddaad7326cf546cdea;hp=af331d9c4316a56db7bd4b3cfb4f1d5d8d5f6de5;hpb=f2054be4c4816d8c363dc867f462bc0af9031c02;p=git.git diff --git a/git-cvsimport.perl b/git-cvsimport.perl index af331d9c4..4310dea13 100755 --- a/git-cvsimport.perl +++ b/git-cvsimport.perl @@ -17,13 +17,13 @@ use strict; use warnings; use Getopt::Std; use File::Spec; -use File::Temp qw(tempfile); +use File::Temp qw(tempfile tmpnam); use File::Path qw(mkpath); use File::Basename qw(basename dirname); use Time::Local; use IO::Socket; use IO::Pipe; -use POSIX qw(strftime dup2 :errno_h); +use POSIX qw(strftime dup2 ENOENT); use IPC::Open2; $SIG{'PIPE'}="IGNORE"; @@ -161,8 +161,22 @@ sub new { sub conn { my $self = shift; my $repo = $self->{'fullrep'}; - if($repo =~ s/^:pserver:(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) { - my($user,$pass,$serv,$port) = ($1,$2,$3,$4); + if($repo =~ s/^:pserver(?:([^:]*)):(?:(.*?)(?::(.*?))?@)?([^:\/]*)(?::(\d*))?//) { + my($param,$user,$pass,$serv,$port) = ($1,$2,$3,$4,$5); + + my($proxyhost,$proxyport); + if($param && ($param =~ m/proxy=([^;]+)/)) { + $proxyhost = $1; + # Default proxyport, if not specified, is 8080. + $proxyport = 8080; + if($ENV{"CVS_PROXY_PORT"}) { + $proxyport = $ENV{"CVS_PROXY_PORT"}; + } + if($param =~ m/proxyport=([^;]+)/){ + $proxyport = $1; + } + } + $user="anonymous" unless defined $user; my $rr2 = "-"; unless($port) { @@ -187,13 +201,43 @@ sub conn { } $pass="A" unless $pass; - my $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port); - die "Socket to $serv: $!\n" unless defined $s; + my ($s, $rep); + if($proxyhost) { + + # Use a HTTP Proxy. Only works for HTTP proxies that + # don't require user authentication + # + # See: http://www.ietf.org/rfc/rfc2817.txt + + $s = IO::Socket::INET->new(PeerHost => $proxyhost, PeerPort => $proxyport); + die "Socket to $proxyhost: $!\n" unless defined $s; + $s->write("CONNECT $serv:$port HTTP/1.1\r\nHost: $serv:$port\r\n\r\n") + or die "Write to $proxyhost: $!\n"; + $s->flush(); + + $rep = <$s>; + + # The answer should look like 'HTTP/1.x 2yy ....' + if(!($rep =~ m#^HTTP/1\.. 2[0-9][0-9]#)) { + die "Proxy connect: $rep\n"; + } + # Skip up to the empty line of the proxy server output + # including the response headers. + while ($rep = <$s>) { + last if (!defined $rep || + $rep eq "\n" || + $rep eq "\r\n"); + } + } else { + $s = IO::Socket::INET->new(PeerHost => $serv, PeerPort => $port); + die "Socket to $serv: $!\n" unless defined $s; + } + $s->write("BEGIN AUTH REQUEST\n$repo\n$user\n$pass\nEND AUTH REQUEST\n") or die "Write to $serv: $!\n"; $s->flush(); - my $rep = <$s>; + $rep = <$s>; if($rep ne "I LOVE YOU\n") { $rep="" unless $rep; @@ -465,10 +509,9 @@ $git_dir = getwd()."/".$git_dir unless $git_dir =~ m#^/#; $ENV{"GIT_DIR"} = $git_dir; my $orig_git_index; $orig_git_index = $ENV{GIT_INDEX_FILE} if exists $ENV{GIT_INDEX_FILE}; -my ($git_ih, $git_index) = tempfile('gitXXXXXX', SUFFIX => '.idx', - DIR => File::Spec->tmpdir()); -close ($git_ih); -$ENV{GIT_INDEX_FILE} = $git_index; + +my %index; # holds filenames of one index per branch + unless(-d $git_dir) { system("git-init-db"); die "Cannot init the GIT db at $git_tree: $?\n" if $?; @@ -495,27 +538,18 @@ unless(-d $git_dir) { $orig_branch = $last_branch; $tip_at_start = `git-rev-parse --verify HEAD`; - # populate index - system('git-read-tree', $last_branch); - die "read-tree failed: $?\n" if $?; - # Get the last import timestamps - opendir(D,"$git_dir/refs/heads"); - while(defined(my $head = readdir(D))) { - next if $head =~ /^\./; - open(F,"$git_dir/refs/heads/$head") - or die "Bad head branch: $head: $!\n"; - chomp(my $ftag = ); - close(F); - open(F,"git-cat-file commit $ftag |"); - while() { - next unless /^author\s.*\s(\d+)\s[-+]\d{4}$/; - $branch_date{$head} = $1; - last; - } - close(F); + my $fmt = '($ref, $author) = (%(refname), %(author));'; + open(H, "git-for-each-ref --perl --format='$fmt' refs/heads |") or + die "Cannot run git-for-each-ref: $!\n"; + while(defined(my $entry = )) { + my ($ref, $author); + eval($entry) || die "cannot eval refs list: $@"; + my ($head) = ($ref =~ m|^refs/heads/(.*)|); + $author =~ /^.*\s(\d+)\s[-+]\d{4}$/; + $branch_date{$head} = $1; } - closedir(D); + close(H); } -d $git_dir @@ -529,25 +563,39 @@ if ($opt_A) { write_author_info("$git_dir/cvs-authors"); } -my $pid = open(CVS,"-|"); -die "Cannot fork: $!\n" unless defined $pid; -unless($pid) { - my @opt; - @opt = split(/,/,$opt_p) if defined $opt_p; - unshift @opt, '-z', $opt_z if defined $opt_z; - unshift @opt, '-q' unless defined $opt_v; - unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) { - push @opt, '--cvs-direct'; + +# +# run cvsps into a file unless we are getting +# it passed as a file via $opt_P +# +unless ($opt_P) { + print "Running cvsps...\n" if $opt_v; + my $pid = open(CVSPS,"-|"); + die "Cannot fork: $!\n" unless defined $pid; + unless($pid) { + my @opt; + @opt = split(/,/,$opt_p) if defined $opt_p; + unshift @opt, '-z', $opt_z if defined $opt_z; + unshift @opt, '-q' unless defined $opt_v; + unless (defined($opt_p) && $opt_p =~ m/--no-cvs-direct/) { + push @opt, '--cvs-direct'; + } + exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree); + die "Could not start cvsps: $!\n"; } - if ($opt_P) { - exec("cat", $opt_P); - } else { - exec("cvsps","--norc",@opt,"-u","-A",'--root',$opt_d,$cvs_tree); - die "Could not start cvsps: $!\n"; + my ($cvspsfh, $cvspsfile) = tempfile('gitXXXXXX', SUFFIX => '.cvsps', + DIR => File::Spec->tmpdir()); + while () { + print $cvspsfh $_; } + close CVSPS; + close $cvspsfh; + $opt_P = $cvspsfile; } +open(CVS, "<$opt_P") or die $!; + ## cvsps output: #--------------------- #PatchSet 314 @@ -595,8 +643,33 @@ sub write_tree () { } my($patchset,$date,$author_name,$author_email,$branch,$ancestor,$tag,$logmsg); -my(@old,@new,@skipped); +my(@old,@new,@skipped,%ignorebranch); + +# commits that cvsps cannot place anywhere... +$ignorebranch{'#CVSPS_NO_BRANCH'} = 1; + sub commit { + if ($branch eq $opt_o && !$index{branch} && !get_headref($branch, $git_dir)) { + # looks like an initial commit + # use the index primed by git-init-db + $ENV{GIT_INDEX_FILE} = '.git/index'; + $index{$branch} = '.git/index'; + } else { + # use an index per branch to speed up + # imports of projects with many branches + unless ($index{$branch}) { + $index{$branch} = tmpnam(); + $ENV{GIT_INDEX_FILE} = $index{$branch}; + if ($ancestor) { + system("git-read-tree", $ancestor); + } else { + system("git-read-tree", $branch); + } + die "read-tree failed: $?\n" if $?; + } + } + $ENV{GIT_INDEX_FILE} = $index{$branch}; + update_index(@old, @new); @old = @new = (); my $tree = write_tree(); @@ -751,7 +824,16 @@ while() { $state = 11; next; } + if (exists $ignorebranch{$branch}) { + print STDERR "Skipping $branch\n"; + $state = 11; + next; + } if($ancestor) { + if($ancestor eq $branch) { + print STDERR "Branch $branch erroneously stems from itself -- changed ancestor to $opt_o\n"; + $ancestor = $opt_o; + } if(-f "$git_dir/refs/heads/$branch") { print STDERR "Branch $branch already exists!\n"; $state=11; @@ -759,6 +841,7 @@ while() { } unless(open(H,"$git_dir/refs/heads/$ancestor")) { print STDERR "Branch $ancestor does not exist!\n"; + $ignorebranch{$branch} = 1; $state=11; next; } @@ -766,6 +849,7 @@ while() { close(H); unless(open(H,"> $git_dir/refs/heads/$branch")) { print STDERR "Could not create branch $branch: $!\n"; + $ignorebranch{$branch} = 1; $state=11; next; } @@ -774,11 +858,6 @@ while() { close(H) or die "Could not write branch $branch: $!"; } - if(($ancestor || $branch) ne $last_branch) { - print "Switching from $last_branch to $branch\n" if $opt_v; - system("git-read-tree", $branch); - die "read-tree failed: $?\n" if $?; - } $last_branch = $branch if $branch ne $last_branch; $state = 9; } elsif($state == 8) { @@ -841,7 +920,21 @@ while() { } commit() if $branch and $state != 11; -unlink($git_index); +# The heuristic of repacking every 1024 commits can leave a +# lot of unpacked data. If there is more than 1MB worth of +# not-packed objects, repack once more. +my $line = `git-count-objects`; +if ($line =~ /^(\d+) objects, (\d+) kilobytes$/) { + my ($n_objects, $kb) = ($1, $2); + 1024 < $kb + and system("git repack -a -d"); +} + +foreach my $git_index (values %index) { + if ($git_index ne '.git/index') { + unlink($git_index); + } +} if (defined $orig_git_index) { $ENV{GIT_INDEX_FILE} = $orig_git_index;