/[gentoo-x86]/dev-vcs/git/files/git-1.7.12-git-svn-backport.patch
Gentoo

Contents of /dev-vcs/git/files/git-1.7.12-git-svn-backport.patch

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations) (download)
Wed Aug 22 04:44:07 2012 UTC (2 years, 8 months ago) by robbat2
Branch: MAIN
Finally, a Git that works with SVN 1.7, per bug #418431! 1.7.12-r1 contains backported ms/git-svn-1.7 branch that will be merged into Git 1.7.13. 1.7.12-r0 excludes that backport but is otherwise identical. Thanks to Michael Schwern for the development work!

(Portage version: 2.2.0_alpha121/cvs/Linux x86_64)

1 commit 0dfcf2dacd4be3f0c647a987b78def5136429165
2 Merge: 889d358 5eaa1fd
3 Author: Junio C Hamano <gitster@pobox.com>
4 Date: Tue Aug 21 15:27:57 2012 -0700
5
6 Merge branch 'ms/git-svn-1.7' into jch
7
8 A series by Michael Schwern via Eric to update git-svn to revamp the
9 way URLs are internally passed around, to make it work with SVN 1.7.
10
11 Will merge to 'next' after pinging Eric to double check and then to 'master'.
12
13 * ms/git-svn-1.7:
14 git-svn: remove ad-hoc canonicalizations
15 git-svn: canonicalize newly-minted URLs
16 git-svn: introduce add_path_to_url function
17 git-svn: canonicalize earlier
18 git-svn: replace URL escapes with canonicalization
19 git-svn: attempt to mimic SVN 1.7 URL canonicalization
20 t9107: fix typo
21 t9118: workaround inconsistency between SVN versions
22 Git::SVN{,::Ra}: canonicalize earlier
23 git-svn: path canonicalization uses SVN API
24 Git::SVN::Utils: remove irrelevant comment
25 git-svn: add join_paths() to safely concatenate paths
26 git-svn: factor out _collapse_dotdot function
27 git-svn: use SVN 1.7 to canonicalize when possible
28 git-svn: move canonicalization to Git::SVN::Utils
29 use Git::SVN{,::RA}->url accessor globally
30 use Git::SVN->path accessor globally
31 Git::SVN::Ra: use accessor for URLs
32 Git::SVN: use accessor for URLs internally
33 Git::SVN: use accessors internally for path
34
35 diff --git a/git-svn.perl b/git-svn.perl
36 index 828b8f0..0d77ffb 100755
37 --- a/git-svn.perl
38 +++ b/git-svn.perl
39 @@ -29,7 +29,16 @@ use Git::SVN::Prompt;
40 use Git::SVN::Log;
41 use Git::SVN::Migration;
42
43 -use Git::SVN::Utils qw(fatal can_compress);
44 +use Git::SVN::Utils qw(
45 + fatal
46 + can_compress
47 + canonicalize_path
48 + canonicalize_url
49 + join_paths
50 + add_path_to_url
51 + join_paths
52 +);
53 +
54 use Git qw(
55 git_cmd_try
56 command
57 @@ -1231,7 +1240,7 @@ sub cmd_show_ignore {
58 my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
59 $gs ||= Git::SVN->new;
60 my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
61 - $gs->prop_walk($gs->{path}, $r, sub {
62 + $gs->prop_walk($gs->path, $r, sub {
63 my ($gs, $path, $props) = @_;
64 print STDOUT "\n# $path\n";
65 my $s = $props->{'svn:ignore'} or return;
66 @@ -1247,7 +1256,7 @@ sub cmd_show_externals {
67 my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
68 $gs ||= Git::SVN->new;
69 my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
70 - $gs->prop_walk($gs->{path}, $r, sub {
71 + $gs->prop_walk($gs->path, $r, sub {
72 my ($gs, $path, $props) = @_;
73 print STDOUT "\n# $path\n";
74 my $s = $props->{'svn:externals'} or return;
75 @@ -1262,7 +1271,7 @@ sub cmd_create_ignore {
76 my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
77 $gs ||= Git::SVN->new;
78 my $r = (defined $_revision ? $_revision : $gs->ra->get_latest_revnum);
79 - $gs->prop_walk($gs->{path}, $r, sub {
80 + $gs->prop_walk($gs->path, $r, sub {
81 my ($gs, $path, $props) = @_;
82 # $path is of the form /path/to/dir/
83 $path = '.' . $path;
84 @@ -1292,31 +1301,6 @@ sub cmd_mkdirs {
85 $gs->mkemptydirs($_revision);
86 }
87
88 -sub canonicalize_path {
89 - my ($path) = @_;
90 - my $dot_slash_added = 0;
91 - if (substr($path, 0, 1) ne "/") {
92 - $path = "./" . $path;
93 - $dot_slash_added = 1;
94 - }
95 - # File::Spec->canonpath doesn't collapse x/../y into y (for a
96 - # good reason), so let's do this manually.
97 - $path =~ s#/+#/#g;
98 - $path =~ s#/\.(?:/|$)#/#g;
99 - $path =~ s#/[^/]+/\.\.##g;
100 - $path =~ s#/$##g;
101 - $path =~ s#^\./## if $dot_slash_added;
102 - $path =~ s#^/##;
103 - $path =~ s#^\.$##;
104 - return $path;
105 -}
106 -
107 -sub canonicalize_url {
108 - my ($url) = @_;
109 - $url =~ s#^([^:]+://[^/]*/)(.*)$#$1 . canonicalize_path($2)#e;
110 - return $url;
111 -}
112 -
113 # get_svnprops(PATH)
114 # ------------------
115 # Helper for cmd_propget and cmd_proplist below.
116 @@ -1330,7 +1314,7 @@ sub get_svnprops {
117 $path = $cmd_dir_prefix . $path;
118 fatal("No such file or directory: $path") unless -e $path;
119 my $is_dir = -d $path ? 1 : 0;
120 - $path = $gs->{path} . '/' . $path;
121 + $path = join_paths($gs->{path}, $path);
122
123 # canonicalize the path (otherwise libsvn will abort or fail to
124 # find the file)
125 @@ -1431,8 +1415,8 @@ sub cmd_commit_diff {
126 fatal("Needed URL or usable git-svn --id in ",
127 "the command-line\n", $usage);
128 }
129 - $url = $gs->{url};
130 - $svn_path = $gs->{path};
131 + $url = $gs->url;
132 + $svn_path = $gs->path;
133 }
134 unless (defined $_revision) {
135 fatal("-r|--revision is a required argument\n", $usage);
136 @@ -1466,24 +1450,6 @@ sub cmd_commit_diff {
137 }
138 }
139
140 -sub escape_uri_only {
141 - my ($uri) = @_;
142 - my @tmp;
143 - foreach (split m{/}, $uri) {
144 - s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
145 - push @tmp, $_;
146 - }
147 - join('/', @tmp);
148 -}
149 -
150 -sub escape_url {
151 - my ($url) = @_;
152 - if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
153 - my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
154 - $url = "$scheme://$domain$uri";
155 - }
156 - $url;
157 -}
158
159 sub cmd_info {
160 my $path = canonicalize_path(defined($_[0]) ? $_[0] : ".");
161 @@ -1508,21 +1474,21 @@ sub cmd_info {
162 # canonicalize_path() will return "" to make libsvn 1.5.x happy,
163 $path = "." if $path eq "";
164
165 - my $full_url = $url . ($fullpath eq "" ? "" : "/$fullpath");
166 + my $full_url = canonicalize_url( add_path_to_url( $url, $fullpath ) );
167
168 if ($_url) {
169 - print escape_url($full_url), "\n";
170 + print "$full_url\n";
171 return;
172 }
173
174 my $result = "Path: $path\n";
175 $result .= "Name: " . basename($path) . "\n" if $file_type ne "dir";
176 - $result .= "URL: " . escape_url($full_url) . "\n";
177 + $result .= "URL: $full_url\n";
178
179 eval {
180 my $repos_root = $gs->repos_root;
181 Git::SVN::remove_username($repos_root);
182 - $result .= "Repository Root: " . escape_url($repos_root) . "\n";
183 + $result .= "Repository Root: " . canonicalize_url($repos_root) . "\n";
184 };
185 if ($@) {
186 $result .= "Repository Root: (offline)\n";
187 @@ -1669,7 +1635,9 @@ sub post_fetch_checkout {
188
189 sub complete_svn_url {
190 my ($url, $path) = @_;
191 - $path =~ s#/+$##;
192 + $path = canonicalize_path($path);
193 +
194 + # If the path is not a URL...
195 if ($path !~ m#^[a-z\+]+://#) {
196 if (!defined $url || $url !~ m#^[a-z\+]+://#) {
197 fatal("E: '$path' is not a complete URL ",
198 @@ -1686,7 +1654,7 @@ sub complete_url_ls_init {
199 print STDERR "W: $switch not specified\n";
200 return;
201 }
202 - $repo_path =~ s#/+$##;
203 + $repo_path = canonicalize_path($repo_path);
204 if ($repo_path =~ m#^[a-z\+]+://#) {
205 $ra = Git::SVN::Ra->new($repo_path);
206 $repo_path = '';
207 @@ -1697,18 +1665,18 @@ sub complete_url_ls_init {
208 "and a separate URL is not specified");
209 }
210 }
211 - my $url = $ra->{url};
212 + my $url = $ra->url;
213 my $gs = Git::SVN->init($url, undef, undef, undef, 1);
214 my $k = "svn-remote.$gs->{repo_id}.url";
215 my $orig_url = eval { command_oneline(qw/config --get/, $k) };
216 - if ($orig_url && ($orig_url ne $gs->{url})) {
217 + if ($orig_url && ($orig_url ne $gs->url)) {
218 die "$k already set: $orig_url\n",
219 - "wanted to set to: $gs->{url}\n";
220 + "wanted to set to: $gs->url\n";
221 }
222 - command_oneline('config', $k, $gs->{url}) unless $orig_url;
223 - my $remote_path = "$gs->{path}/$repo_path";
224 + command_oneline('config', $k, $gs->url) unless $orig_url;
225 +
226 + my $remote_path = join_paths( $gs->path, $repo_path );
227 $remote_path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
228 - $remote_path =~ s#/+#/#g;
229 $remote_path =~ s#^/##g;
230 $remote_path .= "/*" if $remote_path !~ /\*/;
231 my ($n) = ($switch =~ /^--(\w+)/);
232 diff --git a/perl/Git/SVN.pm b/perl/Git/SVN.pm
233 index 8478d0c..acb2539 100644
234 --- a/perl/Git/SVN.pm
235 +++ b/perl/Git/SVN.pm
236 @@ -23,7 +23,14 @@ use Git qw(
237 command_output_pipe
238 command_close_pipe
239 );
240 -use Git::SVN::Utils qw(fatal can_compress);
241 +use Git::SVN::Utils qw(
242 + fatal
243 + can_compress
244 + join_paths
245 + canonicalize_path
246 + canonicalize_url
247 + add_path_to_url
248 +);
249
250 my $can_use_yaml;
251 BEGIN {
252 @@ -195,9 +202,9 @@ sub read_all_remotes {
253 } elsif (m!^(.+)\.usesvmprops=\s*(.*)\s*$!) {
254 $r->{$1}->{svm} = {};
255 } elsif (m!^(.+)\.url=\s*(.*)\s*$!) {
256 - $r->{$1}->{url} = $2;
257 + $r->{$1}->{url} = canonicalize_url($2);
258 } elsif (m!^(.+)\.pushurl=\s*(.*)\s*$!) {
259 - $r->{$1}->{pushurl} = $2;
260 + $r->{$1}->{pushurl} = canonicalize_url($2);
261 } elsif (m!^(.+)\.ignore-refs=\s*(.*)\s*$!) {
262 $r->{$1}->{ignore_refs_regex} = $2;
263 } elsif (m!^(.+)\.(branches|tags)=$svn_refspec$!) {
264 @@ -290,7 +297,7 @@ sub find_existing_remote {
265
266 sub init_remote_config {
267 my ($self, $url, $no_write) = @_;
268 - $url =~ s!/+$!!; # strip trailing slash
269 + $url = canonicalize_url($url);
270 my $r = read_all_remotes();
271 my $existing = find_existing_remote($url, $r);
272 if ($existing) {
273 @@ -314,12 +321,10 @@ sub init_remote_config {
274 print STDERR "Using higher level of URL: ",
275 "$url => $min_url\n";
276 }
277 - my $old_path = $self->{path};
278 - $self->{path} = $url;
279 - $self->{path} =~ s!^\Q$min_url\E(/|$)!!;
280 - if (length $old_path) {
281 - $self->{path} .= "/$old_path";
282 - }
283 + my $old_path = $self->path;
284 + $url =~ s!^\Q$min_url\E(/|$)!!;
285 + $url = join_paths($url, $old_path);
286 + $self->path($url);
287 $url = $min_url;
288 }
289 }
290 @@ -343,18 +348,22 @@ sub init_remote_config {
291 unless ($no_write) {
292 command_noisy('config',
293 "svn-remote.$self->{repo_id}.url", $url);
294 - $self->{path} =~ s{^/}{};
295 - $self->{path} =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
296 + my $path = $self->path;
297 + $path =~ s{^/}{};
298 + $path =~ s{%([0-9A-F]{2})}{chr hex($1)}ieg;
299 + $self->path($path);
300 command_noisy('config', '--add',
301 "svn-remote.$self->{repo_id}.fetch",
302 - "$self->{path}:".$self->refname);
303 + $self->path.":".$self->refname);
304 }
305 - $self->{url} = $url;
306 + $self->url($url);
307 }
308
309 sub find_by_url { # repos_root and, path are optional
310 my ($class, $full_url, $repos_root, $path) = @_;
311
312 + $full_url = canonicalize_url($full_url);
313 +
314 return undef unless defined $full_url;
315 remove_username($full_url);
316 remove_username($repos_root) if defined $repos_root;
317 @@ -393,6 +402,11 @@ sub find_by_url { # repos_root and, path are optional
318 }
319 $p =~ s#^\Q$z\E(?:/|$)#$prefix# or next;
320 }
321 +
322 + # remote fetch paths are not URI escaped. Decode ours
323 + # so they match
324 + $p = uri_decode($p);
325 +
326 foreach my $f (keys %$fetch) {
327 next if $f ne $p;
328 return Git::SVN->new($fetch->{$f}, $repo_id, $f);
329 @@ -435,20 +449,25 @@ sub new {
330 }
331 }
332 my $self = _new($class, $repo_id, $ref_id, $path);
333 - if (!defined $self->{path} || !length $self->{path}) {
334 + if (!defined $self->path || !length $self->path) {
335 my $fetch = command_oneline('config', '--get',
336 "svn-remote.$repo_id.fetch",
337 ":$ref_id\$") or
338 die "Failed to read \"svn-remote.$repo_id.fetch\" ",
339 "\":$ref_id\$\" in config\n";
340 - ($self->{path}, undef) = split(/\s*:\s*/, $fetch);
341 + my($path) = split(/\s*:\s*/, $fetch);
342 + $self->path($path);
343 }
344 - $self->{path} =~ s{/+}{/}g;
345 - $self->{path} =~ s{\A/}{};
346 - $self->{path} =~ s{/\z}{};
347 - $self->{url} = command_oneline('config', '--get',
348 - "svn-remote.$repo_id.url") or
349 + {
350 + my $path = $self->path;
351 + $path =~ s{\A/}{};
352 + $path =~ s{/\z}{};
353 + $self->path($path);
354 + }
355 + my $url = command_oneline('config', '--get',
356 + "svn-remote.$repo_id.url") or
357 die "Failed to read \"svn-remote.$repo_id.url\" in config\n";
358 + $self->url($url);
359 $self->{pushurl} = eval { command_oneline('config', '--get',
360 "svn-remote.$repo_id.pushurl") };
361 $self->rebuild;
362 @@ -552,8 +571,7 @@ sub _set_svm_vars {
363 # username is of no interest
364 $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1};
365
366 - my $replace = $ra->{url};
367 - $replace .= "/$path" if length $path;
368 + my $replace = add_path_to_url($ra->url, $path);
369
370 my $section = "svn-remote.$self->{repo_id}";
371 tmp_config("$section.svm-source", $src);
372 @@ -567,20 +585,21 @@ sub _set_svm_vars {
373 }
374
375 my $r = $ra->get_latest_revnum;
376 - my $path = $self->{path};
377 + my $path = $self->path;
378 my %tried;
379 while (length $path) {
380 - unless ($tried{"$self->{url}/$path"}) {
381 + my $try = add_path_to_url($self->url, $path);
382 + unless ($tried{$try}) {
383 return $ra if $self->read_svm_props($ra, $path, $r);
384 - $tried{"$self->{url}/$path"} = 1;
385 + $tried{$try} = 1;
386 }
387 $path =~ s#/?[^/]+$##;
388 }
389 die "Path: '$path' should be ''\n" if $path ne '';
390 return $ra if $self->read_svm_props($ra, $path, $r);
391 - $tried{"$self->{url}/$path"} = 1;
392 + $tried{ add_path_to_url($self->url, $path) } = 1;
393
394 - if ($ra->{repos_root} eq $self->{url}) {
395 + if ($ra->{repos_root} eq $self->url) {
396 die @err, (map { " $_\n" } keys %tried), "\n";
397 }
398
399 @@ -590,20 +609,21 @@ sub _set_svm_vars {
400 $path = $ra->{svn_path};
401 $ra = Git::SVN::Ra->new($ra->{repos_root});
402 while (length $path) {
403 - unless ($tried{"$ra->{url}/$path"}) {
404 + my $try = add_path_to_url($ra->url, $path);
405 + unless ($tried{$try}) {
406 $ok = $self->read_svm_props($ra, $path, $r);
407 last if $ok;
408 - $tried{"$ra->{url}/$path"} = 1;
409 + $tried{$try} = 1;
410 }
411 $path =~ s#/?[^/]+$##;
412 }
413 die "Path: '$path' should be ''\n" if $path ne '';
414 $ok ||= $self->read_svm_props($ra, $path, $r);
415 - $tried{"$ra->{url}/$path"} = 1;
416 + $tried{ add_path_to_url($ra->url, $path) } = 1;
417 if (!$ok) {
418 die @err, (map { " $_\n" } keys %tried), "\n";
419 }
420 - Git::SVN::Ra->new($self->{url});
421 + Git::SVN::Ra->new($self->url);
422 }
423
424 sub svnsync {
425 @@ -670,7 +690,7 @@ sub ra_uuid {
426 if (!$@ && $uuid && $uuid =~ /^([a-f\d\-]{30,})$/i) {
427 $self->{ra_uuid} = $uuid;
428 } else {
429 - die "ra_uuid called without URL\n" unless $self->{url};
430 + die "ra_uuid called without URL\n" unless $self->url;
431 $self->{ra_uuid} = $self->ra->get_uuid;
432 tmp_config('--add', $key, $self->{ra_uuid});
433 }
434 @@ -694,7 +714,7 @@ sub repos_root {
435
436 sub ra {
437 my ($self) = shift;
438 - my $ra = Git::SVN::Ra->new($self->{url});
439 + my $ra = Git::SVN::Ra->new($self->url);
440 $self->_set_repos_root($ra->{repos_root});
441 if ($self->use_svm_props && !$self->{svm}) {
442 if ($self->no_metadata) {
443 @@ -728,7 +748,7 @@ sub prop_walk {
444 $path =~ s#^/*#/#g;
445 my $p = $path;
446 # Strip the irrelevant part of the path.
447 - $p =~ s#^/+\Q$self->{path}\E(/|$)#/#;
448 + $p =~ s#^/+\Q@{[$self->path]}\E(/|$)#/#;
449 # Ensure the path is terminated by a `/'.
450 $p =~ s#/*$#/#;
451
452 @@ -749,7 +769,7 @@ sub prop_walk {
453
454 foreach (sort keys %$dirent) {
455 next if $dirent->{$_}->{kind} != $SVN::Node::dir;
456 - $self->prop_walk($self->{path} . $p . $_, $rev, $sub);
457 + $self->prop_walk($self->path . $p . $_, $rev, $sub);
458 }
459 }
460
461 @@ -919,20 +939,19 @@ sub rewrite_uuid {
462
463 sub metadata_url {
464 my ($self) = @_;
465 - ($self->rewrite_root || $self->{url}) .
466 - (length $self->{path} ? '/' . $self->{path} : '');
467 + my $url = $self->rewrite_root || $self->url;
468 + return canonicalize_url( add_path_to_url( $url, $self->path ) );
469 }
470
471 sub full_url {
472 my ($self) = @_;
473 - $self->{url} . (length $self->{path} ? '/' . $self->{path} : '');
474 + return canonicalize_url( add_path_to_url( $self->url, $self->path ) );
475 }
476
477 sub full_pushurl {
478 my ($self) = @_;
479 if ($self->{pushurl}) {
480 - return $self->{pushurl} . (length $self->{path} ? '/' .
481 - $self->{path} : '');
482 + return canonicalize_url( add_path_to_url( $self->{pushurl}, $self->path ) );
483 } else {
484 return $self->full_url;
485 }
486 @@ -1048,20 +1067,20 @@ sub do_git_commit {
487
488 sub match_paths {
489 my ($self, $paths, $r) = @_;
490 - return 1 if $self->{path} eq '';
491 - if (my $path = $paths->{"/$self->{path}"}) {
492 + return 1 if $self->path eq '';
493 + if (my $path = $paths->{"/".$self->path}) {
494 return ($path->{action} eq 'D') ? 0 : 1;
495 }
496 - $self->{path_regex} ||= qr/^\/\Q$self->{path}\E\//;
497 + $self->{path_regex} ||= qr{^/\Q@{[$self->path]}\E/};
498 if (grep /$self->{path_regex}/, keys %$paths) {
499 return 1;
500 }
501 my $c = '';
502 - foreach (split m#/#, $self->{path}) {
503 + foreach (split m#/#, $self->path) {
504 $c .= "/$_";
505 next unless ($paths->{$c} &&
506 ($paths->{$c}->{action} =~ /^[AR]$/));
507 - if ($self->ra->check_path($self->{path}, $r) ==
508 + if ($self->ra->check_path($self->path, $r) ==
509 $SVN::Node::dir) {
510 return 1;
511 }
512 @@ -1075,14 +1094,14 @@ sub find_parent_branch {
513 unless (defined $paths) {
514 my $err_handler = $SVN::Error::handler;
515 $SVN::Error::handler = \&Git::SVN::Ra::skip_unknown_revs;
516 - $self->ra->get_log([$self->{path}], $rev, $rev, 0, 1, 1,
517 + $self->ra->get_log([$self->path], $rev, $rev, 0, 1, 1,
518 sub { $paths = $_[0] });
519 $SVN::Error::handler = $err_handler;
520 }
521 return undef unless defined $paths;
522
523 # look for a parent from another branch:
524 - my @b_path_components = split m#/#, $self->{path};
525 + my @b_path_components = split m#/#, $self->path;
526 my @a_path_components;
527 my $i;
528 while (@b_path_components) {
529 @@ -1099,8 +1118,8 @@ sub find_parent_branch {
530 }
531 my $r = $i->{copyfrom_rev};
532 my $repos_root = $self->ra->{repos_root};
533 - my $url = $self->ra->{url};
534 - my $new_url = $url . $branch_from;
535 + my $url = $self->ra->url;
536 + my $new_url = canonicalize_url( add_path_to_url( $url, $branch_from ) );
537 print STDERR "Found possible branch point: ",
538 "$new_url => ", $self->full_url, ", $r\n"
539 unless $::_q > 1;
540 @@ -1114,7 +1133,7 @@ sub find_parent_branch {
541 ($base, $head) = parse_revision_argument(0, $r);
542 } else {
543 if ($r0 < $r) {
544 - $gs->ra->get_log([$gs->{path}], $r0 + 1, $r, 1,
545 + $gs->ra->get_log([$gs->path], $r0 + 1, $r, 1,
546 0, 1, sub { $base = $_[1] - 1 });
547 }
548 }
549 @@ -1136,7 +1155,7 @@ sub find_parent_branch {
550 # at the moment), so we can't rely on it
551 $self->{last_rev} = $r0;
552 $self->{last_commit} = $parent;
553 - $ed = Git::SVN::Fetcher->new($self, $gs->{path});
554 + $ed = Git::SVN::Fetcher->new($self, $gs->path);
555 $gs->ra->gs_do_switch($r0, $rev, $gs,
556 $self->full_url, $ed)
557 or die "SVN connection failed somewhere...\n";
558 @@ -1235,7 +1254,7 @@ sub mkemptydirs {
559 close $fh;
560 }
561
562 - my $strip = qr/\A\Q$self->{path}\E(?:\/|$)/;
563 + my $strip = qr/\A\Q@{[$self->path]}\E(?:\/|$)/;
564 foreach my $d (sort keys %empty_dirs) {
565 $d = uri_decode($d);
566 $d =~ s/$strip//;
567 @@ -1429,12 +1448,11 @@ sub find_extra_svk_parents {
568 for my $ticket ( @tickets ) {
569 my ($uuid, $path, $rev) = split /:/, $ticket;
570 if ( $uuid eq $self->ra_uuid ) {
571 - my $url = $self->{url};
572 - my $repos_root = $url;
573 + my $repos_root = $self->url;
574 my $branch_from = $path;
575 $branch_from =~ s{^/}{};
576 - my $gs = $self->other_gs($repos_root."/".$branch_from,
577 - $url,
578 + my $gs = $self->other_gs(add_path_to_url( $repos_root, $branch_from ),
579 + $repos_root,
580 $branch_from,
581 $rev,
582 $self->{ref_id});
583 @@ -1693,7 +1711,7 @@ sub find_extra_svn_parents {
584 # are now marked as merge, we can add the tip as a parent.
585 my @merges = split "\n", $mergeinfo;
586 my @merge_tips;
587 - my $url = $self->{url};
588 + my $url = $self->url;
589 my $uuid = $self->ra_uuid;
590 my %ranges;
591 for my $merge ( @merges ) {
592 @@ -1875,8 +1893,9 @@ sub make_log_entry {
593 $email ||= "$author\@$uuid";
594 $commit_email ||= "$author\@$uuid";
595 } elsif ($self->use_svnsync_props) {
596 - my $full_url = $self->svnsync->{url};
597 - $full_url .= "/$self->{path}" if length $self->{path};
598 + my $full_url = canonicalize_url(
599 + add_path_to_url( $self->svnsync->{url}, $self->path )
600 + );
601 remove_username($full_url);
602 my $uuid = $self->svnsync->{uuid};
603 $log_entry{metadata} = "$full_url\@$rev $uuid";
604 @@ -1923,7 +1942,7 @@ sub set_tree {
605 tree_b => $tree,
606 editor_cb => sub {
607 $self->set_tree_cb($log_entry, $tree, @_) },
608 - svn_path => $self->{path} );
609 + svn_path => $self->path );
610 if (!Git::SVN::Editor->new(\%ed_opts)->apply_diff) {
611 print "No changes\nr$self->{last_rev} = $tree\n";
612 }
613 @@ -2299,10 +2318,39 @@ sub _new {
614
615 $_[3] = $path = '' unless (defined $path);
616 mkpath([$dir]);
617 - bless {
618 + my $obj = bless {
619 ref_id => $ref_id, dir => $dir, index => "$dir/index",
620 - path => $path, config => "$ENV{GIT_DIR}/svn/config",
621 + config => "$ENV{GIT_DIR}/svn/config",
622 map_root => "$dir/.rev_map", repo_id => $repo_id }, $class;
623 +
624 + # Ensure it gets canonicalized
625 + $obj->path($path);
626 +
627 + return $obj;
628 +}
629 +
630 +sub path {
631 + my $self = shift;
632 +
633 + if (@_) {
634 + my $path = shift;
635 + $self->{path} = canonicalize_path($path);
636 + return;
637 + }
638 +
639 + return $self->{path};
640 +}
641 +
642 +sub url {
643 + my $self = shift;
644 +
645 + if (@_) {
646 + my $url = shift;
647 + $self->{url} = canonicalize_url($url);
648 + return;
649 + }
650 +
651 + return $self->{url};
652 }
653
654 # for read-only access of old .rev_db formats
655 diff --git a/perl/Git/SVN/Fetcher.pm b/perl/Git/SVN/Fetcher.pm
656 index 76fae9b..046a7a2 100644
657 --- a/perl/Git/SVN/Fetcher.pm
658 +++ b/perl/Git/SVN/Fetcher.pm
659 @@ -83,7 +83,7 @@ sub _mark_empty_symlinks {
660 chomp(my $empty_blob = `git hash-object -t blob --stdin < /dev/null`);
661 my ($ls, $ctx) = command_output_pipe(qw/ls-tree -r -z/, $cmt);
662 local $/ = "\0";
663 - my $pfx = defined($switch_path) ? $switch_path : $git_svn->{path};
664 + my $pfx = defined($switch_path) ? $switch_path : $git_svn->path;
665 $pfx .= '/' if length($pfx);
666 while (<$ls>) {
667 chomp;
668 diff --git a/perl/Git/SVN/Migration.pm b/perl/Git/SVN/Migration.pm
669 index 75d7429..30daf35 100644
670 --- a/perl/Git/SVN/Migration.pm
671 +++ b/perl/Git/SVN/Migration.pm
672 @@ -177,14 +177,14 @@ sub minimize_connections {
673 my $ra = Git::SVN::Ra->new($url);
674
675 # skip existing cases where we already connect to the root
676 - if (($ra->{url} eq $ra->{repos_root}) ||
677 + if (($ra->url eq $ra->{repos_root}) ||
678 ($ra->{repos_root} eq $repo_id)) {
679 - $root_repos->{$ra->{url}} = $repo_id;
680 + $root_repos->{$ra->url} = $repo_id;
681 next;
682 }
683
684 my $root_ra = Git::SVN::Ra->new($ra->{repos_root});
685 - my $root_path = $ra->{url};
686 + my $root_path = $ra->url;
687 $root_path =~ s#^\Q$ra->{repos_root}\E(/|$)##;
688 foreach my $path (keys %$fetch) {
689 my $ref_id = $fetch->{$path};
690 diff --git a/perl/Git/SVN/Ra.pm b/perl/Git/SVN/Ra.pm
691 index 23ff43e..90ec30b 100644
692 --- a/perl/Git/SVN/Ra.pm
693 +++ b/perl/Git/SVN/Ra.pm
694 @@ -3,6 +3,12 @@ use vars qw/@ISA $config_dir $_ignore_refs_regex $_log_window_size/;
695 use strict;
696 use warnings;
697 use SVN::Client;
698 +use Git::SVN::Utils qw(
699 + canonicalize_url
700 + canonicalize_path
701 + add_path_to_url
702 +);
703 +
704 use SVN::Ra;
705 BEGIN {
706 @ISA = qw(SVN::Ra);
707 @@ -62,29 +68,11 @@ sub _auth_providers () {
708 \@rv;
709 }
710
711 -sub escape_uri_only {
712 - my ($uri) = @_;
713 - my @tmp;
714 - foreach (split m{/}, $uri) {
715 - s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
716 - push @tmp, $_;
717 - }
718 - join('/', @tmp);
719 -}
720 -
721 -sub escape_url {
722 - my ($url) = @_;
723 - if ($url =~ m#^(https?)://([^/]+)(.*)$#) {
724 - my ($scheme, $domain, $uri) = ($1, $2, escape_uri_only($3));
725 - $url = "$scheme://$domain$uri";
726 - }
727 - $url;
728 -}
729
730 sub new {
731 my ($class, $url) = @_;
732 - $url =~ s!/+$!!;
733 - return $RA if ($RA && $RA->{url} eq $url);
734 + $url = canonicalize_url($url);
735 + return $RA if ($RA && $RA->url eq $url);
736
737 ::_req_svn();
738
739 @@ -115,17 +103,34 @@ sub new {
740 $Git::SVN::Prompt::_no_auth_cache = 1;
741 }
742 } # no warnings 'once'
743 - my $self = SVN::Ra->new(url => escape_url($url), auth => $baton,
744 +
745 + my $self = SVN::Ra->new(url => $url, auth => $baton,
746 config => $config,
747 pool => SVN::Pool->new,
748 auth_provider_callbacks => $callbacks);
749 - $self->{url} = $url;
750 + $RA = bless $self, $class;
751 +
752 + # Make sure its canonicalized
753 + $self->url($url);
754 $self->{svn_path} = $url;
755 $self->{repos_root} = $self->get_repos_root;
756 $self->{svn_path} =~ s#^\Q$self->{repos_root}\E(/|$)##;
757 $self->{cache} = { check_path => { r => 0, data => {} },
758 get_dir => { r => 0, data => {} } };
759 - $RA = bless $self, $class;
760 +
761 + return $RA;
762 +}
763 +
764 +sub url {
765 + my $self = shift;
766 +
767 + if (@_) {
768 + my $url = shift;
769 + $self->{url} = canonicalize_url($url);
770 + return;
771 + }
772 +
773 + return $self->{url};
774 }
775
776 sub check_path {
777 @@ -195,6 +200,7 @@ sub get_log {
778 qw/copyfrom_path copyfrom_rev action/;
779 if ($s{'copyfrom_path'}) {
780 $s{'copyfrom_path'} =~ s/$prefix_regex//;
781 + $s{'copyfrom_path'} = canonicalize_path($s{'copyfrom_path'});
782 }
783 $_[0]{$p} = \%s;
784 }
785 @@ -246,7 +252,7 @@ sub get_commit_editor {
786 sub gs_do_update {
787 my ($self, $rev_a, $rev_b, $gs, $editor) = @_;
788 my $new = ($rev_a == $rev_b);
789 - my $path = $gs->{path};
790 + my $path = $gs->path;
791
792 if ($new && -e $gs->{index}) {
793 unlink $gs->{index} or die
794 @@ -282,30 +288,33 @@ sub gs_do_update {
795 # svn_ra_reparent didn't work before 1.4)
796 sub gs_do_switch {
797 my ($self, $rev_a, $rev_b, $gs, $url_b, $editor) = @_;
798 - my $path = $gs->{path};
799 + my $path = $gs->path;
800 my $pool = SVN::Pool->new;
801
802 - my $full_url = $self->{url};
803 - my $old_url = $full_url;
804 - $full_url .= '/' . $path if length $path;
805 + my $old_url = $self->url;
806 + my $full_url = add_path_to_url( $self->url, $path );
807 my ($ra, $reparented);
808
809 if ($old_url =~ m#^svn(\+ssh)?://# ||
810 ($full_url =~ m#^https?://# &&
811 - escape_url($full_url) ne $full_url)) {
812 + canonicalize_url($full_url) ne $full_url)) {
813 $_[0] = undef;
814 $self = undef;
815 $RA = undef;
816 $ra = Git::SVN::Ra->new($full_url);
817 $ra_invalid = 1;
818 } elsif ($old_url ne $full_url) {
819 - SVN::_Ra::svn_ra_reparent($self->{session}, $full_url, $pool);
820 - $self->{url} = $full_url;
821 + SVN::_Ra::svn_ra_reparent(
822 + $self->{session},
823 + canonicalize_url($full_url),
824 + $pool
825 + );
826 + $self->url($full_url);
827 $reparented = 1;
828 }
829
830 $ra ||= $self;
831 - $url_b = escape_url($url_b);
832 + $url_b = canonicalize_url($url_b);
833 my $reporter = $ra->do_switch($rev_b, '', 1, $url_b, $editor, $pool);
834 my @lock = (::compare_svn_version('1.2.0') >= 0) ? (undef) : ();
835 $reporter->set_path('', $rev_a, 0, @lock, $pool);
836 @@ -313,7 +322,7 @@ sub gs_do_switch {
837
838 if ($reparented) {
839 SVN::_Ra::svn_ra_reparent($self->{session}, $old_url, $pool);
840 - $self->{url} = $old_url;
841 + $self->url($old_url);
842 }
843
844 $pool->clear;
845 @@ -326,7 +335,7 @@ sub longest_common_path {
846 my $common_max = scalar @$gsv;
847
848 foreach my $gs (@$gsv) {
849 - my @tmp = split m#/#, $gs->{path};
850 + my @tmp = split m#/#, $gs->path;
851 my $p = '';
852 foreach (@tmp) {
853 $p .= length($p) ? "/$_" : $_;
854 @@ -362,7 +371,7 @@ sub gs_fetch_loop_common {
855 my $inc = $_log_window_size;
856 my ($min, $max) = ($base, $head < $base + $inc ? $head : $base + $inc);
857 my $longest_path = longest_common_path($gsv, $globs);
858 - my $ra_url = $self->{url};
859 + my $ra_url = $self->url;
860 my $find_trailing_edge;
861 while (1) {
862 my %revs;
863 @@ -508,7 +517,7 @@ sub match_globs {
864 ($self->check_path($p, $r) !=
865 $SVN::Node::dir));
866 next unless $p =~ /$g->{path}->{regex}/;
867 - $exists->{$p} = Git::SVN->init($self->{url}, $p, undef,
868 + $exists->{$p} = Git::SVN->init($self->url, $p, undef,
869 $g->{ref}->full_path($de), 1);
870 }
871 }
872 @@ -532,7 +541,7 @@ sub match_globs {
873 next if ($self->check_path($pathname, $r) !=
874 $SVN::Node::dir);
875 $exists->{$pathname} = Git::SVN->init(
876 - $self->{url}, $pathname, undef,
877 + $self->url, $pathname, undef,
878 $g->{ref}->full_path($p), 1);
879 }
880 my $c = '';
881 @@ -548,19 +557,20 @@ sub match_globs {
882
883 sub minimize_url {
884 my ($self) = @_;
885 - return $self->{url} if ($self->{url} eq $self->{repos_root});
886 + return $self->url if ($self->url eq $self->{repos_root});
887 my $url = $self->{repos_root};
888 my @components = split(m!/!, $self->{svn_path});
889 my $c = '';
890 do {
891 - $url .= "/$c" if length $c;
892 + $url = add_path_to_url($url, $c);
893 eval {
894 my $ra = (ref $self)->new($url);
895 my $latest = $ra->get_latest_revnum;
896 $ra->get_log("", $latest, 0, 1, 0, 1, sub {});
897 };
898 } while ($@ && ($c = shift @components));
899 - $url;
900 +
901 + return canonicalize_url($url);
902 }
903
904 sub can_do_switch {
905 @@ -568,7 +578,7 @@ sub can_do_switch {
906 unless (defined $can_do_switch) {
907 my $pool = SVN::Pool->new;
908 my $rep = eval {
909 - $self->do_switch(1, '', 0, $self->{url},
910 + $self->do_switch(1, '', 0, $self->url,
911 SVN::Delta::Editor->new, $pool);
912 };
913 if ($@) {
914 diff --git a/perl/Git/SVN/Utils.pm b/perl/Git/SVN/Utils.pm
915 index 496006b..4bb4dde 100644
916 --- a/perl/Git/SVN/Utils.pm
917 +++ b/perl/Git/SVN/Utils.pm
918 @@ -3,9 +3,18 @@ package Git::SVN::Utils;
919 use strict;
920 use warnings;
921
922 +use SVN::Core;
923 +
924 use base qw(Exporter);
925
926 -our @EXPORT_OK = qw(fatal can_compress);
927 +our @EXPORT_OK = qw(
928 + fatal
929 + can_compress
930 + canonicalize_path
931 + canonicalize_url
932 + join_paths
933 + add_path_to_url
934 +);
935
936
937 =head1 NAME
938 @@ -56,4 +65,169 @@ sub can_compress {
939 }
940
941
942 +=head3 canonicalize_path
943 +
944 + my $canoncalized_path = canonicalize_path($path);
945 +
946 +Converts $path into a canonical form which is safe to pass to the SVN
947 +API as a file path.
948 +
949 +=cut
950 +
951 +# Turn foo/../bar into bar
952 +sub _collapse_dotdot {
953 + my $path = shift;
954 +
955 + 1 while $path =~ s{/[^/]+/+\.\.}{};
956 + 1 while $path =~ s{[^/]+/+\.\./}{};
957 + 1 while $path =~ s{[^/]+/+\.\.}{};
958 +
959 + return $path;
960 +}
961 +
962 +
963 +sub canonicalize_path {
964 + my $path = shift;
965 + my $rv;
966 +
967 + # The 1.7 way to do it
968 + if ( defined &SVN::_Core::svn_dirent_canonicalize ) {
969 + $path = _collapse_dotdot($path);
970 + $rv = SVN::_Core::svn_dirent_canonicalize($path);
971 + }
972 + # The 1.6 way to do it
973 + # This can return undef on subversion-perl-1.4.2-2.el5 (CentOS 5.2)
974 + elsif ( defined &SVN::_Core::svn_path_canonicalize ) {
975 + $path = _collapse_dotdot($path);
976 + $rv = SVN::_Core::svn_path_canonicalize($path);
977 + }
978 +
979 + return $rv if defined $rv;
980 +
981 + # No SVN API canonicalization is available, or the SVN API
982 + # didn't return a successful result, do it ourselves
983 + return _canonicalize_path_ourselves($path);
984 +}
985 +
986 +
987 +sub _canonicalize_path_ourselves {
988 + my ($path) = @_;
989 + my $dot_slash_added = 0;
990 + if (substr($path, 0, 1) ne "/") {
991 + $path = "./" . $path;
992 + $dot_slash_added = 1;
993 + }
994 + $path =~ s#/+#/#g;
995 + $path =~ s#/\.(?:/|$)#/#g;
996 + $path = _collapse_dotdot($path);
997 + $path =~ s#/$##g;
998 + $path =~ s#^\./## if $dot_slash_added;
999 + $path =~ s#^/##;
1000 + $path =~ s#^\.$##;
1001 + return $path;
1002 +}
1003 +
1004 +
1005 +=head3 canonicalize_url
1006 +
1007 + my $canonicalized_url = canonicalize_url($url);
1008 +
1009 +Converts $url into a canonical form which is safe to pass to the SVN
1010 +API as a URL.
1011 +
1012 +=cut
1013 +
1014 +sub canonicalize_url {
1015 + my $url = shift;
1016 +
1017 + # The 1.7 way to do it
1018 + if ( defined &SVN::_Core::svn_uri_canonicalize ) {
1019 + return SVN::_Core::svn_uri_canonicalize($url);
1020 + }
1021 + # There wasn't a 1.6 way to do it, so we do it ourself.
1022 + else {
1023 + return _canonicalize_url_ourselves($url);
1024 + }
1025 +}
1026 +
1027 +
1028 +sub _canonicalize_url_path {
1029 + my ($uri_path) = @_;
1030 +
1031 + my @parts;
1032 + foreach my $part (split m{/+}, $uri_path) {
1033 + $part =~ s/([^~\w.%+-]|%(?![a-fA-F0-9]{2}))/sprintf("%%%02X",ord($1))/eg;
1034 + push @parts, $part;
1035 + }
1036 +
1037 + return join('/', @parts);
1038 +}
1039 +
1040 +sub _canonicalize_url_ourselves {
1041 + my ($url) = @_;
1042 + if ($url =~ m#^([^:]+)://([^/]*)(.*)$#) {
1043 + my ($scheme, $domain, $uri) = ($1, $2, _canonicalize_url_path(canonicalize_path($3)));
1044 + $url = "$scheme://$domain$uri";
1045 + }
1046 + $url;
1047 +}
1048 +
1049 +
1050 +=head3 join_paths
1051 +
1052 + my $new_path = join_paths(@paths);
1053 +
1054 +Appends @paths together into a single path. Any empty paths are ignored.
1055 +
1056 +=cut
1057 +
1058 +sub join_paths {
1059 + my @paths = @_;
1060 +
1061 + @paths = grep { defined $_ && length $_ } @paths;
1062 +
1063 + return '' unless @paths;
1064 + return $paths[0] if @paths == 1;
1065 +
1066 + my $new_path = shift @paths;
1067 + $new_path =~ s{/+$}{};
1068 +
1069 + my $last_path = pop @paths;
1070 + $last_path =~ s{^/+}{};
1071 +
1072 + for my $path (@paths) {
1073 + $path =~ s{^/+}{};
1074 + $path =~ s{/+$}{};
1075 + $new_path .= "/$path";
1076 + }
1077 +
1078 + return $new_path .= "/$last_path";
1079 +}
1080 +
1081 +
1082 +=head3 add_path_to_url
1083 +
1084 + my $new_url = add_path_to_url($url, $path);
1085 +
1086 +Appends $path onto the $url. If $path is empty, $url is returned unchanged.
1087 +
1088 +=cut
1089 +
1090 +sub add_path_to_url {
1091 + my($url, $path) = @_;
1092 +
1093 + return $url if !defined $path or !length $path;
1094 +
1095 + # Strip trailing and leading slashes so we don't
1096 + # wind up with http://x.com///path
1097 + $url =~ s{/+$}{};
1098 + $path =~ s{^/+}{};
1099 +
1100 + # If a path has a % in it, URI escape it so it's not
1101 + # mistaken for a URI escape later.
1102 + $path =~ s{%}{%25}g;
1103 +
1104 + return join '/', $url, $path;
1105 +}
1106 +
1107 1;
1108 diff --git a/t/Git-SVN/Utils/add_path_to_url.t b/t/Git-SVN/Utils/add_path_to_url.t
1109 new file mode 100644
1110 index 0000000..bfbd878
1111 --- /dev/null
1112 +++ b/t/Git-SVN/Utils/add_path_to_url.t
1113 @@ -0,0 +1,27 @@
1114 +#!/usr/bin/env perl
1115 +
1116 +use strict;
1117 +use warnings;
1118 +
1119 +use Test::More 'no_plan';
1120 +
1121 +use Git::SVN::Utils qw(
1122 + add_path_to_url
1123 +);
1124 +
1125 +# A reference cannot be a hash key, so we use an array.
1126 +my @tests = (
1127 + ["http://x.com", "bar"] => 'http://x.com/bar',
1128 + ["http://x.com", ""] => 'http://x.com',
1129 + ["http://x.com/foo/", undef] => 'http://x.com/foo/',
1130 + ["http://x.com/foo/", "/bar/baz/"] => 'http://x.com/foo/bar/baz/',
1131 + ["http://x.com", 'per%cent'] => 'http://x.com/per%25cent',
1132 +);
1133 +
1134 +while(@tests) {
1135 + my($have, $want) = splice @tests, 0, 2;
1136 +
1137 + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
1138 + my $name = "add_path_to_url($args) eq $want";
1139 + is add_path_to_url(@$have), $want, $name;
1140 +}
1141 diff --git a/t/Git-SVN/Utils/canonicalize_url.t b/t/Git-SVN/Utils/canonicalize_url.t
1142 new file mode 100644
1143 index 0000000..05795ab
1144 --- /dev/null
1145 +++ b/t/Git-SVN/Utils/canonicalize_url.t
1146 @@ -0,0 +1,26 @@
1147 +#!/usr/bin/env perl
1148 +
1149 +# Test our own home rolled URL canonicalizer. Test the private one
1150 +# directly because we can't predict what the SVN API is doing to do.
1151 +
1152 +use strict;
1153 +use warnings;
1154 +
1155 +use Test::More 'no_plan';
1156 +
1157 +use Git::SVN::Utils;
1158 +my $canonicalize_url = \&Git::SVN::Utils::_canonicalize_url_ourselves;
1159 +
1160 +my %tests = (
1161 + "http://x.com" => "http://x.com",
1162 + "http://x.com/" => "http://x.com",
1163 + "http://x.com/foo/bar" => "http://x.com/foo/bar",
1164 + "http://x.com//foo//bar//" => "http://x.com/foo/bar",
1165 + "http://x.com/ /%/" => "http://x.com/%20%20/%25",
1166 +);
1167 +
1168 +for my $arg (keys %tests) {
1169 + my $want = $tests{$arg};
1170 +
1171 + is $canonicalize_url->($arg), $want, "canonicalize_url('$arg') => $want";
1172 +}
1173 diff --git a/t/Git-SVN/Utils/collapse_dotdot.t b/t/Git-SVN/Utils/collapse_dotdot.t
1174 new file mode 100644
1175 index 0000000..1da1cce
1176 --- /dev/null
1177 +++ b/t/Git-SVN/Utils/collapse_dotdot.t
1178 @@ -0,0 +1,23 @@
1179 +#!/usr/bin/env perl
1180 +
1181 +use strict;
1182 +use warnings;
1183 +
1184 +use Test::More 'no_plan';
1185 +
1186 +use Git::SVN::Utils;
1187 +my $collapse_dotdot = \&Git::SVN::Utils::_collapse_dotdot;
1188 +
1189 +my %tests = (
1190 + "foo/bar/baz" => "foo/bar/baz",
1191 + ".." => "..",
1192 + "foo/.." => "",
1193 + "/foo/bar/../../baz" => "/baz",
1194 + "deeply/.././deeply/nested" => "./deeply/nested",
1195 +);
1196 +
1197 +for my $arg (keys %tests) {
1198 + my $want = $tests{$arg};
1199 +
1200 + is $collapse_dotdot->($arg), $want, "_collapse_dotdot('$arg') => $want";
1201 +}
1202 diff --git a/t/Git-SVN/Utils/join_paths.t b/t/Git-SVN/Utils/join_paths.t
1203 new file mode 100644
1204 index 0000000..d4488e7
1205 --- /dev/null
1206 +++ b/t/Git-SVN/Utils/join_paths.t
1207 @@ -0,0 +1,32 @@
1208 +#!/usr/bin/env perl
1209 +
1210 +use strict;
1211 +use warnings;
1212 +
1213 +use Test::More 'no_plan';
1214 +
1215 +use Git::SVN::Utils qw(
1216 + join_paths
1217 +);
1218 +
1219 +# A reference cannot be a hash key, so we use an array.
1220 +my @tests = (
1221 + [] => '',
1222 + ["/x.com", "bar"] => '/x.com/bar',
1223 + ["x.com", ""] => 'x.com',
1224 + ["/x.com/foo/", undef, "bar"] => '/x.com/foo/bar',
1225 + ["x.com/foo/", "/bar/baz/"] => 'x.com/foo/bar/baz/',
1226 + ["foo", "bar"] => 'foo/bar',
1227 + ["/foo/bar", "baz", "/biff"] => '/foo/bar/baz/biff',
1228 + ["", undef, "."] => '.',
1229 + [] => '',
1230 +
1231 +);
1232 +
1233 +while(@tests) {
1234 + my($have, $want) = splice @tests, 0, 2;
1235 +
1236 + my $args = join ", ", map { qq['$_'] } map { defined($_) ? $_ : 'undef' } @$have;
1237 + my $name = "join_paths($args) eq '$want'";
1238 + is join_paths(@$have), $want, $name;
1239 +}
1240 diff --git a/t/t9107-git-svn-migrate.sh b/t/t9107-git-svn-migrate.sh
1241 index 289fc31..ee73013 100755
1242 --- a/t/t9107-git-svn-migrate.sh
1243 +++ b/t/t9107-git-svn-migrate.sh
1244 @@ -27,15 +27,17 @@ test_expect_success 'setup old-looking metadata' '
1245 head=`git rev-parse --verify refs/heads/git-svn-HEAD^0`
1246 test_expect_success 'git-svn-HEAD is a real HEAD' "test -n '$head'"
1247
1248 +svnrepo_escaped=`echo $svnrepo | sed 's/ /%20/'`
1249 +
1250 test_expect_success 'initialize old-style (v0) git svn layout' '
1251 mkdir -p "$GIT_DIR"/git-svn/info "$GIT_DIR"/svn/info &&
1252 echo "$svnrepo" > "$GIT_DIR"/git-svn/info/url &&
1253 echo "$svnrepo" > "$GIT_DIR"/svn/info/url &&
1254 git svn migrate &&
1255 - ! test -d "$GIT_DIR"/git svn &&
1256 + ! test -d "$GIT_DIR"/git-svn &&
1257 git rev-parse --verify refs/${remotes_git_svn}^0 &&
1258 git rev-parse --verify refs/remotes/svn^0 &&
1259 - test "$(git config --get svn-remote.svn.url)" = "$svnrepo" &&
1260 + test "$(git config --get svn-remote.svn.url)" = "$svnrepo_escaped" &&
1261 test `git config --get svn-remote.svn.fetch` = \
1262 ":refs/${remotes_git_svn}"
1263 '
1264 diff --git a/t/t9118-git-svn-funky-branch-names.sh b/t/t9118-git-svn-funky-branch-names.sh
1265 index 63fc982..193d3ca 100755
1266 --- a/t/t9118-git-svn-funky-branch-names.sh
1267 +++ b/t/t9118-git-svn-funky-branch-names.sh
1268 @@ -32,6 +32,11 @@ test_expect_success 'setup svnrepo' '
1269 start_httpd
1270 '
1271
1272 +# SVN 1.7 will truncate "not-a%40{0]" to just "not-a".
1273 +# Look at what SVN wound up naming the branch and use that.
1274 +# Be sure to escape the @ if it shows up.
1275 +non_reflog=`svn_cmd ls "$svnrepo/pr ject/branches" | grep not-a | sed 's/\///' | sed 's/@/%40/'`
1276 +
1277 test_expect_success 'test clone with funky branch names' '
1278 git svn clone -s "$svnrepo/pr ject" project &&
1279 (
1280 @@ -42,7 +47,7 @@ test_expect_success 'test clone with funky branch names' '
1281 git rev-parse "refs/remotes/%2Eleading_dot" &&
1282 git rev-parse "refs/remotes/trailing_dot%2E" &&
1283 git rev-parse "refs/remotes/trailing_dotlock%2Elock" &&
1284 - git rev-parse "refs/remotes/not-a%40{0}reflog"
1285 + git rev-parse "refs/remotes/$non_reflog"
1286 )
1287 '
1288

  ViewVC Help
Powered by ViewVC 1.1.20