X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=git-svn.perl;h=ecacf74c22b1d74fc17e5dbab511b86d127f2eb9;hb=eaa2a6fc84bc02c1356353f7364e976e46133e98;hp=4dc33801a88c63f62a263b5008649b05fc1b9d7d;hpb=00b718e02d97c956cade8c1b4cbe29a9d3e92765;p=git.git diff --git a/git-svn.perl b/git-svn.perl index 4dc33801a..ecacf74c2 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -421,15 +421,15 @@ sub cmd_dcommit { $head ||= 'HEAD'; my @refs; my ($url, $rev, $uuid, $gs) = working_head_info($head, \@refs); - $url = $_commit_url if defined $_commit_url; - my $last_rev = $_revision if defined $_revision; - if ($url) { - print "Committing to $url ...\n"; - } unless ($gs) { die "Unable to determine upstream SVN information from ", "$head history.\nPerhaps the repository is empty."; } + $url = defined $_commit_url ? $_commit_url : $gs->full_url; + my $last_rev = $_revision if defined $_revision; + if ($url) { + print "Committing to $url ...\n"; + } my ($linear_refs, $parents) = linearize_history($gs, \@refs); if ($_no_rebase && scalar(@$linear_refs) > 1) { warn "Attempting to commit more than one change while ", @@ -437,6 +437,8 @@ sub cmd_dcommit { "If these changes depend on each other, re-running ", "without --no-rebase may be required." } + my $expect_url = $url; + Git::SVN::remove_username($expect_url); while (1) { my $d = shift @$linear_refs or last; unless (defined $last_rev) { @@ -511,9 +513,9 @@ sub cmd_dcommit { $gs->refname, "\nBefore dcommitting"; } - if ($url_ ne $url) { + if ($url_ ne $expect_url) { fatal "URL mismatch after rebase: ", - "$url_ != $url"; + "$url_ != $expect_url"; } if ($uuid_ ne $uuid) { fatal "uuid mismatch after rebase: ", @@ -801,8 +803,28 @@ sub cmd_commit_diff { } } +sub escape_uri_only { + my ($uri) = @_; + my @tmp; + foreach (split m{/}, $uri) { + s/([^\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; + push @tmp, $_; + } + join('/', @tmp); +} + +sub escape_url { + my ($url) = @_; + if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) { + my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3)); + $url = "$scheme://$domain$uri"; + } + $url; +} + sub cmd_info { my $path = canonicalize_path(defined($_[0]) ? $_[0] : "."); + my $fullpath = canonicalize_path($cmd_dir_prefix . $path); if (exists $_[1]) { die "Too many arguments specified\n"; } @@ -810,8 +832,8 @@ sub cmd_info { my ($file_type, $diff_status) = find_file_type_and_diff_status($path); if (!$file_type && !$diff_status) { - print STDERR "$path: (Not a versioned resource)\n\n"; - return; + print STDERR "svn: '$path' is not under version control\n"; + exit 1; } my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); @@ -823,21 +845,21 @@ sub cmd_info { # canonicalize_path() will return "" to make libsvn 1.5.x happy, $path = "." if $path eq ""; - my $full_url = $url . ($path eq "." ? "" : "/$path"); + my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath"); if ($_url) { - print $full_url, "\n"; + print escape_url($full_url), "\n"; return; } my $result = "Path: $path\n"; $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir"; - $result .= "URL: " . $full_url . "\n"; + $result .= "URL: " . escape_url($full_url) . "\n"; eval { my $repos_root = $gs->repos_root; Git::SVN::remove_username($repos_root); - $result .= "Repository Root: $repos_root\n"; + $result .= "Repository Root: " . escape_url($repos_root) . "\n"; }; if ($@) { $result .= "Repository Root: (offline)\n"; @@ -859,7 +881,7 @@ sub cmd_info { } my ($lc_author, $lc_rev, $lc_date_utc); - my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $path); + my @args = Git::SVN::Log::git_svn_log_cmd($rev, $rev, "--", $fullpath); my $log = command_output_pipe(@args); my $esc_color = qr/(?:\033\[(?:(?:\d+;)*\d*)?m)*/; while (<$log>) { @@ -1265,7 +1287,7 @@ sub md5sum { my $arg = shift; my $ref = ref $arg; my $md5 = Digest::MD5->new(); - if ($ref eq 'GLOB' || $ref eq 'IO::File') { + if ($ref eq 'GLOB' || $ref eq 'IO::File' || $ref eq 'File::Temp') { $md5->addfile($arg) or croak $!; } elsif ($ref eq 'SCALAR') { $md5->add($$arg) or croak $!; @@ -1328,6 +1350,7 @@ BEGIN { } } + my (%LOCKFILES, %INDEX_FILES); END { unlink keys %LOCKFILES if %LOCKFILES; @@ -3230,13 +3253,11 @@ sub change_file_prop { sub apply_textdelta { my ($self, $fb, $exp) = @_; - my $fh = IO::File->new_tmpfile; - $fh->autoflush(1); + my $fh = Git::temp_acquire('svn_delta'); # $fh gets auto-closed() by SVN::TxDelta::apply(), # (but $base does not,) so dup() it for reading in close_file open my $dup, '<&', $fh or croak $!; - my $base = IO::File->new_tmpfile; - $base->autoflush(1); + my $base = Git::temp_acquire('git_blob'); if ($fb->{blob}) { print $base 'link ' if ($fb->{mode_a} == 120000); my $size = $::_repository->cat_blob($fb->{blob}, $base); @@ -3251,9 +3272,9 @@ sub apply_textdelta { } } seek $base, 0, 0 or croak $!; - $fb->{fh} = $dup; + $fb->{fh} = $fh; $fb->{base} = $base; - [ SVN::TxDelta::apply($base, $fh, undef, $fb->{path}, $fb->{pool}) ]; + [ SVN::TxDelta::apply($base, $dup, undef, $fb->{path}, $fb->{pool}) ]; } sub close_file { @@ -3269,35 +3290,36 @@ sub close_file { "expected: $exp\n got: $got\n"; } } - sysseek($fh, 0, 0) or croak $!; if ($fb->{mode_b} == 120000) { - eval { - sysread($fh, my $buf, 5) == 5 or croak $!; - $buf eq 'link ' or die "$path has mode 120000", - " but is not a link"; - }; - if ($@) { - warn "$@\n"; - sysseek($fh, 0, 0) or croak $!; - } - } + sysseek($fh, 0, 0) or croak $!; + sysread($fh, my $buf, 5) == 5 or croak $!; - my ($tmp_fh, $tmp_filename) = File::Temp::tempfile(UNLINK => 1); - my $result; - while ($result = sysread($fh, my $string, 1024)) { - my $wrote = syswrite($tmp_fh, $string, $result); - defined($wrote) && $wrote == $result - or croak("write $tmp_filename: $!\n"); - } - defined $result or croak $!; - close $tmp_fh or croak $!; + unless ($buf eq 'link ') { + warn "$path has mode 120000", + " but is not a link\n"; + } else { + my $tmp_fh = Git::temp_acquire('svn_hash'); + my $res; + while ($res = sysread($fh, my $str, 1024)) { + my $out = syswrite($tmp_fh, $str, $res); + defined($out) && $out == $res + or croak("write ", + $tmp_fh->filename, + ": $!\n"); + } + defined $res or croak $!; - close $fh or croak $!; + ($fh, $tmp_fh) = ($tmp_fh, $fh); + Git::temp_release($tmp_fh, 1); + } + } - $hash = $::_repository->hash_and_insert_object($tmp_filename); - unlink($tmp_filename); + $hash = $::_repository->hash_and_insert_object( + $fh->filename); $hash =~ /^[a-f\d]{40}$/ or die "not a sha1: $hash\n"; - close $fb->{base} or croak $!; + + Git::temp_release($fb->{base}, 1); + Git::temp_release($fh, 1); } else { $hash = $fb->{blob} or die "no blob information\n"; } @@ -3378,11 +3400,12 @@ sub generate_diff { while (<$diff_fh>) { chomp $_; # this gets rid of the trailing "\0" if ($state eq 'meta' && /^:(\d{6})\s(\d{6})\s - $::sha1\s($::sha1)\s + ($::sha1)\s($::sha1)\s ([MTCRAD])\d*$/xo) { push @mods, { mode_a => $1, mode_b => $2, - sha1_b => $3, chg => $4 }; - if ($4 =~ /^(?:C|R)$/) { + sha1_a => $3, sha1_b => $4, + chg => $5 }; + if ($5 =~ /^(?:C|R)$/) { $state = 'file_a'; } else { $state = 'file_b'; @@ -3634,6 +3657,7 @@ sub R { my $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat, $self->url_path($m->{file_a}), $self->{r}); print "\tR\t$m->{file_a} => $m->{file_b}\n" unless $::_q; + $self->apply_autoprops($file, $fbat); $self->chg_file($fbat, $m); $self->close_file($fbat,undef,$self->{pool}); @@ -3660,35 +3684,53 @@ sub change_file_prop { $self->SUPER::change_file_prop($fbat, $pname, $pval, $self->{pool}); } -sub chg_file { - my ($self, $fbat, $m) = @_; - if ($m->{mode_b} =~ /755$/ && $m->{mode_a} !~ /755$/) { - $self->change_file_prop($fbat,'svn:executable','*'); - } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { - $self->change_file_prop($fbat,'svn:executable',undef); - } - my $fh = IO::File->new_tmpfile or croak $!; - if ($m->{mode_b} =~ /^120/) { +sub _chg_file_get_blob ($$$$) { + my ($self, $fbat, $m, $which) = @_; + my $fh = Git::temp_acquire("git_blob_$which"); + if ($m->{"mode_$which"} =~ /^120/) { print $fh 'link ' or croak $!; $self->change_file_prop($fbat,'svn:special','*'); - } elsif ($m->{mode_a} =~ /^120/ && $m->{mode_b} !~ /^120/) { + } elsif ($m->{mode_a} =~ /^120/ && $m->{"mode_$which"} !~ /^120/) { $self->change_file_prop($fbat,'svn:special',undef); } - my $size = $::_repository->cat_blob($m->{sha1_b}, $fh); - croak "Failed to read object $m->{sha1_b}" if ($size < 0); + my $blob = $m->{"sha1_$which"}; + return ($fh,) if ($blob =~ /^0{40}$/); + my $size = $::_repository->cat_blob($blob, $fh); + croak "Failed to read object $blob" if ($size < 0); $fh->flush == 0 or croak $!; seek $fh, 0, 0 or croak $!; my $exp = ::md5sum($fh); seek $fh, 0, 0 or croak $!; + return ($fh, $exp); +} +sub chg_file { + my ($self, $fbat, $m) = @_; + if ($m->{mode_b} =~ /755$/ && $m->{mode_a} !~ /755$/) { + $self->change_file_prop($fbat,'svn:executable','*'); + } elsif ($m->{mode_b} !~ /755$/ && $m->{mode_a} =~ /755$/) { + $self->change_file_prop($fbat,'svn:executable',undef); + } + my ($fh_a, $exp_a) = _chg_file_get_blob $self, $fbat, $m, 'a'; + my ($fh_b, $exp_b) = _chg_file_get_blob $self, $fbat, $m, 'b'; my $pool = SVN::Pool->new; - my $atd = $self->apply_textdelta($fbat, undef, $pool); - my $got = SVN::TxDelta::send_stream($fh, @$atd, $pool); - die "Checksum mismatch\nexpected: $exp\ngot: $got\n" if ($got ne $exp); + my $atd = $self->apply_textdelta($fbat, $exp_a, $pool); + if (-s $fh_a) { + my $txstream = SVN::TxDelta::new ($fh_a, $fh_b, $pool); + my $res = SVN::TxDelta::send_txstream($txstream, @$atd, $pool); + if (defined $res) { + die "Unexpected result from send_txstream: $res\n", + "(SVN::Core::VERSION: $SVN::Core::VERSION)\n"; + } + } else { + my $got = SVN::TxDelta::send_stream($fh_b, @$atd, $pool); + die "Checksum mismatch\nexpected: $exp_b\ngot: $got\n" + if ($got ne $exp_b); + } + Git::temp_release($fh_b, 1); + Git::temp_release($fh_a, 1); $pool->clear; - - close $fh or croak $!; } sub D { @@ -3983,6 +4025,7 @@ sub gs_do_switch { } } $ra ||= $self; + $url_b = escape_url($url_b); my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool); my @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef) : (); $reporter->set_path('', $rev_a, 0, @lock, $pool);