git-svn: fix useSvmProps, hopefully for the last time

svm:mirror is not useful at all for us.  Parts of the old unit
test were broken and based on my misunderstanding of the
svm:mirror property.

When we read svm:source; make sure we correctly handle the '!'
in it: it is used to separate the path of the repository root
from the virtual path within the repository.  We don't need
to make that distinction, honestly!

We also ensure that subdirectories are also mirrored with the
correct URL if we're using useSvmProps.

We have a new test that uses dumped repo that was really
created using SVN::Mirror to avoid ambiguities and
mis-understandings about the svm: properties.

Note: trailing whitespace in the svm.dump file is unfortunately
a reality and required by SVN; so please ignore it when applying
this patch.

Also, ensure that the -R/--remote/--svn-remote flag is always
in effect if explicitly passed via the command-line.  This
allows us to track logically different mirrors sharing the
same URL (probably common with SVN::Mirror/SVK users).

Signed-off-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:
Eric Wong 2007-02-17 02:53:07 -08:00
Родитель 62e349d235
Коммит befc9adc0c
4 изменённых файлов: 619 добавлений и 140 удалений

Просмотреть файл

@ -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"

Просмотреть файл

@ -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

Просмотреть файл

@ -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

511
t/t9110/svm.dump Normal file
Просмотреть файл

@ -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