X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=git-svnimport.perl;h=639aa41861a734aab225479be7524c972191da70;hb=3443546f6ef57fe28ea5cca232df8e400bfc3883;hp=cb241d1b5174fad6b6eb081635e614d251688f0d;hpb=988eece42aa4c1c6b7c4cdfd102748c19acba7ed;p=git.git diff --git a/git-svnimport.perl b/git-svnimport.perl index cb241d1b..639aa418 100755 --- a/git-svnimport.perl +++ b/git-svnimport.perl @@ -10,10 +10,10 @@ # The head revision is on branch "origin" by default. # You can change that with the '-o' option. -require 5.008; # for shell-safe open("-|",LIST) use strict; use warnings; use Getopt::Std; +use File::Copy; use File::Spec; use File::Temp qw(tempfile); use File::Path qw(mkpath); @@ -30,19 +30,21 @@ die "Need SVN:Core 1.2.1 or better" if $SVN::Core::VERSION lt "1.2.1"; $SIG{'PIPE'}="IGNORE"; $ENV{'TZ'}="UTC"; -our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T,$opt_b,$opt_s,$opt_l,$opt_d,$opt_D); +our($opt_h,$opt_o,$opt_v,$opt_u,$opt_C,$opt_i,$opt_m,$opt_M,$opt_t,$opt_T, + $opt_b,$opt_r,$opt_I,$opt_A,$opt_s,$opt_l,$opt_d,$opt_D); sub usage() { print STDERR <rel2abs($opt_A) if $opt_A; + +our %users = (); +our $users_file = undef; +sub read_users($) { + $users_file = File::Spec->rel2abs(@_); + die "Cannot open $users_file\n" unless -f $users_file; + open(my $authors,$users_file); + while(<$authors>) { + chomp; + next unless /^(\S+?)\s*=\s*(.+?)\s*<(.+)>\s*$/; + (my $user,my $name,my $email) = ($1,$2,$3); + $users{$user} = [$name,$email]; + } + close($authors); +} + select(STDERR); $|=1; select(STDOUT); @@ -96,8 +117,10 @@ sub new { sub conn { my $self = shift; my $repo = $self->{'fullrep'}; - my $s = SVN::Ra->new($repo); - + my $auth = SVN::Core::auth_open ([SVN::Client::get_simple_provider, + SVN::Client::get_ssl_server_trust_file_provider, + SVN::Client::get_username_provider]); + my $s = SVN::Ra->new(url => $repo, auth => $auth); die "SVN connection to $repo: $!\n" unless defined $s; $self->{'svn'} = $s; $self->{'repo'} = $repo; @@ -111,16 +134,40 @@ sub file { DIR => File::Spec->tmpdir(), UNLINK => 1); print "... $rev $path ...\n" if $opt_v; - my $pool = SVN::Pool->new(); - eval { $self->{'svn'}->get_file($path,$rev,$fh,$pool); }; - $pool->clear; + my (undef, $properties); + eval { (undef, $properties) + = $self->{'svn'}->get_file($path,$rev,$fh); }; if($@) { return undef if $@ =~ /Attempted to get checksum/; die $@; } + my $mode; + if (exists $properties->{'svn:executable'}) { + $mode = '0755'; + } else { + $mode = '0644'; + } close ($fh); - return $name; + return ($name, $mode); +} + +sub ignore { + my($self,$path,$rev) = @_; + + print "... $rev $path ...\n" if $opt_v; + my (undef,undef,$properties) + = $self->{'svn'}->get_dir($path,$rev,undef); + if (exists $properties->{'svn:ignore'}) { + my ($fh, $name) = tempfile('gitsvn.XXXXXX', + DIR => File::Spec->tmpdir(), + UNLINK => 1); + print $fh $properties->{'svn:ignore'}; + close($fh); + return $name; + } else { + return undef; + } } package main; @@ -262,6 +309,14 @@ EOM -d $git_dir or die "Could not create git subdir ($git_dir).\n"; +my $default_authors = "$git_dir/svn-authors"; +if ($opt_A) { + read_users($opt_A); + copy($opt_A,$default_authors) or die "Copy failed: $!"; +} else { + read_users($default_authors) if -f $default_authors; +} + open BRANCHES,">>", "$git_dir/svn2git"; sub node_kind($$$) { @@ -295,7 +350,7 @@ sub get_file($$$) { my $svnpath = revert_split_path($branch,$path); # now get it - my $name; + my ($name,$mode); if($opt_d) { my($req,$res); @@ -315,21 +370,53 @@ sub get_file($$$) { return undef if $res->code == 301; # directory? die $res->status_line." at $url\n"; } + $mode = '0644'; # can't obtain mode via direct http request? } else { - $name = $svn->file("/$svnpath",$rev); + ($name,$mode) = $svn->file("$svnpath",$rev); return undef unless defined $name; } - open my $F, '-|', "git-hash-object", "-w", $name + my $pid = open(my $F, '-|'); + die $! unless defined $pid; + if (!$pid) { + exec("git-hash-object", "-w", $name) or die "Cannot create object: $!\n"; + } my $sha = <$F>; chomp $sha; close $F; unlink $name; - my $mode = "0644"; # SV does not seem to store any file modes return [$mode, $sha, $path]; } +sub get_ignore($$$$$) { + my($new,$old,$rev,$branch,$path) = @_; + + return unless $opt_I; + my $svnpath = revert_split_path($branch,$path); + my $name = $svn->ignore("$svnpath",$rev); + if ($path eq '/') { + $path = $opt_I; + } else { + $path = File::Spec->catfile($path,$opt_I); + } + if (defined $name) { + my $pid = open(my $F, '-|'); + die $! unless defined $pid; + if (!$pid) { + exec("git-hash-object", "-w", $name) + or die "Cannot create object: $!\n"; + } + my $sha = <$F>; + chomp $sha; + close $F; + unlink $name; + push(@$new,['0644',$sha,$path]); + } else { + push(@$old,$path); + } +} + sub split_path($$) { my($rev,$path) = @_; my $branch; @@ -396,7 +483,12 @@ sub copy_path($$$$$$$$) { $srcpath =~ s#/*$#/#; } - open my $f,"-|","git-ls-tree","-r","-z",$gitrev,$srcpath; + my $pid = open my $f,'-|'; + die $! unless defined $pid; + if (!$pid) { + exec("git-ls-tree","-r","-z",$gitrev,$srcpath) + or die $!; + } local $/ = "\0"; while(<$f>) { chomp; @@ -421,6 +513,10 @@ sub commit { if (not defined $author) { $author_name = $author_email = "unknown"; + } elsif (defined $users_file) { + die "User $author is not listed in $users_file\n" + unless exists $users{$author}; + ($author_name,$author_email) = @{$users{$author}}; } elsif ($author =~ /^(.*?)\s+<(.*)>$/) { ($author_name, $author_email) = ($1, $2); } else { @@ -530,6 +626,9 @@ sub commit { my $opath = $action->[3]; print STDERR "$revision: $branch: could not fetch '$opath'\n"; } + } elsif ($node_kind eq $SVN::Node::dir) { + get_ignore(\@new, \@old, $revision, + $branch,$path); } } elsif ($action->[0] eq "D") { push(@old,$path); @@ -538,29 +637,43 @@ sub commit { if ($node_kind eq $SVN::Node::file) { my $f = get_file($revision,$branch,$path); push(@new,$f) if $f; + } elsif ($node_kind eq $SVN::Node::dir) { + get_ignore(\@new, \@old, $revision, + $branch,$path); } } else { die "$revision: unknown action '".$action->[0]."' for $path\n"; } } - if(@old) { - open my $F, "-|", "git-ls-files", "-z", @old or die $!; - @old = (); + while(@old) { + my @o1; + if(@old > 55) { + @o1 = splice(@old,0,50); + } else { + @o1 = @old; + @old = (); + } + my $pid = open my $F, "-|"; + die "$!" unless defined $pid; + if (!$pid) { + exec("git-ls-files", "-z", @o1) or die $!; + } + @o1 = (); local $/ = "\0"; while(<$F>) { chomp; - push(@old,$_); + push(@o1,$_); } close($F); - while(@old) { + while(@o1) { my @o2; - if(@old > 55) { - @o2 = splice(@old,0,50); + if(@o1 > 55) { + @o2 = splice(@o1,0,50); } else { - @o2 = @old; - @old = (); + @o2 = @o1; + @o1 = (); } system("git-update-index","--force-remove","--",@o2); die "Cannot remove files: $?\n" if $?; @@ -641,6 +754,7 @@ sub commit { $pr->reader(); $message =~ s/[\s\n]+\z//; + $message = "r$revision: $message" if $opt_r; print $pw "$message\n" or die "Error writing to git-commit-tree: $!\n";