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 --- perl/Git/SVN.pm | 86 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 31 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index b8b34744ea..a93ac61b67 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 v1.2.3 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 --- perl/Git/SVN.pm | 42 ++++++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 14 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index a93ac61b67..208a0edc89 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 v1.2.3 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 --- perl/Git/SVN/Ra.pm | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 23ff43e86b..df8dcb35ef 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 v1.2.3 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 --- perl/Git/SVN.pm | 4 ++-- perl/Git/SVN/Fetcher.pm | 2 +- perl/Git/SVN/Ra.pm | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index 208a0edc89..a16acbbbff 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 76fae9bce0..046a7a2f31 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 df8dcb35ef..9234bf99e8 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 v1.2.3 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 --- perl/Git/SVN.pm | 11 ++++++----- perl/Git/SVN/Migration.pm | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index a16acbbbff..fc1ac07136 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 75d74298ea..30daf35465 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 v1.2.3 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 --- perl/Git/SVN/Utils.pm | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'perl') diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 496006bc7b..ad5351e9ba 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 v1.2.3 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 --- perl/Git/SVN/Utils.pm | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'perl') diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index ad5351e9ba..246d1aa601 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 v1.2.3 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 --- perl/Git/SVN/Utils.pm | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'perl') diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 246d1aa601..4925410dd1 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#^/##; -- cgit v1.2.3 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 --- perl/Git/SVN.pm | 10 ++++++---- perl/Git/SVN/Utils.pm | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 4 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index fc1ac07136..ff747821fb 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 4925410dd1..4005da9d7d 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; -- cgit v1.2.3 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 --- perl/Git/SVN/Utils.pm | 2 -- 1 file changed, 2 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 4005da9d7d..17ba698a6d 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 v1.2.3 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 --- perl/Git/SVN/Utils.pm | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'perl') diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm index 17ba698a6d..f0b1b53a3f 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 v1.2.3 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 --- perl/Git/SVN.pm | 6 ++++-- perl/Git/SVN/Ra.pm | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index ff747821fb..dacac7fb46 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 9234bf99e8..77bceb913a 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 v1.2.3 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 --- perl/Git/SVN.pm | 4 ++-- perl/Git/SVN/Utils.pm | 19 +++++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index dacac7fb46..a2e7144b4c 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 f0b1b53a3f..ab7add5e8b 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; } -- cgit v1.2.3 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 --- perl/Git/SVN.pm | 2 +- perl/Git/SVN/Ra.pm | 27 +++++---------------------- 2 files changed, 6 insertions(+), 23 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index a2e7144b4c..6a2a52e808 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 77bceb913a..268b368de3 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 v1.2.3 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 --- perl/Git/SVN/Ra.pm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm index 268b368de3..c88b2b91da 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 v1.2.3 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 --- perl/Git/SVN.pm | 33 +++++++++++++++------------------ perl/Git/SVN/Ra.pm | 8 ++++---- perl/Git/SVN/Utils.pm | 27 +++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 22 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index 6a2a52e808..ec5e826468 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 c88b2b91da..ec3c570b21 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 ab7add5e8b..4bb4dde89a 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; -- cgit v1.2.3 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 --- perl/Git/SVN.pm | 19 ++++++++++++++----- perl/Git/SVN/Ra.pm | 9 ++++++++- 2 files changed, 22 insertions(+), 6 deletions(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index ec5e826468..d0087b2897 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 ec3c570b21..90ec30bfff 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 v1.2.3 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 --- perl/Git/SVN.pm | 1 - 1 file changed, 1 deletion(-) (limited to 'perl') diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm index d0087b2897..08891452a1 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 v1.2.3