From 5578ed744ddcf4e43d4fffa40fe3c76e38a91d11 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Fri, 27 Jul 2012 13:00:48 -0700 Subject: Git::SVN: use accessors internally for path Then later it can be canonicalized automatically rather than everywhere its used. Later patch will make other things use it. [ew: commit title, reformatted accessor to match existing style] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index b8b3474..a93ac61 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -314,12 +314,12 @@ sub init_remote_config { print STDERR "Using higher level of URL: ", "$url => $min_url\n"; } - my $old_path = $self->{path}; - $self->{path} = $url; - $self->{path} =~ s!^\Q$min_url\E(/|$)!!; + my $old_path = $self->path; + $url =~ s!^\Q$min_url\E(/|$)!!; if (length $old_path) { - $self->{path} .= "/$old_path"; + $url .= "/$old_path"; } + $self->path($url); $url = $min_url; } } @@ -343,11 +343,13 @@ sub init_remote_config { unless ($no_write) { command_noisy('config', "svn-remote.$self->{repo_id}.url", $url); - $self->{path} =~ s{^/}{}; - $self->{path} =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; + my $path = $self->path; + $path =~ s{^/}{}; + $path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; + $self->path($path); command_noisy('config', '--add', "svn-remote.$self->{repo_id}.fetch", - "$self->{path}:".$self->refname); + $self->path.":".$self->refname); } $self->{url} = $url; } @@ -435,17 +437,22 @@ sub new { } } my $self = _new($class, $repo_id, $ref_id, $path); - if (!defined $self->{path} || !length $self->{path}) { + if (!defined $self->path || !length $self->path) { my $fetch = command_oneline('config', '--get', "svn-remote.$repo_id.fetch", ":$ref_id\$") or die "Failed to read \"svn-remote.$repo_id.fetch\" ", "\":$ref_id\$\" in config\n"; - ($self->{path}, undef) = split(/\s*:\s*/, $fetch); + my($path) = split(/\s*:\s*/, $fetch); + $self->path($path); + } + { + my $path = $self->path; + $path =~ s{/+}{/}g; + $path =~ s{\A/}{}; + $path =~ s{/\z}{}; + $self->path($path); } - $self->{path} =~ s{/+}{/}g; - $self->{path} =~ s{\A/}{}; - $self->{path} =~ s{/\z}{}; $self->{url} = command_oneline('config', '--get', "svn-remote.$repo_id.url") or die "Failed to read \"svn-remote.$repo_id.url\" in config\n"; @@ -567,7 +574,7 @@ sub _set_svm_vars { } my $r = $ra->get_latest_revnum; - my $path = $self->{path}; + my $path = $self->path; my %tried; while (length $path) { unless ($tried{"$self->{url}/$path"}) { @@ -728,7 +735,7 @@ sub prop_walk { $path =~ s#^/*#/#g; my $p = $path; # Strip the irrelevant part of the path. - $p =~ s#^/+\Q$self->{path}\E(/|$)#/#; + $p =~ s#^/+\Q@{[$self->path]}\E(/|$)#/#; # Ensure the path is terminated by a `/'. $p =~ s#/*$#/#; @@ -749,7 +756,7 @@ sub prop_walk { foreach (sort keys %$dirent) { next if $dirent->{$_}->{kind} != $SVN::Node::dir; - $self->prop_walk($self->{path} . $p . $_, $rev, $sub); + $self->prop_walk($self->path . $p . $_, $rev, $sub); } } @@ -920,19 +927,19 @@ sub rewrite_uuid { sub metadata_url { my ($self) = @_; ($self->rewrite_root || $self->{url}) . - (length $self->{path} ? '/' . $self->{path} : ''); + (length $self->path ? '/' . $self->path : ''); } sub full_url { my ($self) = @_; - $self->{url} . (length $self->{path} ? '/' . $self->{path} : ''); + $self->{url} . (length $self->path ? '/' . $self->path : ''); } sub full_pushurl { my ($self) = @_; if ($self->{pushurl}) { - return $self->{pushurl} . (length $self->{path} ? '/' . - $self->{path} : ''); + return $self->{pushurl} . (length $self->path ? '/' . + $self->path : ''); } else { return $self->full_url; } @@ -1048,20 +1055,20 @@ sub do_git_commit { sub match_paths { my ($self, $paths, $r) = @_; - return 1 if $self->{path} eq ''; - if (my $path = $paths->{"/$self->{path}"}) { + return 1 if $self->path eq ''; + if (my $path = $paths->{"/".$self->path}) { return ($path->{action} eq 'D') ? 0 : 1; } - $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//; + $self->{path_regex} ||= qr{^/\Q@{[$self->path]}\E/}; if (grep /$self->{path_regex}/, keys %$paths) { return 1; } my $c = ''; - foreach (split m#/#, $self->{path}) { + foreach (split m#/#, $self->path) { $c .= "/$_"; next unless ($paths->{$c} && ($paths->{$c}->{action} =~ /^[AR]$/)); - if ($self->ra->check_path($self->{path}, $r) == + if ($self->ra->check_path($self->path, $r) == $SVN::Node::dir) { return 1; } @@ -1075,14 +1082,14 @@ sub find_parent_branch { unless (defined $paths) { my $err_handler = $SVN::Error::handler; $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs; - $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1, + $self->ra->get_log([$self->path], $rev, $rev, 0, 1, 1, sub { $paths = $_[0] }); $SVN::Error::handler = $err_handler; } return undef unless defined $paths; # look for a parent from another branch: - my @b_path_components = split m#/#, $self->{path}; + my @b_path_components = split m#/#, $self->path; my @a_path_components; my $i; while (@b_path_components) { @@ -1235,7 +1242,7 @@ sub mkemptydirs { close $fh; } - my $strip = qr/\A\Q$self->{path}\E(?:\/|$)/; + my $strip = qr/\A\Q@{[$self->path]}\E(?:\/|$)/; foreach my $d (sort keys %empty_dirs) { $d = uri_decode($d); $d =~ s/$strip//; @@ -1858,7 +1865,7 @@ sub make_log_entry { $commit_email ||= "$author\@$uuid"; } elsif ($self->use_svnsync_props) { my $full_url = $self->svnsync->{url}; - $full_url .= "/$self->{path}" if length $self->{path}; + $full_url .= "/".$self->path if length $self->path; remove_username($full_url); my $uuid = $self->svnsync->{uuid}; $log_entry{metadata} = "$full_url\@$rev $uuid"; @@ -1905,7 +1912,7 @@ sub set_tree { tree_b => $tree, editor_cb => sub { $self->set_tree_cb($log_entry, $tree, @_) }, - svn_path => $self->{path} ); + svn_path => $self->path ); if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) { print "No changes\nr$self->{last_rev} = $tree\n"; } @@ -2276,10 +2283,27 @@ sub _new { $_[3] = $path = '' unless (defined $path); mkpath([$dir]); - bless { + my $obj = bless { ref_id => $ref_id, dir => $dir, index => "$dir/index", - path => $path, config => "$ENV{GIT_DIR}/svn/config", + config => "$ENV{GIT_DIR}/svn/config", map_root => "$dir/.rev_map", repo_id => $repo_id }, $class; + + # Ensure it gets canonicalized + $obj->path($path); + + return $obj; +} + +sub path { + my $self = shift; + + if (@_) { + my $path = shift; + $self->{path} = $path; + return; + } + + return $self->{path}; } # for read-only access of old .rev_db formats -- cgit v0.10.2-6-g49f6 From 06ee19e8e5401e90d3b8e60bcee4b25e7b49efc5 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Fri, 27 Jul 2012 13:00:49 -0700 Subject: Git::SVN: use accessor for URLs internally So later it can do automatic canonicalization. A later patch will make other things use the accessor. No functional change here. [ew: commit title] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index a93ac61..208a0ed 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -351,7 +351,7 @@ sub init_remote_config { "svn-remote.$self->{repo_id}.fetch", $self->path.":".$self->refname); } - $self->{url} = $url; + $self->url($url); } sub find_by_url { # repos_root and, path are optional @@ -453,9 +453,10 @@ sub new { $path =~ s{/\z}{}; $self->path($path); } - $self->{url} = command_oneline('config', '--get', - "svn-remote.$repo_id.url") or + my $url = command_oneline('config', '--get', + "svn-remote.$repo_id.url") or die "Failed to read \"svn-remote.$repo_id.url\" in config\n"; + $self->url($url); $self->{pushurl} = eval { command_oneline('config', '--get', "svn-remote.$repo_id.pushurl") }; $self->rebuild; @@ -577,17 +578,18 @@ sub _set_svm_vars { my $path = $self->path; my %tried; while (length $path) { - unless ($tried{"$self->{url}/$path"}) { + my $try = $self->url . "/$path"; + unless ($tried{$try}) { return $ra if $self->read_svm_props($ra, $path, $r); - $tried{"$self->{url}/$path"} = 1; + $tried{$try} = 1; } $path =~ s#/?[^/]+$##; } die "Path: '$path' should be ''\n" if $path ne ''; return $ra if $self->read_svm_props($ra, $path, $r); - $tried{"$self->{url}/$path"} = 1; + $tried{$self->url."/$path"} = 1; - if ($ra->{repos_root} eq $self->{url}) { + if ($ra->{repos_root} eq $self->url) { die @err, (map { " $_\n" } keys %tried), "\n"; } @@ -610,7 +612,7 @@ sub _set_svm_vars { if (!$ok) { die @err, (map { " $_\n" } keys %tried), "\n"; } - Git::SVN::Ra->new($self->{url}); + Git::SVN::Ra->new($self->url); } sub svnsync { @@ -677,7 +679,7 @@ sub ra_uuid { if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) { $self->{ra_uuid} = $uuid; } else { - die "ra_uuid called without URL\n" unless $self->{url}; + die "ra_uuid called without URL\n" unless $self->url; $self->{ra_uuid} = $self->ra->get_uuid; tmp_config('--add', $key, $self->{ra_uuid}); } @@ -701,7 +703,7 @@ sub repos_root { sub ra { my ($self) = shift; - my $ra = Git::SVN::Ra->new($self->{url}); + my $ra = Git::SVN::Ra->new($self->url); $self->_set_repos_root($ra->{repos_root}); if ($self->use_svm_props && !$self->{svm}) { if ($self->no_metadata) { @@ -926,13 +928,13 @@ sub rewrite_uuid { sub metadata_url { my ($self) = @_; - ($self->rewrite_root || $self->{url}) . + ($self->rewrite_root || $self->url) . (length $self->path ? '/' . $self->path : ''); } sub full_url { my ($self) = @_; - $self->{url} . (length $self->path ? '/' . $self->path : ''); + $self->url . (length $self->path ? '/' . $self->path : ''); } sub full_pushurl { @@ -1436,7 +1438,7 @@ sub find_extra_svk_parents { for my $ticket ( @tickets ) { my ($uuid, $path, $rev) = split /:/, $ticket; if ( $uuid eq $self->ra_uuid ) { - my $url = $self->{url}; + my $url = $self->url; my $repos_root = $url; my $branch_from = $path; $branch_from =~ s{^/}{}; @@ -1682,7 +1684,7 @@ sub find_extra_svn_parents { # are now marked as merge, we can add the tip as a parent. my @merges = split "\n", $mergeinfo; my @merge_tips; - my $url = $self->{url}; + my $url = $self->url; my $uuid = $self->ra_uuid; my %ranges; for my $merge ( @merges ) { @@ -2306,6 +2308,18 @@ sub path { return $self->{path}; } +sub url { + my $self = shift; + + if (@_) { + my $url = shift; + $self->{url} = $url; + return; + } + + return $self->{url}; +} + # for read-only access of old .rev_db formats sub unlink_rev_db_symlink { my ($self) = @_; -- cgit v0.10.2-6-g49f6 From b4943dc96324fec568125d7a5af1c4fdbd078543 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Fri, 27 Jul 2012 13:00:50 -0700 Subject: Git::SVN::Ra: use accessor for URLs Later it can canonicalize automatically. A later change will make other things use the accessor. No functional change. [ew: commit title, reformatted accessor to match existing style] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 23ff43e..df8dcb3 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -84,7 +84,7 @@ sub escape_url { sub new { my ($class, $url) = @_; $url =~ s!/+$!!; - return $RA if ($RA && $RA->{url} eq $url); + return $RA if ($RA && $RA->url eq $url); ::_req_svn(); @@ -119,13 +119,29 @@ sub new { config => $config, pool => SVN::Pool->new, auth_provider_callbacks => $callbacks); - $self->{url} = $url; + $RA = bless $self, $class; + + # Make sure its canonicalized + $self->url($url); $self->{svn_path} = $url; $self->{repos_root} = $self->get_repos_root; $self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##; $self->{cache} = { check_path => { r => 0, data => {} }, get_dir => { r => 0, data => {} } }; - $RA = bless $self, $class; + + return $RA; +} + +sub url { + my $self = shift; + + if (@_) { + my $url = shift; + $self->{url} = $url; + return; + } + + return $self->{url}; } sub check_path { @@ -285,7 +301,7 @@ sub gs_do_switch { my $path = $gs->{path}; my $pool = SVN::Pool->new; - my $full_url = $self->{url}; + my $full_url = $self->url; my $old_url = $full_url; $full_url .= '/' . $path if length $path; my ($ra, $reparented); @@ -300,7 +316,7 @@ sub gs_do_switch { $ra_invalid = 1; } elsif ($old_url ne $full_url) { SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool); - $self->{url} = $full_url; + $self->url($full_url); $reparented = 1; } @@ -313,7 +329,7 @@ sub gs_do_switch { if ($reparented) { SVN::_Ra::svn_ra_reparent($self->{session}, $old_url, $pool); - $self->{url} = $old_url; + $self->url($old_url); } $pool->clear; @@ -362,7 +378,7 @@ sub gs_fetch_loop_common { my $inc = $_log_window_size; my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc); my $longest_path = longest_common_path($gsv, $globs); - my $ra_url = $self->{url}; + my $ra_url = $self->url; my $find_trailing_edge; while (1) { my %revs; @@ -508,7 +524,7 @@ sub match_globs { ($self->check_path($p, $r) != $SVN::Node::dir)); next unless $p =~ /$g->{path}->{regex}/; - $exists->{$p} = Git::SVN->init($self->{url}, $p, undef, + $exists->{$p} = Git::SVN->init($self->url, $p, undef, $g->{ref}->full_path($de), 1); } } @@ -532,7 +548,7 @@ sub match_globs { next if ($self->check_path($pathname, $r) != $SVN::Node::dir); $exists->{$pathname} = Git::SVN->init( - $self->{url}, $pathname, undef, + $self->url, $pathname, undef, $g->{ref}->full_path($p), 1); } my $c = ''; @@ -548,7 +564,7 @@ sub match_globs { sub minimize_url { my ($self) = @_; - return $self->{url} if ($self->{url} eq $self->{repos_root}); + return $self->url if ($self->url eq $self->{repos_root}); my $url = $self->{repos_root}; my @components = split(m!/!, $self->{svn_path}); my $c = ''; @@ -568,7 +584,7 @@ sub can_do_switch { unless (defined $can_do_switch) { my $pool = SVN::Pool->new; my $rep = eval { - $self->do_switch(1, '', 0, $self->{url}, + $self->do_switch(1, '', 0, $self->url, SVN::Delta::Editor->new, $pool); }; if ($@) { -- cgit v0.10.2-6-g49f6 From 6a8d999ed4a0030ab7902382ed3b122ce448e581 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Fri, 27 Jul 2012 13:00:51 -0700 Subject: use Git::SVN->path accessor globally No functional change. [ew: commit title] Signed-off-by: Eric Wong diff --git a/git-svn.perl b/git-svn.perl index 5711c57..039623e 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1195,7 +1195,7 @@ sub cmd_show_ignore { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; print STDOUT "\n# $path\n"; my $s = $props->{'svn:ignore'} or return; @@ -1211,7 +1211,7 @@ sub cmd_show_externals { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; print STDOUT "\n# $path\n"; my $s = $props->{'svn:externals'} or return; @@ -1226,7 +1226,7 @@ sub cmd_create_ignore { my ($url, $rev, $uuid, $gs) = working_head_info('HEAD'); $gs ||= Git::SVN->new; my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum); - $gs->prop_walk($gs->{path}, $r, sub { + $gs->prop_walk($gs->path, $r, sub { my ($gs, $path, $props) = @_; # $path is of the form /path/to/dir/ $path = '.' . $path; @@ -1396,7 +1396,7 @@ sub cmd_commit_diff { "the command-line\n", $usage); } $url = $gs->{url}; - $svn_path = $gs->{path}; + $svn_path = $gs->path; } unless (defined $_revision) { fatal("-r|--revision is a required argument\n", $usage); @@ -1634,6 +1634,8 @@ sub post_fetch_checkout { sub complete_svn_url { my ($url, $path) = @_; $path =~ s#/+$##; + + # If the path is not a URL... if ($path !~ m#^[a-z\+]+://#) { if (!defined $url || $url !~ m#^[a-z\+]+://#) { fatal("E: '$path' is not a complete URL ", @@ -1670,7 +1672,7 @@ sub complete_url_ls_init { "wanted to set to: $gs->{url}\n"; } command_oneline('config', $k, $gs->{url}) unless $orig_url; - my $remote_path = "$gs->{path}/$repo_path"; + my $remote_path = $gs->path . "/$repo_path"; $remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; $remote_path =~ s#/+#/#g; $remote_path =~ s#^/##g; diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index 208a0ed..a16acbb 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -1123,7 +1123,7 @@ sub find_parent_branch { ($base, $head) = parse_revision_argument(0, $r); } else { if ($r0 < $r) { - $gs->ra->get_log([$gs->{path}], $r0 + 1, $r, 1, + $gs->ra->get_log([$gs->path], $r0 + 1, $r, 1, 0, 1, sub { $base = $_[1] - 1 }); } } @@ -1145,7 +1145,7 @@ sub find_parent_branch { # at the moment), so we can't rely on it $self->{last_rev} = $r0; $self->{last_commit} = $parent; - $ed = Git::SVN::Fetcher->new($self, $gs->{path}); + $ed = Git::SVN::Fetcher->new($self, $gs->path); $gs->ra->gs_do_switch($r0, $rev, $gs, $self->full_url, $ed) or die "SVN connection failed somewhere...\n"; diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm index 76fae9b..046a7a2 100644 --- a/perl/Git/SVN/Fetcher.pm +++ b/perl/Git/SVN/Fetcher.pm @@ -83,7 +83,7 @@ sub _mark_empty_symlinks { chomp(my $empty_blob = `git hash-object -t blob --stdin < /dev/null`); my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r -z/, $cmt); local $/ = "\0"; - my $pfx = defined($switch_path) ? $switch_path : $git_svn->{path}; + my $pfx = defined($switch_path) ? $switch_path : $git_svn->path; $pfx .= '/' if length($pfx); while (<$ls>) { chomp; diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index df8dcb3..9234bf9 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -262,7 +262,7 @@ sub get_commit_editor { sub gs_do_update { my ($self, $rev_a, $rev_b, $gs, $editor) = @_; my $new = ($rev_a == $rev_b); - my $path = $gs->{path}; + my $path = $gs->path; if ($new && -e $gs->{index}) { unlink $gs->{index} or die @@ -298,7 +298,7 @@ sub gs_do_update { # svn_ra_reparent didn't work before 1.4) sub gs_do_switch { my ($self, $rev_a, $rev_b, $gs, $url_b, $editor) = @_; - my $path = $gs->{path}; + my $path = $gs->path; my $pool = SVN::Pool->new; my $full_url = $self->url; @@ -342,7 +342,7 @@ sub longest_common_path { my $common_max = scalar @$gsv; foreach my $gs (@$gsv) { - my @tmp = split m#/#, $gs->{path}; + my @tmp = split m#/#, $gs->path; my $p = ''; foreach (@tmp) { $p .= length($p) ? "/$_" : $_; -- cgit v0.10.2-6-g49f6 From b1ea6c3829109aff412095b889432bf496f46a90 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Fri, 27 Jul 2012 13:00:52 -0700 Subject: use Git::SVN{,::RA}->url accessor globally Note: The structure returned from Git::SVN->read_all_remotes() does not appear to contain objects, so I'm leaving them alone. That's everything converted over to the url and path accessors. No functional change. [ew: commit title] Signed-off-by: Eric Wong diff --git a/git-svn.perl b/git-svn.perl index 039623e..de1ddd1 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1395,7 +1395,7 @@ sub cmd_commit_diff { fatal("Needed URL or usable git-svn --id in ", "the command-line\n", $usage); } - $url = $gs->{url}; + $url = $gs->url; $svn_path = $gs->path; } unless (defined $_revision) { @@ -1663,15 +1663,16 @@ sub complete_url_ls_init { "and a separate URL is not specified"); } } - my $url = $ra->{url}; + my $url = $ra->url; my $gs = Git::SVN->init($url, undef, undef, undef, 1); my $k = "svn-remote.$gs->{repo_id}.url"; my $orig_url = eval { command_oneline(qw/config --get/, $k) }; - if ($orig_url && ($orig_url ne $gs->{url})) { + if ($orig_url && ($orig_url ne $gs->url)) { die "$k already set: $orig_url\n", - "wanted to set to: $gs->{url}\n"; + "wanted to set to: $gs->url\n"; } - command_oneline('config', $k, $gs->{url}) unless $orig_url; + command_oneline('config', $k, $gs->url) unless $orig_url; + my $remote_path = $gs->path . "/$repo_path"; $remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; $remote_path =~ s#/+#/#g; diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index a16acbb..fc1ac07 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -560,7 +560,7 @@ sub _set_svm_vars { # username is of no interest $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1}; - my $replace = $ra->{url}; + my $replace = $ra->url; $replace .= "/$path" if length $path; my $section = "svn-remote.$self->{repo_id}"; @@ -599,16 +599,17 @@ sub _set_svm_vars { $path = $ra->{svn_path}; $ra = Git::SVN::Ra->new($ra->{repos_root}); while (length $path) { - unless ($tried{"$ra->{url}/$path"}) { + my $try = $ra->url ."/$path"; + unless ($tried{$try}) { $ok = $self->read_svm_props($ra, $path, $r); last if $ok; - $tried{"$ra->{url}/$path"} = 1; + $tried{$try} = 1; } $path =~ s#/?[^/]+$##; } die "Path: '$path' should be ''\n" if $path ne ''; $ok ||= $self->read_svm_props($ra, $path, $r); - $tried{"$ra->{url}/$path"} = 1; + $tried{$ra->url ."/$path"} = 1; if (!$ok) { die @err, (map { " $_\n" } keys %tried), "\n"; } @@ -1108,7 +1109,7 @@ sub find_parent_branch { } my $r = $i->{copyfrom_rev}; my $repos_root = $self->ra->{repos_root}; - my $url = $self->ra->{url}; + my $url = $self->ra->url; my $new_url = $url . $branch_from; print STDERR "Found possible branch point: ", "$new_url => ", $self->full_url, ", $r\n" diff --git a/perl/Git/SVN/Migration.pm b/perl/Git/SVN/Migration.pm index 75d7429..30daf35 100644 --- a/perl/Git/SVN/Migration.pm +++ b/perl/Git/SVN/Migration.pm @@ -177,14 +177,14 @@ sub minimize_connections { my $ra = Git::SVN::Ra->new($url); # skip existing cases where we already connect to the root - if (($ra->{url} eq $ra->{repos_root}) || + if (($ra->url eq $ra->{repos_root}) || ($ra->{repos_root} eq $repo_id)) { - $root_repos->{$ra->{url}} = $repo_id; + $root_repos->{$ra->url} = $repo_id; next; } my $root_ra = Git::SVN::Ra->new($ra->{repos_root}); - my $root_path = $ra->{url}; + my $root_path = $ra->url; $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##; foreach my $path (keys %$fetch) { my $ref_id = $fetch->{$path}; -- cgit v0.10.2-6-g49f6 From 91e6e0c56cc83e5f53d93e90726380a2d392f5f1 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:38:26 -0700 Subject: git-svn: move canonicalization to Git::SVN::Utils So they can be used by others. I'd like to test them, but they're going to become SVN API wrappers shortly and those aren't predictable. No functional change. [ew: commit title] Signed-off-by: Eric Wong diff --git a/git-svn.perl b/git-svn.perl index de1ddd1..a857484 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -29,7 +29,13 @@ use Git::SVN::Prompt; use Git::SVN::Log; use Git::SVN::Migration; -use Git::SVN::Utils qw(fatal can_compress); +use Git::SVN::Utils qw( + fatal + can_compress + canonicalize_path + canonicalize_url +); + use Git qw( git_cmd_try command @@ -1256,31 +1262,6 @@ sub cmd_mkdirs { $gs->mkemptydirs($_revision); } -sub canonicalize_path { - my ($path) = @_; - my $dot_slash_added = 0; - if (substr($path, 0, 1) ne "/") { - $path = "./" . $path; - $dot_slash_added = 1; - } - # File::Spec->canonpath doesn't collapse x/../y into y (for a - # good reason), so let's do this manually. - $path =~ s#/+#/#g; - $path =~ s#/\.(?:/|$)#/#g; - $path =~ s#/[^/]+/\.\.##g; - $path =~ s#/$##g; - $path =~ s#^\./## if $dot_slash_added; - $path =~ s#^/##; - $path =~ s#^\.$##; - return $path; -} - -sub canonicalize_url { - my ($url) = @_; - $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e; - return $url; -} - # get_svnprops(PATH) # ------------------ # Helper for cmd_propget and cmd_proplist below. diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 496006b..ad5351e 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -5,7 +5,12 @@ use warnings; use base qw(Exporter); -our @EXPORT_OK = qw(fatal can_compress); +our @EXPORT_OK = qw( + fatal + can_compress + canonicalize_path + canonicalize_url +); =head1 NAME @@ -56,4 +61,49 @@ sub can_compress { } +=head3 canonicalize_path + + my $canoncalized_path = canonicalize_path($path); + +Converts $path into a canonical form which is safe to pass to the SVN +API as a file path. + +=cut + +sub canonicalize_path { + my ($path) = @_; + my $dot_slash_added = 0; + if (substr($path, 0, 1) ne "/") { + $path = "./" . $path; + $dot_slash_added = 1; + } + # File::Spec->canonpath doesn't collapse x/../y into y (for a + # good reason), so let's do this manually. + $path =~ s#/+#/#g; + $path =~ s#/\.(?:/|$)#/#g; + $path =~ s#/[^/]+/\.\.##g; + $path =~ s#/$##g; + $path =~ s#^\./## if $dot_slash_added; + $path =~ s#^/##; + $path =~ s#^\.$##; + return $path; +} + + +=head3 canonicalize_url + + my $canonicalized_url = canonicalize_url($url); + +Converts $url into a canonical form which is safe to pass to the SVN +API as a URL. + +=cut + +sub canonicalize_url { + my ($url) = @_; + $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e; + return $url; +} + + 1; -- cgit v0.10.2-6-g49f6 From 82009f304826fcaf3188fb422769a7974ae78afa Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:38:27 -0700 Subject: git-svn: use SVN 1.7 to canonicalize when possible No change on SVN 1.6. The tests all pass with SVN 1.6 if canonicalize_url() does nothing, so tests passing doesn't have much meaning. The tests are so messed up right now with SVN 1.7 it isn't really useful to check. They will be useful later. [ew: commit title] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index ad5351e..246d1aa 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -3,6 +3,8 @@ package Git::SVN::Utils; use strict; use warnings; +use SVN::Core; + use base qw(Exporter); our @EXPORT_OK = qw( @@ -100,6 +102,20 @@ API as a URL. =cut sub canonicalize_url { + my $url = shift; + + # The 1.7 way to do it + if ( defined &SVN::_Core::svn_uri_canonicalize ) { + return SVN::_Core::svn_uri_canonicalize($url); + } + # There wasn't a 1.6 way to do it, so we do it ourself. + else { + return _canonicalize_url_ourselves($url); + } +} + + +sub _canonicalize_url_ourselves { my ($url) = @_; $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e; return $url; -- cgit v0.10.2-6-g49f6 From 280ad88aa0e851b2f2945222edb8e7b681a7574b Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:38:28 -0700 Subject: git-svn: factor out _collapse_dotdot function The SVN API functions will not accept ../foo but their canonicalization functions will not collapse it. So we'll have to do it ourselves. _collapse_dotdot() works better than the existing regex did. This will be used shortly when canonicalize_path() starts using the SVN API. [ew: commit title] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 246d1aa..4925410 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -72,6 +72,18 @@ API as a file path. =cut +# Turn foo/../bar into bar +sub _collapse_dotdot { + my $path = shift; + + 1 while $path =~ s{/[^/]+/+\.\.}{}; + 1 while $path =~ s{[^/]+/+\.\./}{}; + 1 while $path =~ s{[^/]+/+\.\.}{}; + + return $path; +} + + sub canonicalize_path { my ($path) = @_; my $dot_slash_added = 0; @@ -83,7 +95,7 @@ sub canonicalize_path { # good reason), so let's do this manually. $path =~ s#/+#/#g; $path =~ s#/\.(?:/|$)#/#g; - $path =~ s#/[^/]+/\.\.##g; + $path = _collapse_dotdot($path); $path =~ s#/$##g; $path =~ s#^\./## if $dot_slash_added; $path =~ s#^/##; diff --git a/t/Git-SVN/Utils/collapse_dotdot.t b/t/Git-SVN/Utils/collapse_dotdot.t new file mode 100644 index 0000000..1da1cce --- /dev/null +++ b/t/Git-SVN/Utils/collapse_dotdot.t @@ -0,0 +1,23 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils; +my $collapse_dotdot = \&Git::SVN::Utils::_collapse_dotdot; + +my %tests = ( + "foo/bar/baz" => "foo/bar/baz", + ".." => "..", + "foo/.." => "", + "/foo/bar/../../baz" => "/baz", + "deeply/.././deeply/nested" => "./deeply/nested", +); + +for my $arg (keys %tests) { + my $want = $tests{$arg}; + + is $collapse_dotdot->($arg), $want, "_collapse_dotdot('$arg') => $want"; +} -- cgit v0.10.2-6-g49f6 From ca475a61f8c07d475c505bf64d219f7e9d61e728 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:38:29 -0700 Subject: git-svn: add join_paths() to safely concatenate paths Otherwise you might wind up with things like... my $path1 = undef; my $path2 = 'foo'; my $path = $path1 . '/' . $path2; creating '/foo'. Or this... my $path1 = 'foo/'; my $path2 = 'bar'; my $path = $path1 . '/' . $path2; creating 'foo//bar'. Could have used File::Spec, but I'm shying away from it due to SVN 1.7's pickiness about paths. Felt it would be better to have our own we can control completely. [ew: commit title] Signed-off-by: Eric Wong diff --git a/git-svn.perl b/git-svn.perl index a857484..6e3e240 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -34,6 +34,7 @@ use Git::SVN::Utils qw( can_compress canonicalize_path canonicalize_url + join_paths ); use Git qw( @@ -1275,7 +1276,7 @@ sub get_svnprops { $path = $cmd_dir_prefix . $path; fatal("No such file or directory: $path") unless -e $path; my $is_dir = -d $path ? 1 : 0; - $path = $gs->{path} . '/' . $path; + $path = join_paths($gs->{path}, $path); # canonicalize the path (otherwise libsvn will abort or fail to # find the file) diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index fc1ac07..ff74782 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -23,7 +23,11 @@ use Git qw( command_output_pipe command_close_pipe ); -use Git::SVN::Utils qw(fatal can_compress); +use Git::SVN::Utils qw( + fatal + can_compress + join_paths +); my $can_use_yaml; BEGIN { @@ -316,9 +320,7 @@ sub init_remote_config { } my $old_path = $self->path; $url =~ s!^\Q$min_url\E(/|$)!!; - if (length $old_path) { - $url .= "/$old_path"; - } + $url = join_paths($url, $old_path); $self->path($url); $url = $min_url; } diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 4925410..4005da9 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -12,6 +12,7 @@ our @EXPORT_OK = qw( can_compress canonicalize_path canonicalize_url + join_paths ); @@ -134,4 +135,35 @@ sub _canonicalize_url_ourselves { } +=head3 join_paths + + my $new_path = join_paths(@paths); + +Appends @paths together into a single path. Any empty paths are ignored. + +=cut + +sub join_paths { + my @paths = @_; + + @paths = grep { defined $_ && length $_ } @paths; + + return '' unless @paths; + return $paths[0] if @paths == 1; + + my $new_path = shift @paths; + $new_path =~ s{/+$}{}; + + my $last_path = pop @paths; + $last_path =~ s{^/+}{}; + + for my $path (@paths) { + $path =~ s{^/+}{}; + $path =~ s{/+$}{}; + $new_path .= "/$path"; + } + + return $new_path .= "/$last_path"; +} + 1; diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t new file mode 100644 index 0000000..d4488e7 --- /dev/null +++ b/t/Git-SVN/Utils/join_paths.t @@ -0,0 +1,32 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw( + join_paths +); + +# A reference cannot be a hash key, so we use an array. +my @tests = ( + [] => '', + ["/x.com", "bar"] => '/x.com/bar', + ["x.com", ""] => 'x.com', + ["/x.com/foo/", undef, "bar"] => '/x.com/foo/bar', + ["x.com/foo/", "/bar/baz/"] => 'x.com/foo/bar/baz/', + ["foo", "bar"] => 'foo/bar', + ["/foo/bar", "baz", "/biff"] => '/foo/bar/baz/biff', + ["", undef, "."] => '.', + [] => '', + +); + +while(@tests) { + my($have, $want) = splice @tests, 0, 2; + + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have; + my $name = "join_paths($args) eq '$want'"; + is join_paths(@$have), $want, $name; +} -- cgit v0.10.2-6-g49f6 From 8169a3908c72ce08763516745d726d8a2ac51a36 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:38:30 -0700 Subject: Git::SVN::Utils: remove irrelevant comment The code doesn't use File::Spec. [ew: commit title] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 4005da9..17ba698 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -92,8 +92,6 @@ sub canonicalize_path { $path = "./" . $path; $dot_slash_added = 1; } - # File::Spec->canonpath doesn't collapse x/../y into y (for a - # good reason), so let's do this manually. $path =~ s#/+#/#g; $path =~ s#/\.(?:/|$)#/#g; $path = _collapse_dotdot($path); -- cgit v0.10.2-6-g49f6 From 3def8d088499b94919de36305ce710487a5e2bb0 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:38:31 -0700 Subject: git-svn: path canonicalization uses SVN API All tests pass with SVN 1.6. SVN 1.7 remains broken, not worrying about it yet. SVN changed its path canonicalization API between 1.6 and 1.7. http://svnbook.red-bean.com/en/1.6/svn.developer.usingapi.html#svn.developer.usingapi.urlpath http://svnbook.red-bean.com/en/1.7/svn.developer.usingapi.html#svn.developer.usingapi.urlpath The SVN API does not accept foo/.. but it also doesn't canonicalize it. We have to do it ourselves. [ew: commit title, fall back if SVN <= 1.6 fails to canonicalize] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 17ba698..f0b1b53 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -86,6 +86,30 @@ sub _collapse_dotdot { sub canonicalize_path { + my $path = shift; + my $rv; + + # The 1.7 way to do it + if ( defined &SVN::_Core::svn_dirent_canonicalize ) { + $path = _collapse_dotdot($path); + $rv = SVN::_Core::svn_dirent_canonicalize($path); + } + # The 1.6 way to do it + # This can return undef on subversion-perl-1.4.2-2.el5 (CentOS 5.2) + elsif ( defined &SVN::_Core::svn_path_canonicalize ) { + $path = _collapse_dotdot($path); + $rv = SVN::_Core::svn_path_canonicalize($path); + } + + return $rv if defined $rv; + + # No SVN API canonicalization is available, or the SVN API + # didn't return a successful result, do it ourselves + return _canonicalize_path_ourselves($path); +} + + +sub _canonicalize_path_ourselves { my ($path) = @_; my $dot_slash_added = 0; if (substr($path, 0, 1) ne "/") { -- cgit v0.10.2-6-g49f6 From 565e56c2cc7ebe42ad12ee5970f3d5af1dc3f36c Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:38:32 -0700 Subject: Git::SVN{,::Ra}: canonicalize earlier This canonicalizes paths and urls as early as possible so we don't have to remember to do it at the point of use. It will fix a swath of SVN 1.7 problems in one go. Its ok to double canonicalize things. SVN 1.7 still fails, still not worrying about that. [ew: commit title] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index ff74782..dacac7f 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -27,6 +27,8 @@ use Git::SVN::Utils qw( fatal can_compress join_paths + canonicalize_path + canonicalize_url ); my $can_use_yaml; @@ -2304,7 +2306,7 @@ sub path { if (@_) { my $path = shift; - $self->{path} = $path; + $self->{path} = canonicalize_path($path); return; } @@ -2316,7 +2318,7 @@ sub url { if (@_) { my $url = shift; - $self->{url} = $url; + $self->{url} = canonicalize_url($url); return; } diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 9234bf9..77bceb9 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -3,6 +3,10 @@ use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/; use strict; use warnings; use SVN::Client; +use Git::SVN::Utils qw( + canonicalize_url +); + use SVN::Ra; BEGIN { @ISA = qw(SVN::Ra); @@ -137,7 +141,7 @@ sub url { if (@_) { my $url = shift; - $self->{url} = $url; + $self->{url} = canonicalize_url($url); return; } -- cgit v0.10.2-6-g49f6 From dad9090f89b8d24f2cb7ecc70f21f52274224c30 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:47:45 -0700 Subject: t9118: workaround inconsistency between SVN versions SVN 1.7 will truncate "not-a%40{0}" to just "not-a". Rather than guess what SVN is going to do for each version, make the test use the branch name that was actually created. [ew: commit title] Signed-off-by: Eric Wong diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh index 63fc982..193d3ca 100755 --- a/t/t9118-git-svn-funky-branch-names.sh +++ b/t/t9118-git-svn-funky-branch-names.sh @@ -32,6 +32,11 @@ test_expect_success 'setup svnrepo' ' start_httpd ' +# SVN 1.7 will truncate "not-a%40{0]" to just "not-a". +# Look at what SVN wound up naming the branch and use that. +# Be sure to escape the @ if it shows up. +non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'` + test_expect_success 'test clone with funky branch names' ' git svn clone -s "$svnrepo/pr ject" project && ( @@ -42,7 +47,7 @@ test_expect_success 'test clone with funky branch names' ' git rev-parse "refs/remotes/%2Eleading_dot" && git rev-parse "refs/remotes/trailing_dot%2E" && git rev-parse "refs/remotes/trailing_dotlock%2Elock" && - git rev-parse "refs/remotes/not-a%40{0}reflog" + git rev-parse "refs/remotes/$non_reflog" ) ' -- cgit v0.10.2-6-g49f6 From 1a35da0b5dc74dc23d7184f838c5dea9bd544334 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:47:46 -0700 Subject: t9107: fix typo Test to check that the migration got rid of the old style git-svn directory. It wasn't failing, just throwing a message to STDERR. [ew: commit title] Signed-off-by: Eric Wong diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index 289fc31..cfb4453 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -32,7 +32,7 @@ test_expect_success 'initialize old-style (v0) git svn layout' ' echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url && echo "$svnrepo" > "$GIT_DIR"/svn/info/url && git svn migrate && - ! test -d "$GIT_DIR"/git svn && + ! test -d "$GIT_DIR"/git-svn && git rev-parse --verify refs/${remotes_git_svn}^0 && git rev-parse --verify refs/remotes/svn^0 && test "$(git config --get svn-remote.svn.url)" = "$svnrepo" && -- cgit v0.10.2-6-g49f6 From 93c3fcbe4d4893fac6c9de64219b2eda0b309a13 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:47:47 -0700 Subject: git-svn: attempt to mimic SVN 1.7 URL canonicalization Previously, our URL canonicalization didn't do much of anything. Now it actually escapes and collapses slashes. This is mostly a cut & paste of escape_url from git-svn. This is closer to how SVN 1.7's canonicalization behaves. Doing it with 1.6 lets us chase down some problems caused by more effective canonicalization without having to deal with all the other 1.7 issues on top of that. * Remote URLs have to be canonicalized otherwise Git::SVN->find_existing_remote will think they're different. * The SVN remote is now written to the git config canonicalized. That should be ok. Adjust a test to account for that. [ew: commit title] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index dacac7f..a2e7144 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -201,9 +201,9 @@ sub read_all_remotes { } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) { $r->{$1}->{svm} = {}; } elsif (m!^(.+)\.url=\s*(.*)\s*$!) { - $r->{$1}->{url} = $2; + $r->{$1}->{url} = canonicalize_url($2); } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) { - $r->{$1}->{pushurl} = $2; + $r->{$1}->{pushurl} = canonicalize_url($2); } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) { $r->{$1}->{ignore_refs_regex} = $2; } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) { diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index f0b1b53..ab7add5 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -150,10 +150,25 @@ sub canonicalize_url { } +sub _canonicalize_url_path { + my ($uri_path) = @_; + + my @parts; + foreach my $part (split m{/+}, $uri_path) { + $part =~ s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg; + push @parts, $part; + } + + return join('/', @parts); +} + sub _canonicalize_url_ourselves { my ($url) = @_; - $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e; - return $url; + if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) { + my ($scheme, $domain, $uri) = ($1, $2, _canonicalize_url_path(canonicalize_path($3))); + $url = "$scheme://$domain$uri"; + } + $url; } diff --git a/t/Git-SVN/Utils/canonicalize_url.t b/t/Git-SVN/Utils/canonicalize_url.t new file mode 100644 index 0000000..05795ab --- /dev/null +++ b/t/Git-SVN/Utils/canonicalize_url.t @@ -0,0 +1,26 @@ +#!/usr/bin/env perl + +# Test our own home rolled URL canonicalizer. Test the private one +# directly because we can't predict what the SVN API is doing to do. + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils; +my $canonicalize_url = \&Git::SVN::Utils::_canonicalize_url_ourselves; + +my %tests = ( + "http://x.com" => "http://x.com", + "http://x.com/" => "http://x.com", + "http://x.com/foo/bar" => "http://x.com/foo/bar", + "http://x.com//foo//bar//" => "http://x.com/foo/bar", + "http://x.com/ /%/" => "http://x.com/%20%20/%25", +); + +for my $arg (keys %tests) { + my $want = $tests{$arg}; + + is $canonicalize_url->($arg), $want, "canonicalize_url('$arg') => $want"; +} diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh index cfb4453..ee73013 100755 --- a/t/t9107-git-svn-migrate.sh +++ b/t/t9107-git-svn-migrate.sh @@ -27,6 +27,8 @@ test_expect_success 'setup old-looking metadata' ' head=`git rev-parse --verify refs/heads/git-svn-HEAD^0` test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'" +svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'` + test_expect_success 'initialize old-style (v0) git svn layout' ' mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info && echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url && @@ -35,7 +37,7 @@ test_expect_success 'initialize old-style (v0) git svn layout' ' ! test -d "$GIT_DIR"/git-svn && git rev-parse --verify refs/${remotes_git_svn}^0 && git rev-parse --verify refs/remotes/svn^0 && - test "$(git config --get svn-remote.svn.url)" = "$svnrepo" && + test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" && test `git config --get svn-remote.svn.fetch` = \ ":refs/${remotes_git_svn}" ' -- cgit v0.10.2-6-g49f6 From 9c27a57b2da502b7dd3736013b7a185fb6e5064e Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:47:48 -0700 Subject: git-svn: replace URL escapes with canonicalization The old hand-rolled URL escape functions were inferior to canonicalization functions. Continuing to move towards getting everything canonicalizing the same way. * Git::SVN->init_remote_config and Git::SVN::Ra->minimize_url both have to canonicalize the same way else init_remote_config will incorrectly think they're different URLs causing t9107-git-svn-migrate.sh to fail. [ew: commit title] Signed-off-by: Eric Wong diff --git a/git-svn.perl b/git-svn.perl index 6e3e240..6e97545 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1412,24 +1412,6 @@ 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] : "."); @@ -1457,18 +1439,18 @@ sub cmd_info { my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath"); if ($_url) { - print escape_url($full_url), "\n"; + print canonicalize_url($full_url), "\n"; return; } my $result = "Path: $path\n"; $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir"; - $result .= "URL: " . escape_url($full_url) . "\n"; + $result .= "URL: " . canonicalize_url($full_url) . "\n"; eval { my $repos_root = $gs->repos_root; Git::SVN::remove_username($repos_root); - $result .= "Repository Root: " . escape_url($repos_root) . "\n"; + $result .= "Repository Root: " . canonicalize_url($repos_root) . "\n"; }; if ($@) { $result .= "Repository Root: (offline)\n"; diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index a2e7144..6a2a52e 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -296,7 +296,7 @@ sub find_existing_remote { sub init_remote_config { my ($self, $url, $no_write) = @_; - $url =~ s!/+$!!; # strip trailing slash + $url = canonicalize_url($url); my $r = read_all_remotes(); my $existing = find_existing_remote($url, $r); if ($existing) { diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 77bceb9..268b368 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -66,24 +66,6 @@ sub _auth_providers () { \@rv; } -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#^(https?)://([^/]+)(.*)$#) { - my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3)); - $url = "$scheme://$domain$uri"; - } - $url; -} sub new { my ($class, $url) = @_; @@ -119,7 +101,7 @@ sub new { $Git::SVN::Prompt::_no_auth_cache = 1; } } # no warnings 'once' - my $self = SVN::Ra->new(url => escape_url($url), auth => $baton, + my $self = SVN::Ra->new(url => canonicalize_url($url), auth => $baton, config => $config, pool => SVN::Pool->new, auth_provider_callbacks => $callbacks); @@ -312,7 +294,7 @@ sub gs_do_switch { if ($old_url =~ m#^svn(\+ssh)?://# || ($full_url =~ m#^https?://# && - escape_url($full_url) ne $full_url)) { + canonicalize_url($full_url) ne $full_url)) { $_[0] = undef; $self = undef; $RA = undef; @@ -325,7 +307,7 @@ sub gs_do_switch { } $ra ||= $self; - $url_b = escape_url($url_b); + $url_b = canonicalize_url($url_b); my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool); my @lock = (::compare_svn_version('1.2.0') >= 0) ? (undef) : (); $reporter->set_path('', $rev_a, 0, @lock, $pool); @@ -580,7 +562,8 @@ sub minimize_url { $ra->get_log("", $latest, 0, 1, 0, 1, sub {}); }; } while ($@ && ($c = shift @components)); - $url; + + return canonicalize_url($url); } sub can_do_switch { -- cgit v0.10.2-6-g49f6 From 8266fc8be19ef1405d4ef175bb0e75ebc2730f5d Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:47:49 -0700 Subject: git-svn: canonicalize earlier Just a few things I noticed. Its good to canonicalize as early as possible. [ew: commit title] Signed-off-by: Eric Wong diff --git a/git-svn.perl b/git-svn.perl index 6e97545..6b90765 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -1436,16 +1436,16 @@ sub cmd_info { # canonicalize_path() will return "" to make libsvn 1.5.x happy, $path = "." if $path eq ""; - my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath"); + my $full_url = canonicalize_url( $url . ($fullpath eq "" ? "" : "/$fullpath") ); if ($_url) { - print canonicalize_url($full_url), "\n"; + print "$full_url\n"; return; } my $result = "Path: $path\n"; $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir"; - $result .= "URL: " . canonicalize_url($full_url) . "\n"; + $result .= "URL: $full_url\n"; eval { my $repos_root = $gs->repos_root; diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 268b368..c88b2b9 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -69,7 +69,7 @@ sub _auth_providers () { sub new { my ($class, $url) = @_; - $url =~ s!/+$!!; + $url = canonicalize_url($url); return $RA if ($RA && $RA->url eq $url); ::_req_svn(); @@ -101,7 +101,7 @@ sub new { $Git::SVN::Prompt::_no_auth_cache = 1; } } # no warnings 'once' - my $self = SVN::Ra->new(url => canonicalize_url($url), auth => $baton, + my $self = SVN::Ra->new(url => $url, auth => $baton, config => $config, pool => SVN::Pool->new, auth_provider_callbacks => $callbacks); -- cgit v0.10.2-6-g49f6 From d2fd119c4fcaea266a894354b506959376140c37 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:47:50 -0700 Subject: git-svn: introduce add_path_to_url function Remove the ad-hoc versions. This is mostly to normalize the process and ensure the URLs produced don't have double slashes or anything. Also provides a place to fix the corner case where a file path contains a percent sign. [ew: commit title] Signed-off-by: Eric Wong diff --git a/git-svn.perl b/git-svn.perl index 6b90765..3d120d5 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -35,6 +35,7 @@ use Git::SVN::Utils qw( canonicalize_path canonicalize_url join_paths + add_path_to_url ); use Git qw( @@ -1436,7 +1437,7 @@ sub cmd_info { # canonicalize_path() will return "" to make libsvn 1.5.x happy, $path = "." if $path eq ""; - my $full_url = canonicalize_url( $url . ($fullpath eq "" ? "" : "/$fullpath") ); + my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) ); if ($_url) { print "$full_url\n"; diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index 6a2a52e..ec5e826 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -29,6 +29,7 @@ use Git::SVN::Utils qw( join_paths canonicalize_path canonicalize_url + add_path_to_url ); my $can_use_yaml; @@ -564,8 +565,7 @@ sub _set_svm_vars { # username is of no interest $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1}; - my $replace = $ra->url; - $replace .= "/$path" if length $path; + my $replace = add_path_to_url($ra->url, $path); my $section = "svn-remote.$self->{repo_id}"; tmp_config("$section.svm-source", $src); @@ -582,7 +582,7 @@ sub _set_svm_vars { my $path = $self->path; my %tried; while (length $path) { - my $try = $self->url . "/$path"; + my $try = add_path_to_url($self->url, $path); unless ($tried{$try}) { return $ra if $self->read_svm_props($ra, $path, $r); $tried{$try} = 1; @@ -591,7 +591,7 @@ sub _set_svm_vars { } die "Path: '$path' should be ''\n" if $path ne ''; return $ra if $self->read_svm_props($ra, $path, $r); - $tried{$self->url."/$path"} = 1; + $tried{ add_path_to_url($self->url, $path) } = 1; if ($ra->{repos_root} eq $self->url) { die @err, (map { " $_\n" } keys %tried), "\n"; @@ -603,7 +603,7 @@ sub _set_svm_vars { $path = $ra->{svn_path}; $ra = Git::SVN::Ra->new($ra->{repos_root}); while (length $path) { - my $try = $ra->url ."/$path"; + my $try = add_path_to_url($ra->url, $path); unless ($tried{$try}) { $ok = $self->read_svm_props($ra, $path, $r); last if $ok; @@ -613,7 +613,7 @@ sub _set_svm_vars { } die "Path: '$path' should be ''\n" if $path ne ''; $ok ||= $self->read_svm_props($ra, $path, $r); - $tried{$ra->url ."/$path"} = 1; + $tried{ add_path_to_url($ra->url, $path) } = 1; if (!$ok) { die @err, (map { " $_\n" } keys %tried), "\n"; } @@ -933,20 +933,19 @@ sub rewrite_uuid { sub metadata_url { my ($self) = @_; - ($self->rewrite_root || $self->url) . - (length $self->path ? '/' . $self->path : ''); + my $url = $self->rewrite_root || $self->url; + return add_path_to_url( $url, $self->path ); } sub full_url { my ($self) = @_; - $self->url . (length $self->path ? '/' . $self->path : ''); + return add_path_to_url( $self->url, $self->path ); } sub full_pushurl { my ($self) = @_; if ($self->{pushurl}) { - return $self->{pushurl} . (length $self->path ? '/' . - $self->path : ''); + return add_path_to_url( $self->{pushurl}, $self->path ); } else { return $self->full_url; } @@ -1114,7 +1113,7 @@ sub find_parent_branch { my $r = $i->{copyfrom_rev}; my $repos_root = $self->ra->{repos_root}; my $url = $self->ra->url; - my $new_url = $url . $branch_from; + my $new_url = add_path_to_url( $url, $branch_from ); print STDERR "Found possible branch point: ", "$new_url => ", $self->full_url, ", $r\n" unless $::_q > 1; @@ -1443,12 +1442,11 @@ sub find_extra_svk_parents { for my $ticket ( @tickets ) { my ($uuid, $path, $rev) = split /:/, $ticket; if ( $uuid eq $self->ra_uuid ) { - my $url = $self->url; - my $repos_root = $url; + my $repos_root = $self->url; my $branch_from = $path; $branch_from =~ s{^/}{}; - my $gs = $self->other_gs($repos_root."/".$branch_from, - $url, + my $gs = $self->other_gs(add_path_to_url( $repos_root, $branch_from ), + $repos_root, $branch_from, $rev, $self->{ref_id}); @@ -1871,8 +1869,7 @@ sub make_log_entry { $email ||= "$author\@$uuid"; $commit_email ||= "$author\@$uuid"; } elsif ($self->use_svnsync_props) { - my $full_url = $self->svnsync->{url}; - $full_url .= "/".$self->path if length $self->path; + my $full_url = add_path_to_url( $self->svnsync->{url}, $self->path ); remove_username($full_url); my $uuid = $self->svnsync->{uuid}; $log_entry{metadata} = "$full_url\@$rev $uuid"; diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index c88b2b9..ec3c570 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -5,6 +5,7 @@ use warnings; use SVN::Client; use Git::SVN::Utils qw( canonicalize_url + add_path_to_url ); use SVN::Ra; @@ -287,9 +288,8 @@ sub gs_do_switch { my $path = $gs->path; my $pool = SVN::Pool->new; - my $full_url = $self->url; - my $old_url = $full_url; - $full_url .= '/' . $path if length $path; + my $old_url = $self->url; + my $full_url = add_path_to_url( $self->url, $path ); my ($ra, $reparented); if ($old_url =~ m#^svn(\+ssh)?://# || @@ -555,7 +555,7 @@ sub minimize_url { my @components = split(m!/!, $self->{svn_path}); my $c = ''; do { - $url .= "/$c" if length $c; + $url = add_path_to_url($url, $c); eval { my $ra = (ref $self)->new($url); my $latest = $ra->get_latest_revnum; diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index ab7add5..4bb4dde 100644 --- a/perl/Git/SVN/Utils.pm +++ b/perl/Git/SVN/Utils.pm @@ -13,6 +13,7 @@ our @EXPORT_OK = qw( canonicalize_path canonicalize_url join_paths + add_path_to_url ); @@ -203,4 +204,30 @@ sub join_paths { return $new_path .= "/$last_path"; } + +=head3 add_path_to_url + + my $new_url = add_path_to_url($url, $path); + +Appends $path onto the $url. If $path is empty, $url is returned unchanged. + +=cut + +sub add_path_to_url { + my($url, $path) = @_; + + return $url if !defined $path or !length $path; + + # Strip trailing and leading slashes so we don't + # wind up with http://x.com///path + $url =~ s{/+$}{}; + $path =~ s{^/+}{}; + + # If a path has a % in it, URI escape it so it's not + # mistaken for a URI escape later. + $path =~ s{%}{%25}g; + + return join '/', $url, $path; +} + 1; diff --git a/t/Git-SVN/Utils/add_path_to_url.t b/t/Git-SVN/Utils/add_path_to_url.t new file mode 100644 index 0000000..bfbd878 --- /dev/null +++ b/t/Git-SVN/Utils/add_path_to_url.t @@ -0,0 +1,27 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Test::More 'no_plan'; + +use Git::SVN::Utils qw( + add_path_to_url +); + +# A reference cannot be a hash key, so we use an array. +my @tests = ( + ["http://x.com", "bar"] => 'http://x.com/bar', + ["http://x.com", ""] => 'http://x.com', + ["http://x.com/foo/", undef] => 'http://x.com/foo/', + ["http://x.com/foo/", "/bar/baz/"] => 'http://x.com/foo/bar/baz/', + ["http://x.com", 'per%cent'] => 'http://x.com/per%25cent', +); + +while(@tests) { + my($have, $want) = splice @tests, 0, 2; + + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have; + my $name = "add_path_to_url($args) eq $want"; + is add_path_to_url(@$have), $want, $name; +} -- cgit v0.10.2-6-g49f6 From 705b49cb81351020b57f9356487e9b3fdeea1e40 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:47:51 -0700 Subject: git-svn: canonicalize newly-minted URLs Go through all the spots that use the new add_path_to_url() to make a new URL and canonicalize them. * copyfrom_path has to be canonicalized else find_parent_branch will get confused * due to the `canonicalize_url($full_url) ne $full_url)` line of logic in gs_do_switch(), $full_url is left alone until after. At this point SVN 1.7 passes except for 3 tests in t9100-git-svn-basic.sh that look like an SVN bug to do with symlinks. [ew: commit title] Signed-off-by: Eric Wong diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index ec5e826..d0087b2 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -362,6 +362,8 @@ sub init_remote_config { sub find_by_url { # repos_root and, path are optional my ($class, $full_url, $repos_root, $path) = @_; + $full_url = canonicalize_url($full_url); + return undef unless defined $full_url; remove_username($full_url); remove_username($repos_root) if defined $repos_root; @@ -400,6 +402,11 @@ sub find_by_url { # repos_root and, path are optional } $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next; } + + # remote fetch paths are not URI escaped. Decode ours + # so they match + $p = uri_decode($p); + foreach my $f (keys %$fetch) { next if $f ne $p; return Git::SVN->new($fetch->{$f}, $repo_id, $f); @@ -934,18 +941,18 @@ sub rewrite_uuid { sub metadata_url { my ($self) = @_; my $url = $self->rewrite_root || $self->url; - return add_path_to_url( $url, $self->path ); + return canonicalize_url( add_path_to_url( $url, $self->path ) ); } sub full_url { my ($self) = @_; - return add_path_to_url( $self->url, $self->path ); + return canonicalize_url( add_path_to_url( $self->url, $self->path ) ); } sub full_pushurl { my ($self) = @_; if ($self->{pushurl}) { - return add_path_to_url( $self->{pushurl}, $self->path ); + return canonicalize_url( add_path_to_url( $self->{pushurl}, $self->path ) ); } else { return $self->full_url; } @@ -1113,7 +1120,7 @@ sub find_parent_branch { my $r = $i->{copyfrom_rev}; my $repos_root = $self->ra->{repos_root}; my $url = $self->ra->url; - my $new_url = add_path_to_url( $url, $branch_from ); + my $new_url = canonicalize_url( add_path_to_url( $url, $branch_from ) ); print STDERR "Found possible branch point: ", "$new_url => ", $self->full_url, ", $r\n" unless $::_q > 1; @@ -1869,7 +1876,9 @@ sub make_log_entry { $email ||= "$author\@$uuid"; $commit_email ||= "$author\@$uuid"; } elsif ($self->use_svnsync_props) { - my $full_url = add_path_to_url( $self->svnsync->{url}, $self->path ); + my $full_url = canonicalize_url( + add_path_to_url( $self->svnsync->{url}, $self->path ) + ); remove_username($full_url); my $uuid = $self->svnsync->{uuid}; $log_entry{metadata} = "$full_url\@$rev $uuid"; diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index ec3c570..90ec30b 100644 --- a/perl/Git/SVN/Ra.pm +++ b/perl/Git/SVN/Ra.pm @@ -5,6 +5,7 @@ use warnings; use SVN::Client; use Git::SVN::Utils qw( canonicalize_url + canonicalize_path add_path_to_url ); @@ -102,6 +103,7 @@ sub new { $Git::SVN::Prompt::_no_auth_cache = 1; } } # no warnings 'once' + my $self = SVN::Ra->new(url => $url, auth => $baton, config => $config, pool => SVN::Pool->new, @@ -198,6 +200,7 @@ sub get_log { qw/copyfrom_path copyfrom_rev action/; if ($s{'copyfrom_path'}) { $s{'copyfrom_path'} =~ s/$prefix_regex//; + $s{'copyfrom_path'} = canonicalize_path($s{'copyfrom_path'}); } $_[0]{$p} = \%s; } @@ -301,7 +304,11 @@ sub gs_do_switch { $ra = Git::SVN::Ra->new($full_url); $ra_invalid = 1; } elsif ($old_url ne $full_url) { - SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool); + SVN::_Ra::svn_ra_reparent( + $self->{session}, + canonicalize_url($full_url), + $pool + ); $self->url($full_url); $reparented = 1; } -- cgit v0.10.2-6-g49f6 From 5eaa1fd086e826b1ac8d9346a740527edbdb3c34 Mon Sep 17 00:00:00 2001 From: "Michael G. Schwern" Date: Sat, 28 Jul 2012 02:47:52 -0700 Subject: git-svn: remove ad-hoc canonicalizations [ew: commit title] Signed-off-by: Eric Wong diff --git a/git-svn.perl b/git-svn.perl index 3d120d5..56d1ba7 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -36,6 +36,7 @@ use Git::SVN::Utils qw( canonicalize_url join_paths add_path_to_url + join_paths ); use Git qw( @@ -1598,7 +1599,7 @@ sub post_fetch_checkout { sub complete_svn_url { my ($url, $path) = @_; - $path =~ s#/+$##; + $path = canonicalize_path($path); # If the path is not a URL... if ($path !~ m#^[a-z\+]+://#) { @@ -1617,7 +1618,7 @@ sub complete_url_ls_init { print STDERR "W: $switch not specified\n"; return; } - $repo_path =~ s#/+$##; + $repo_path = canonicalize_path($repo_path); if ($repo_path =~ m#^[a-z\+]+://#) { $ra = Git::SVN::Ra->new($repo_path); $repo_path = ''; @@ -1638,9 +1639,8 @@ sub complete_url_ls_init { } command_oneline('config', $k, $gs->url) unless $orig_url; - my $remote_path = $gs->path . "/$repo_path"; + my $remote_path = join_paths( $gs->path, $repo_path ); $remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg; - $remote_path =~ s#/+#/#g; $remote_path =~ s#^/##g; $remote_path .= "/*" if $remote_path !~ /\*/; my ($n) = ($switch =~ /^--(\w+)/); diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index d0087b2..0889145 100644 --- a/perl/Git/SVN.pm +++ b/perl/Git/SVN.pm @@ -460,7 +460,6 @@ sub new { } { my $path = $self->path; - $path =~ s{/+}{/}g; $path =~ s{\A/}{}; $path =~ s{/\z}{}; $self->path($path); -- cgit v0.10.2-6-g49f6