Skip to content

Commit ca475a6

Browse files
schwernEric Wong
authored andcommitted
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 <normalperson@yhbt.net>
1 parent 280ad88 commit ca475a6

File tree

4 files changed

+72
-5
lines changed

4 files changed

+72
-5
lines changed

git-svn.perl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
can_compress
3535
canonicalize_path
3636
canonicalize_url
37+
join_paths
3738
);
3839

3940
use Git qw(
@@ -1275,7 +1276,7 @@ sub get_svnprops {
12751276
$path = $cmd_dir_prefix . $path;
12761277
fatal("No such file or directory: $path") unless -e $path;
12771278
my $is_dir = -d $path ? 1 : 0;
1278-
$path = $gs->{path} . '/' . $path;
1279+
$path = join_paths($gs->{path}, $path);
12791280

12801281
# canonicalize the path (otherwise libsvn will abort or fail to
12811282
# find the file)

perl/Git/SVN.pm

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ use Git qw(
2323
command_output_pipe
2424
command_close_pipe
2525
);
26-
use Git::SVN::Utils qw(fatal can_compress);
26+
use Git::SVN::Utils qw(
27+
fatal
28+
can_compress
29+
join_paths
30+
);
2731

2832
my $can_use_yaml;
2933
BEGIN {
@@ -316,9 +320,7 @@ sub init_remote_config {
316320
}
317321
my $old_path = $self->path;
318322
$url =~ s!^\Q$min_url\E(/|$)!!;
319-
if (length $old_path) {
320-
$url .= "/$old_path";
321-
}
323+
$url = join_paths($url, $old_path);
322324
$self->path($url);
323325
$url = $min_url;
324326
}

perl/Git/SVN/Utils.pm

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ our @EXPORT_OK = qw(
1212
can_compress
1313
canonicalize_path
1414
canonicalize_url
15+
join_paths
1516
);
1617

1718

@@ -134,4 +135,35 @@ sub _canonicalize_url_ourselves {
134135
}
135136

136137

138+
=head3 join_paths
139+
140+
my $new_path = join_paths(@paths);
141+
142+
Appends @paths together into a single path. Any empty paths are ignored.
143+
144+
=cut
145+
146+
sub join_paths {
147+
my @paths = @_;
148+
149+
@paths = grep { defined $_ && length $_ } @paths;
150+
151+
return '' unless @paths;
152+
return $paths[0] if @paths == 1;
153+
154+
my $new_path = shift @paths;
155+
$new_path =~ s{/+$}{};
156+
157+
my $last_path = pop @paths;
158+
$last_path =~ s{^/+}{};
159+
160+
for my $path (@paths) {
161+
$path =~ s{^/+}{};
162+
$path =~ s{/+$}{};
163+
$new_path .= "/$path";
164+
}
165+
166+
return $new_path .= "/$last_path";
167+
}
168+
137169
1;

t/Git-SVN/Utils/join_paths.t

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#!/usr/bin/env perl
2+
3+
use strict;
4+
use warnings;
5+
6+
use Test::More 'no_plan';
7+
8+
use Git::SVN::Utils qw(
9+
join_paths
10+
);
11+
12+
# A reference cannot be a hash key, so we use an array.
13+
my @tests = (
14+
[] => '',
15+
["/x.com", "bar"] => '/x.com/bar',
16+
["x.com", ""] => 'x.com',
17+
["/x.com/foo/", undef, "bar"] => '/x.com/foo/bar',
18+
["x.com/foo/", "/bar/baz/"] => 'x.com/foo/bar/baz/',
19+
["foo", "bar"] => 'foo/bar',
20+
["/foo/bar", "baz", "/biff"] => '/foo/bar/baz/biff',
21+
["", undef, "."] => '.',
22+
[] => '',
23+
24+
);
25+
26+
while(@tests) {
27+
my($have, $want) = splice @tests, 0, 2;
28+
29+
my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
30+
my $name = "join_paths($args) eq '$want'";
31+
is join_paths(@$have), $want, $name;
32+
}

0 commit comments

Comments
 (0)