diff --git a/git-svn.perl b/git-svn.perl index a857484c58..6e3e240473 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 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; diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t new file mode 100644 index 0000000000..d4488e7162 --- /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; +}