diff --git a/git-svn.perl b/git-svn.perl index 7563eea352..1bcf058ef6 100755 --- a/git-svn.perl +++ b/git-svn.perl @@ -164,7 +164,9 @@ read_repo_config(\%opts); my $rv = GetOptions(%opts, 'help|H|h' => \$_help, 'version|V' => \$_version, 'minimize-connections' => \$Git::SVN::Migration::_minimize, 'id|i=s' => \$Git::SVN::default_ref_id, - 'svn-remote|remote|R=s' => \$Git::SVN::default_repo_id); + 'svn-remote|remote|R=s' => sub { + $Git::SVN::no_reuse_existing = 1; + $Git::SVN::default_repo_id = $_[1] }); exit 1 if (!$rv && $cmd ne 'log'); usage(0) if $_help; @@ -749,7 +751,7 @@ use strict; use warnings; use vars qw/$default_repo_id $default_ref_id $_no_metadata $_follow_parent $_repack $_repack_flags $_use_svm_props $_head - $_use_svnsync_props/; + $_use_svnsync_props $no_reuse_existing/; use Carp qw/croak/; use File::Path qw/mkpath/; use File::Copy qw/copy/; @@ -944,6 +946,7 @@ sub sanitize_remote_name { sub find_existing_remote { my ($url, $remotes) = @_; + return undef if $no_reuse_existing; my $existing; foreach my $repo_id (keys %$remotes) { my $u = $remotes->{$repo_id}->{url} or next; @@ -1116,9 +1119,12 @@ sub svm { $svm = { source => tmp_config('--get', "$section.svm-source"), uuid => tmp_config('--get', "$section.svm-uuid"), + replace => tmp_config('--get', "$section.svm-replace"), } }; - $self->{svm} = $svm if ($svm && $svm->{source} && $svm->{uuid}); + if ($svm && $svm->{source} && $svm->{uuid} && $svm->{replace}) { + $self->{svm} = $svm; + } $self->{svm}; } @@ -1127,64 +1133,76 @@ sub _set_svm_vars { return $ra if $self->svm; my @err = ( "useSvmProps set, but failed to read SVM properties\n", - "(svm:source, svm:mirror, svm:mirror) ", + "(svm:source, svm:uuid) ", "from the following URLs:\n" ); sub read_svm_props { - my ($self, $props) = @_; + my ($self, $ra, $path, $r) = @_; + my $props = ($ra->get_dir($path, $r))[2]; my $src = $props->{'svm:source'}; - my $mirror = $props->{'svm:mirror'}; my $uuid = $props->{'svm:uuid'}; - return undef if (!$src || !$mirror || !$uuid); + return undef if (!$src || !$uuid); - chomp($src, $mirror, $uuid); + chomp($src, $uuid); $uuid =~ m{^[0-9a-f\-]{30,}$} or die "doesn't look right - svm:uuid is '$uuid'\n"; - # don't know what a '!' is there for, also the - # username is of no interest - $src =~ s{/?!$}{$mirror}; + + # the '!' is used to mark the repos_root!/relative/path + $src =~ s{/?!/?}{/}; $src =~ s{/+$}{}; # no trailing slashes please + # username is of no interest $src =~ s{(^[a-z\+]*://)[^/@]*@}{$1}; + my $replace = $ra->{url}; + $replace .= "/$path" if length $path; + my $section = "svn-remote.$self->{repo_id}"; - tmp_config('--add', "$section.svm-source", $src); - tmp_config('--add', "$section.svm-uuid", $uuid); - $self->{svm} = { source => $src , uuid => $uuid }; - return 1; + tmp_config("$section.svm-source", $src); + tmp_config("$section.svm-replace", $replace); + tmp_config("$section.svm-uuid", $uuid); + $self->{svm} = { + source => $src, + uuid => $uuid, + replace => $replace + }; } my $r = $ra->get_latest_revnum; my $path = $self->{path}; - my @tried_a = ($path); + my %tried; while (length $path) { - if ($self->read_svm_props(($ra->get_dir($path, $r))[2])) { - return $ra; + unless ($tried{"$self->{url}/$path"}) { + return $ra if $self->read_svm_props($ra, $path, $r); + $tried{"$self->{url}/$path"} = 1; } - $path =~ s#/?[^/]+$## && push @tried_a, $path; - } - if ($self->read_svm_props(($ra->get_dir('', $r))[2])) { - return $ra; + $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; if ($ra->{repos_root} eq $self->{url}) { - die @err, map { " $self->{url}/$_\n" } @tried_a, "\n"; + die @err, (map { " $_\n" } keys %tried), "\n"; } # nope, make sure we're connected to the repository root: my $ok; my @tried_b; $path = $ra->{svn_path}; - $path =~ s#/?[^/]+$##; # we already tried this one above $ra = Git::SVN::Ra->new($ra->{repos_root}); while (length $path) { - $ok = $self->read_svm_props(($ra->get_dir($path, $r))[2]); - last if $ok; - $path =~ s#/?[^/]+$## && push @tried_b, $path; + unless ($tried{"$ra->{url}/$path"}) { + $ok = $self->read_svm_props($ra, $path, $r); + last if $ok; + $tried{"$ra->{url}/$path"} = 1; + } + $path =~ s#/?[^/]+$##; } - $ok = $self->read_svm_props(($ra->get_dir('', $r))[2]) unless $ok; + die "Path: '$path' should be ''\n" if $path ne ''; + $ok ||= $self->read_svm_props($ra, $path, $r); + $tried{"$ra->{url}/$path"} = 1; if (!$ok) { - die @err, map { " $self->{url}/$_\n" } @tried_a, "\n", - map { " $ra->{url}/$_\n" } @tried_b, "\n" + die @err, (map { " $_\n" } keys %tried), "\n"; } Git::SVN::Ra->new($self->{url}); } @@ -1779,13 +1797,18 @@ sub make_log_entry { "options set!\n"; } my ($uuid, $r) = $headrev =~ m{^([a-f\d\-]{30,}):(\d+)$}; - if ($uuid ne $self->{svm}->{uuid}) { + # we don't want "SVM: initializing mirror for junk" ... + return undef if $r == 0; + my $svm = $self->svm; + if ($uuid ne $svm->{uuid}) { die "UUID mismatch on SVM path:\n", - "expected: $self->{svm}->{uuid}\n", + "expected: $svm->{uuid}\n", " got: $uuid\n"; } - my $full_url = $self->{svm}->{source}; - $full_url .= "/$self->{path}" if length $self->{path}; + my $full_url = $self->full_url; + $full_url =~ s#^\Q$svm->{replace}\E(/|$)#$svm->{source}$1# or + die "Failed to replace '$svm->{replace}' with ", + "'$svm->{source}' in $full_url\n"; $log_entry{metadata} = "$full_url\@$r $uuid"; $log_entry{svm_revision} = $r; $email ||= "$author\@$uuid" diff --git a/t/t9109-git-svn-svk-mirrorpaths.sh b/t/t9109-git-svn-svk-mirrorpaths.sh deleted file mode 100755 index 1e1b97b5fc..0000000000 --- a/t/t9109-git-svn-svk-mirrorpaths.sh +++ /dev/null @@ -1,106 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2006 Sam Vilian -# - -test_description='git-svn on SVK mirror paths' -. ./lib-git-svn.sh - -# ok, people who don't have SVK installed probably don't care about -# this test. - -# we set up the repository manually, because even if SVK is installed -# it is difficult to use it in a way that is idempotent. - -# we are not yet testing merge tickets.. - -uuid=b00bface-b1ff-c0ff-f0ff-b0bafe775e1e -url=https://really.slow.server.com/foobar - -test_expect_success 'initialize repo' " - git config svn-remote.svn.useSvmProps true && - - echo '#!/bin/sh' > $rawsvnrepo/hooks/pre-revprop-change && - echo 'exit 0' >> $rawsvnrepo/hooks/pre-revprop-change && - chmod +x $rawsvnrepo/hooks/pre-revprop-change && - - mkdir import && - cd import && - mkdir local && - echo hello > local/readme && - svn import -m 'random local work' . $svnrepo && - cd .. && - - svn co $svnrepo wc && - cd wc && - mkdir -p mirror/foobar && - svn add mirror && - svn ps svm:source $url mirror/foobar && - svn ps svm:uuid $uuid mirror/foobar && - svn ps svm:mirror / mirror/foobar && - svn commit -m 'setup mirror/foobar as mirror of upstream' && - svn ps -r 2 --revprop svm:headrev $uuid:0 $svnrepo && - - mkdir mirror/foobar/trunk - echo hello, world > mirror/foobar/trunk/readme && - svn add mirror/foobar/trunk && - svn commit -m 'first upstream revision' && - svn ps -r 3 --revprop svm:headrev $uuid:1 $svnrepo && - - svn up && - svn mkdir mirror/foobar/branches && - svn cp mirror/foobar/trunk mirror/foobar/branches/silly && - svn commit -m 'make branch for silliness' && - svn ps -r 4 --revprop svm:headrev $uuid:2 $svnrepo && - - svn up && - echo random untested feature >> mirror/foobar/trunk/readme && - poke mirror/foobar/trunk/readme && - svn commit -m 'add a c00l feature to trunk' && - svn ps -r 5 --revprop svm:headrev $uuid:3 $svnrepo && - - svn up && - echo bug fix >> mirror/foobar/branches/silly/readme && - poke mirror/foobar/branches/silly/readme && - svn commit -m 'fix a bug' && - svn ps -r 6 --revprop svm:headrev $uuid:4 $svnrepo && - - svn mkdir mirror/foobar/tags && - svn cp mirror/foobar/branches/silly mirror/foobar/tags/blah-1.0 && - svn commit -m 'make a release' && - svn ps -r 7 --revprop svm:headrev $uuid:5 $svnrepo && - - cd .. - " - -test_expect_success 'init an SVK mirror path' " - git-svn init -T trunk -t tags -b branches $svnrepo/mirror/foobar - " - -test_expect_success 'multi-fetch an SVK mirror path' "git-svn multi-fetch" - -test_expect_success 'got tag history OK' " - test \`git-log --pretty=oneline remotes/tags/blah-1.0 | wc -l\` -eq 3 - " - -test_expect_success 're-wrote git-svn-id URL, revision and UUID' " - git cat-file commit refs/remotes/trunk | \ - fgrep 'git-svn-id: $url/mirror/foobar/trunk@3 $uuid' && - git cat-file commit refs/remotes/tags/blah-1.0 | \ - fgrep 'git-svn-id: $url/mirror/foobar/tags/blah-1.0@5 $uuid' - git cat-file commit refs/remotes/silly | \ - fgrep 'git-svn-id: $url/mirror/foobar/branches/silly@4 $uuid' - " - -test_expect_success 're-wrote author e-mail domain UUID' " - test \`git log --pretty=fuller trunk | \ - grep '<.*@.*>' | fgrep '@$uuid>' | wc -l\` -eq 4 && - test \`git log --pretty=fuller remotes/silly | \ - grep '<.*@.*>' | fgrep '@$uuid>' | wc -l\` -eq 6 && - test \`git log --pretty=fuller remotes/tags/blah-1.0 | \ - grep '<.*@.*>' | fgrep '@$uuid>' | wc -l\` -eq 6 - " - -test_debug 'gitk --all &' - -test_done diff --git a/t/t9110-git-svn-use-svm-props.sh b/t/t9110-git-svn-use-svm-props.sh new file mode 100755 index 0000000000..9db0d8fd8d --- /dev/null +++ b/t/t9110-git-svn-use-svm-props.sh @@ -0,0 +1,51 @@ +#!/bin/sh +# +# Copyright (c) 2007 Eric Wong +# + +test_description='git-svn useSvmProps test' + +. ./lib-git-svn.sh + +test_expect_success 'load svm repo' " + svnadmin load -q $rawsvnrepo < ../t9110/svm.dump && + git-svn init -R arr -i bar $svnrepo/mirror/arr && + git-svn init -R argh -i dir $svnrepo/mirror/argh && + git-svn init -R argh -i e $svnrepo/mirror/argh/a/b/c/d/e && + git-config svn.useSvmProps true && + git-svn fetch --all + " + +uuid=161ce429-a9dd-4828-af4a-52023f968c89 + +bar_url=http://mayonaise/svnrepo/bar +test_expect_success 'verify metadata for /bar' " + git-cat-file commit refs/remotes/bar | \ + grep '^git-svn-id: $bar_url@12 $uuid$' && + git-cat-file commit refs/remotes/bar~1 | \ + grep '^git-svn-id: $bar_url@11 $uuid$' && + git-cat-file commit refs/remotes/bar~2 | \ + grep '^git-svn-id: $bar_url@10 $uuid$' && + git-cat-file commit refs/remotes/bar~3 | \ + grep '^git-svn-id: $bar_url@9 $uuid$' && + git-cat-file commit refs/remotes/bar~4 | \ + grep '^git-svn-id: $bar_url@6 $uuid$' && + git-cat-file commit refs/remotes/bar~5 | \ + grep '^git-svn-id: $bar_url@1 $uuid$' + " + +e_url=http://mayonaise/svnrepo/dir/a/b/c/d/e +test_expect_success 'verify metadata for /dir/a/b/c/d/e' " + git-cat-file commit refs/remotes/e | \ + grep '^git-svn-id: $e_url@1 $uuid$' + " + +dir_url=http://mayonaise/svnrepo/dir +test_expect_success 'verify metadata for /dir' " + git-cat-file commit refs/remotes/dir | \ + grep '^git-svn-id: $dir_url@2 $uuid$' && + git-cat-file commit refs/remotes/dir~1 | \ + grep '^git-svn-id: $dir_url@1 $uuid$' + " + +test_done diff --git a/t/t9110/svm.dump b/t/t9110/svm.dump new file mode 100644 index 0000000000..cc799c238d --- /dev/null +++ b/t/t9110/svm.dump @@ -0,0 +1,511 @@ +SVN-fs-dump-format-version: 2 + +UUID: de5973c6-545d-41da-aded-c265f9039e74 + +Revision-number: 0 +Prop-content-length: 56 +Content-length: 56 + +K 8 +svn:date +V 27 +2007-02-17T06:54:59.793104Z +PROPS-END + +Revision-number: 1 +Prop-content-length: 200 +Content-length: 200 + +K 7 +svn:log +V 40 +SVM: initializing mirror for /mirror/arr +K 10 +svn:author +V 3 +svm +K 11 +svm:headrev +V 39 +161ce429-a9dd-4828-af4a-52023f968c89:0 + +K 8 +svn:date +V 27 +2007-02-17T06:55:00.121647Z +PROPS-END + +Node-path: +Node-kind: dir +Node-action: change +Prop-content-length: 44 +Content-length: 44 + +K 10 +svm:mirror +V 12 +/mirror/arr + +PROPS-END + + +Node-path: mirror +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: mirror/arr +Node-kind: dir +Node-action: add +Prop-content-length: 116 +Content-length: 116 + +K 10 +svm:source +V 29 +http://mayonaise/svnrepo!/bar +K 8 +svm:uuid +V 36 +161ce429-a9dd-4828-af4a-52023f968c89 +PROPS-END + + +Revision-number: 2 +Prop-content-length: 182 +Content-length: 182 + +K 7 +svn:log +V 18 +import for git-svn +K 10 +svn:author +V 7 +svnsync +K 11 +svm:headrev +V 39 +161ce429-a9dd-4828-af4a-52023f968c89:1 + +K 8 +svn:date +V 27 +2007-02-17T05:10:52.108847Z +PROPS-END + +Node-path: mirror/arr +Node-kind: dir +Node-action: change +Prop-content-length: 116 +Content-length: 116 + +K 10 +svm:source +V 29 +http://mayonaise/svnrepo!/bar +K 8 +svm:uuid +V 36 +161ce429-a9dd-4828-af4a-52023f968c89 +PROPS-END + + +Node-path: mirror/arr/zzz +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 4 +Text-content-md5: 33b02bc15ce9557d2dd8484d58f95ac4 +Content-length: 14 + +PROPS-END +zzz + + +Revision-number: 3 +Prop-content-length: 230 +Content-length: 230 + +K 7 +svn:log +V 66 +new symlink is added to a file that was also just made executable + +K 10 +svn:author +V 7 +svnsync +K 11 +svm:headrev +V 39 +161ce429-a9dd-4828-af4a-52023f968c89:6 + +K 8 +svn:date +V 27 +2007-02-17T05:11:01.686891Z +PROPS-END + +Node-path: mirror/arr/zzz +Node-kind: file +Node-action: change +Prop-content-length: 36 +Text-content-length: 4 +Text-content-md5: 33b02bc15ce9557d2dd8484d58f95ac4 +Content-length: 40 + +K 14 +svn:executable +V 1 +* +PROPS-END +zzz + + +Revision-number: 4 +Prop-content-length: 192 +Content-length: 192 + +K 7 +svn:log +V 28 +/bar/d should be in the log + +K 10 +svn:author +V 7 +svnsync +K 11 +svm:headrev +V 39 +161ce429-a9dd-4828-af4a-52023f968c89:9 + +K 8 +svn:date +V 27 +2007-02-17T05:11:07.686552Z +PROPS-END + +Node-path: mirror/arr/d +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 4 +Text-content-md5: 0bee89b07a248e27c83fc3d5951213c1 +Content-length: 14 + +PROPS-END +abc + + +Revision-number: 5 +Prop-content-length: 185 +Content-length: 185 + +K 7 +svn:log +V 20 +add a new directory + +K 10 +svn:author +V 7 +svnsync +K 11 +svm:headrev +V 40 +161ce429-a9dd-4828-af4a-52023f968c89:10 + +K 8 +svn:date +V 27 +2007-02-17T05:11:08.405953Z +PROPS-END + +Node-path: mirror/arr/newdir +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: mirror/arr/newdir/dir +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 4 +Text-content-md5: 9cd599a3523898e6a12e13ec787da50a +Content-length: 14 + +PROPS-END +new + + +Revision-number: 6 +Prop-content-length: 196 +Content-length: 196 + +K 7 +svn:log +V 31 +modify a file in new directory + +K 10 +svn:author +V 7 +svnsync +K 11 +svm:headrev +V 40 +161ce429-a9dd-4828-af4a-52023f968c89:11 + +K 8 +svn:date +V 27 +2007-02-17T05:11:09.126645Z +PROPS-END + +Node-path: mirror/arr/newdir/dir +Node-kind: file +Node-action: change +Text-content-length: 8 +Text-content-md5: a950e20332358e523a5e9d571e47fa64 +Content-length: 8 + +new +foo + + +Revision-number: 7 +Prop-content-length: 179 +Content-length: 179 + +K 7 +svn:log +V 14 +update /bar/d + +K 10 +svn:author +V 7 +svnsync +K 11 +svm:headrev +V 40 +161ce429-a9dd-4828-af4a-52023f968c89:12 + +K 8 +svn:date +V 27 +2007-02-17T05:11:09.846221Z +PROPS-END + +Node-path: mirror/arr/d +Node-kind: file +Node-action: change +Text-content-length: 4 +Text-content-md5: 7abb78de7f2756ca8b511cbc879fd5e7 +Content-length: 4 + +cba + + +Revision-number: 8 +Prop-content-length: 201 +Content-length: 201 + +K 7 +svn:log +V 41 +SVM: initializing mirror for /mirror/argh +K 10 +svn:author +V 3 +svm +K 11 +svm:headrev +V 39 +161ce429-a9dd-4828-af4a-52023f968c89:0 + +K 8 +svn:date +V 27 +2007-02-17T06:56:03.703677Z +PROPS-END + +Node-path: +Node-kind: dir +Node-action: change +Prop-content-length: 57 +Content-length: 57 + +K 10 +svm:mirror +V 25 +/mirror/argh +/mirror/arr + +PROPS-END + + +Node-path: mirror/argh +Node-kind: dir +Node-action: add +Prop-content-length: 116 +Content-length: 116 + +K 10 +svm:source +V 29 +http://mayonaise/svnrepo!/dir +K 8 +svm:uuid +V 36 +161ce429-a9dd-4828-af4a-52023f968c89 +PROPS-END + + +Revision-number: 9 +Prop-content-length: 182 +Content-length: 182 + +K 7 +svn:log +V 18 +import for git-svn +K 10 +svn:author +V 7 +svnsync +K 11 +svm:headrev +V 39 +161ce429-a9dd-4828-af4a-52023f968c89:1 + +K 8 +svn:date +V 27 +2007-02-17T05:10:52.108847Z +PROPS-END + +Node-path: mirror/argh +Node-kind: dir +Node-action: change +Prop-content-length: 116 +Content-length: 116 + +K 10 +svm:source +V 29 +http://mayonaise/svnrepo!/dir +K 8 +svm:uuid +V 36 +161ce429-a9dd-4828-af4a-52023f968c89 +PROPS-END + + +Node-path: mirror/argh/a +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: mirror/argh/a/b +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: mirror/argh/a/b/c +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: mirror/argh/a/b/c/d +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: mirror/argh/a/b/c/d/e +Node-kind: dir +Node-action: add +Prop-content-length: 10 +Content-length: 10 + +PROPS-END + + +Node-path: mirror/argh/a/b/c/d/e/file +Node-kind: file +Node-action: add +Prop-content-length: 10 +Text-content-length: 9 +Text-content-md5: 3fd46fe46fcdcf062c802ca60dc826d5 +Content-length: 19 + +PROPS-END +deep dir + + +Revision-number: 10 +Prop-content-length: 197 +Content-length: 197 + +K 7 +svn:log +V 33 +try a deep --rmdir with a commit + +K 10 +svn:author +V 7 +svnsync +K 11 +svm:headrev +V 39 +161ce429-a9dd-4828-af4a-52023f968c89:2 + +K 8 +svn:date +V 27 +2007-02-17T05:10:54.847015Z +PROPS-END + +Node-path: mirror/argh/file +Node-kind: file +Node-action: add +Node-copyfrom-rev: 9 +Node-copyfrom-path: mirror/argh/a/b/c/d/e/file +Text-content-length: 9 +Text-content-md5: 3fd46fe46fcdcf062c802ca60dc826d5 +Content-length: 9 + +deep dir + + +Node-path: mirror/argh/a +Node-action: delete + +