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>
Michael G. Schwern committed
Jul 28, 2012 at 02:38 UTC
ca475a61f8c07d475c505bf64d219f7e9d61e728
4 files changed
+72
-5
git-svn.perl
+2
-1
@@ -34,6 +34,7 @@ use Git::SVN::Utils qw(
34
can_compress
35
canonicalize_path
36
canonicalize_url
37
+ join_paths
38
);
39
40
use Git qw(
@@ -1275,7 +1276,7 @@ sub get_svnprops {
1276
$path = $cmd_dir_prefix . $path;
1277
fatal("No such file or directory: $path") unless -e $path;
1278
my $is_dir = -d $path ? 1 : 0;
1278
- $path = $gs->{path} . '/' . $path;
1279
+ $path = join_paths($gs->{path}, $path);
1280
1281
# canonicalize the path (otherwise libsvn will abort or fail to
1282
# find the file)
perl/Git/SVN.pm
+6
-4
@@ -23,7 +23,11 @@ use Git qw(
23
command_output_pipe
24
command_close_pipe
25
);
26
-use Git::SVN::Utils qw(fatal can_compress);
26
+use Git::SVN::Utils qw(
27
+ fatal
28
+ can_compress
29
+ join_paths
30
+);
31
32
my $can_use_yaml;
33
BEGIN {
@@ -316,9 +320,7 @@ sub init_remote_config {
320
}
321
my $old_path = $self->path;
322
$url =~ s!^\Q$min_url\E(/|$)!!;
319
- if (length $old_path) {
320
- $url .= "/$old_path";
321
- }
323
+ $url = join_paths($url, $old_path);
324
$self->path($url);
325
$url = $min_url;
326
}
perl/Git/SVN/Utils.pm
+32
@@ -12,6 +12,7 @@ our @EXPORT_OK = qw(
12
can_compress
13
canonicalize_path
14
canonicalize_url
15
+ join_paths
16
);
17
18
@@ -134,4 +135,35 @@ sub _canonicalize_url_ourselves {
135
}
136
137
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
+
169
1;
t/Git-SVN/Utils/join_paths.t
new
+32
@@ -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
+}