@matheusbsbs / matheus-bagliano / commits / 570d35c26d
Fork 0

git-svn: Allow deep branch names by supporting multi-globs

Some repositories use a deep branching strategy, such as: branches/1.0/1.0.rc1 branches/1.0/1.0.rc2 branches/1.0/1.0.rtm branches/1.0/1.0.gold Only allowing a single glob stiffles this. This change allows for a single glob 'set' to accept this deep branching strategy. The ref glob depth must match the branch glob depth. When using the -b or -t options for init or clone, this is automatically done. For example, using the above branches: svn-remote.svn.branches = branches/*/*:refs/remote/*/* gives the following branch names: 1.0/1.0.rc1 1.0/1.0.rc2 1.0/1.0.rtm 1.0/1.0.gold [ew: * removed unrelated line-wrapping changes * fixed line-wrapping in a few more places * removed trailing whitespace * fixed bashism in test * removed unnecessary httpd startup in test * changed copyright on tests to 2008 Marcus Griep * added executable permissions to new tests ] Signed-off-by: Marcus Griep <marcus@griep.us> Acked-by: Eric Wong <normalperson@yhbt.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Marcus Griep committed Aug 8, 2008 at 01:41 UTC 570d35c26dfbc40757da6032cdc96afb58cc0037
4 files changed +246 -20
git-svn.perl
+44 -16
@@ -987,8 +987,10 @@ sub complete_url_ls_init {
987 if (length $pfx && $pfx !~ m#/$#) {
988 die "--prefix='$pfx' must have a trailing slash '/'\n";
989 }
990 - command_noisy('config', "svn-remote.$gs->{repo_id}.$n",
991 - "$remote_path:refs/remotes/$pfx*");
990 + command_noisy('config',
991 + "svn-remote.$gs->{repo_id}.$n",
992 + "$remote_path:refs/remotes/$pfx*" .
993 + ('/*' x (($remote_path =~ tr/*/*/) - 1)) );
994 }
995
996 sub verify_ref {
@@ -4124,16 +4126,38 @@ sub gs_fetch_loop_common {
4126 Git::SVN::gc();
4127 }
4128
4129 +sub get_dir_globbed {
4130 + my ($self, $left, $depth, $r) = @_;
4131 +
4132 + my @x = eval { $self->get_dir($left, $r) };
4133 + return unless scalar @x == 3;
4134 + my $dirents = $x[0];
4135 + my @finalents;
4136 + foreach my $de (keys %$dirents) {
4137 + next if $dirents->{$de}->{kind} != $SVN::Node::dir;
4138 + if ($depth > 1) {
4139 + my @args = ("$left/$de", $depth - 1, $r);
4140 + foreach my $dir ($self->get_dir_globbed(@args)) {
4141 + push @finalents, "$de/$dir";
4142 + }
4143 + } else {
4144 + push @finalents, $de;
4145 + }
4146 + }
4147 + @finalents;
4148 +}
4149 +
4150 sub match_globs {
4151 my ($self, $exists, $paths, $globs, $r) = @_;
4152
4153 sub get_dir_check {
4154 my ($self, $exists, $g, $r) = @_;
4132 - my @x = eval { $self->get_dir($g->{path}->{left}, $r) };
4133 - return unless scalar @x == 3;
4134 - my $dirents = $x[0];
4135 - foreach my $de (keys %$dirents) {
4136 - next if $dirents->{$de}->{kind} != $SVN::Node::dir;
4155 +
4156 + my @dirs = $self->get_dir_globbed($g->{path}->{left},
4157 + $g->{path}->{depth},
4158 + $r);
4159 +
4160 + foreach my $de (@dirs) {
4161 my $p = $g->{path}->full_path($de);
4162 next if $exists->{$p};
4163 next if (length $g->{path}->{right} &&
@@ -4915,16 +4939,20 @@ sub new {
4939 my ($class, $glob) = @_;
4940 my $re = $glob;
4941 $re =~ s!/+$!!g; # no need for trailing slashes
4918 - my $nr = $re =~ tr/*/*/;
4919 - if ($nr > 1) {
4920 - die "Only one '*' wildcard expansion ",
4921 - "is supported (got $nr): '$glob'\n";
4922 - } elsif ($nr == 0) {
4942 + $re =~ m!^([^*]*)(\*(?:/\*)*)([^*]*)$!;
4943 + my $temp = $re;
4944 + my ($left, $right) = ($1, $3);
4945 + $re = $2;
4946 + my $depth = $re =~ tr/*/*/;
4947 + if ($depth != $temp =~ tr/*/*/) {
4948 + die "Only one set of wildcard directories " .
4949 + "(e.g. '*' or '*/*/*') is supported: '$glob'\n";
4950 + }
4951 + if ($depth == 0) {
4952 die "One '*' is needed for glob: '$glob'\n";
4953 }
4925 - $re =~ s!^(.*)\*(.*)$!\(\[^/\]+\)!g;
4926 - my ($left, $right) = ($1, $2);
4927 - $re = quotemeta($left) . $re . quotemeta($right);
4954 + $re =~ s!\*!\[^/\]*!g;
4955 + $re = quotemeta($left) . "($re)" . quotemeta($right);
4956 if (length $left && !($left =~ s!/+$!!g)) {
4957 die "Missing trailing '/' on left side of: '$glob' ($left)\n";
4958 }
@@ -4933,7 +4961,7 @@ sub new {
4961 }
4962 my $left_re = qr/^\/\Q$left\E(\/|$)/;
4963 bless { left => $left, right => $right, left_regex => $left_re,
4936 - regex => qr/$re/, glob => $glob }, $class;
4964 + regex => qr/$re/, glob => $glob, depth => $depth }, $class;
4965 }
4966
4967 sub full_path {
t/t9108-git-svn-glob.sh
+5 -4
@@ -53,7 +53,8 @@ test_expect_success 'test refspec globbing' '
53 test "`git rev-parse refs/remotes/tags/end~1`" = \
54 "`git rev-parse refs/remotes/branches/start`" &&
55 test "`git rev-parse refs/remotes/branches/start~2`" = \
56 - "`git rev-parse refs/remotes/trunk`"
56 + "`git rev-parse refs/remotes/trunk`" &&
57 + test_must_fail git rev-parse refs/remotes/tags/end@3
58 '
59
60 echo try to try > expect.two
@@ -85,8 +86,8 @@ test_expect_success 'test left-hand-side only globbing' '
86 test_cmp expect.two output.two
87 '
88
88 -echo "Only one '*' wildcard expansion is supported (got 2): 'branches/*/*'" \
89 - > expect.three
89 +echo "Only one set of wildcard directories" \
90 + "(e.g. '*' or '*/*/*') is supported: 'branches/*/t/*'" > expect.three
91 echo "" >> expect.three
92
93 test_expect_success 'test disallow multi-globs' '
@@ -94,7 +95,7 @@ test_expect_success 'test disallow multi-globs' '
95 git config --add svn-remote.three.fetch \
96 trunk:refs/remotes/three/trunk &&
97 git config --add svn-remote.three.branches \
97 - "branches/*/*:refs/remotes/three/branches/*" &&
98 + "branches/*/t/*:refs/remotes/three/branches/*" &&
99 git config --add svn-remote.three.tags \
100 "tags/*/*:refs/remotes/three/tags/*" &&
101 (
t/t9108-git-svn-multi-glob.sh new
+160
@@ -0,0 +1,160 @@
1 +#!/bin/sh
2 +# Copyright (c) 2007 Eric Wong
3 +test_description='git-svn globbing refspecs'
4 +. ./lib-git-svn.sh
5 +
6 +cat > expect.end <<EOF
7 +the end
8 +hi
9 +start a new branch
10 +initial
11 +EOF
12 +
13 +test_expect_success 'test refspec globbing' '
14 + mkdir -p trunk/src/a trunk/src/b trunk/doc &&
15 + echo "hello world" > trunk/src/a/readme &&
16 + echo "goodbye world" > trunk/src/b/readme &&
17 + svn import -m "initial" trunk "$svnrepo"/trunk &&
18 + svn co "$svnrepo" tmp &&
19 + (
20 + cd tmp &&
21 + mkdir branches branches/v1 tags &&
22 + svn add branches tags &&
23 + svn cp trunk branches/v1/start &&
24 + svn commit -m "start a new branch" &&
25 + svn up &&
26 + echo "hi" >> branches/v1/start/src/b/readme &&
27 + poke branches/v1/start/src/b/readme &&
28 + echo "hey" >> branches/v1/start/src/a/readme &&
29 + poke branches/v1/start/src/a/readme &&
30 + svn commit -m "hi" &&
31 + svn up &&
32 + svn cp branches/v1/start tags/end &&
33 + echo "bye" >> tags/end/src/b/readme &&
34 + poke tags/end/src/b/readme &&
35 + echo "aye" >> tags/end/src/a/readme &&
36 + poke tags/end/src/a/readme &&
37 + svn commit -m "the end" &&
38 + echo "byebye" >> tags/end/src/b/readme &&
39 + poke tags/end/src/b/readme &&
40 + svn commit -m "nothing to see here"
41 + ) &&
42 + git config --add svn-remote.svn.url "$svnrepo" &&
43 + git config --add svn-remote.svn.fetch \
44 + "trunk/src/a:refs/remotes/trunk" &&
45 + git config --add svn-remote.svn.branches \
46 + "branches/*/*/src/a:refs/remotes/branches/*/*" &&
47 + git config --add svn-remote.svn.tags\
48 + "tags/*/src/a:refs/remotes/tags/*" &&
49 + git-svn multi-fetch &&
50 + git log --pretty=oneline refs/remotes/tags/end | \
51 + sed -e "s/^.\{41\}//" > output.end &&
52 + test_cmp expect.end output.end &&
53 + test "`git rev-parse refs/remotes/tags/end~1`" = \
54 + "`git rev-parse refs/remotes/branches/v1/start`" &&
55 + test "`git rev-parse refs/remotes/branches/v1/start~2`" = \
56 + "`git rev-parse refs/remotes/trunk`" &&
57 + test_must_fail git rev-parse refs/remotes/tags/end@3
58 + '
59 +
60 +echo try to try > expect.two
61 +echo nothing to see here >> expect.two
62 +cat expect.end >> expect.two
63 +
64 +test_expect_success 'test left-hand-side only globbing' '
65 + git config --add svn-remote.two.url "$svnrepo" &&
66 + git config --add svn-remote.two.fetch trunk:refs/remotes/two/trunk &&
67 + git config --add svn-remote.two.branches \
68 + "branches/*/*:refs/remotes/two/branches/*/*" &&
69 + git config --add svn-remote.two.tags \
70 + "tags/*:refs/remotes/two/tags/*" &&
71 + (
72 + cd tmp &&
73 + echo "try try" >> tags/end/src/b/readme &&
74 + poke tags/end/src/b/readme &&
75 + svn commit -m "try to try"
76 + ) &&
77 + git-svn fetch two &&
78 + test `git rev-list refs/remotes/two/tags/end | wc -l` -eq 6 &&
79 + test `git rev-list refs/remotes/two/branches/v1/start | wc -l` -eq 3 &&
80 + test `git rev-parse refs/remotes/two/branches/v1/start~2` = \
81 + `git rev-parse refs/remotes/two/trunk` &&
82 + test `git rev-parse refs/remotes/two/tags/end~3` = \
83 + `git rev-parse refs/remotes/two/branches/v1/start` &&
84 + git log --pretty=oneline refs/remotes/two/tags/end | \
85 + sed -e "s/^.\{41\}//" > output.two &&
86 + test_cmp expect.two output.two
87 + '
88 +cat > expect.four <<EOF
89 +adios
90 +adding more
91 +Changed 2 in v2/start
92 +Another versioned branch
93 +initial
94 +EOF
95 +
96 +test_expect_success 'test another branch' '
97 + (
98 + cd tmp &&
99 + mkdir branches/v2 &&
100 + svn add branches/v2 &&
101 + svn cp trunk branches/v2/start &&
102 + svn commit -m "Another versioned branch" &&
103 + svn up &&
104 + echo "hello" >> branches/v2/start/src/b/readme &&
105 + poke branches/v2/start/src/b/readme &&
106 + echo "howdy" >> branches/v2/start/src/a/readme &&
107 + poke branches/v2/start/src/a/readme &&
108 + svn commit -m "Changed 2 in v2/start" &&
109 + svn up &&
110 + svn cp branches/v2/start tags/next &&
111 + echo "bye" >> tags/next/src/b/readme &&
112 + poke tags/next/src/b/readme &&
113 + echo "aye" >> tags/next/src/a/readme &&
114 + poke tags/next/src/a/readme &&
115 + svn commit -m "adding more" &&
116 + echo "byebye" >> tags/next/src/b/readme &&
117 + poke tags/next/src/b/readme &&
118 + svn commit -m "adios"
119 + ) &&
120 + git config --add svn-remote.four.url "$svnrepo" &&
121 + git config --add svn-remote.four.fetch trunk:refs/remotes/four/trunk &&
122 + git config --add svn-remote.four.branches \
123 + "branches/*/*:refs/remotes/four/branches/*/*" &&
124 + git config --add svn-remote.four.tags \
125 + "tags/*:refs/remotes/four/tags/*" &&
126 + git-svn fetch four &&
127 + test `git rev-list refs/remotes/four/tags/next | wc -l` -eq 5 &&
128 + test `git rev-list refs/remotes/four/branches/v2/start | wc -l` -eq 3 &&
129 + test `git rev-parse refs/remotes/four/branches/v2/start~2` = \
130 + `git rev-parse refs/remotes/four/trunk` &&
131 + test `git rev-parse refs/remotes/four/tags/next~2` = \
132 + `git rev-parse refs/remotes/four/branches/v2/start` &&
133 + git log --pretty=oneline refs/remotes/four/tags/next | \
134 + sed -e "s/^.\{41\}//" > output.four &&
135 + test_cmp expect.four output.four
136 + '
137 +
138 +echo "Only one set of wildcard directories" \
139 + "(e.g. '*' or '*/*/*') is supported: 'branches/*/t/*'" > expect.three
140 +echo "" >> expect.three
141 +
142 +test_expect_success 'test disallow multiple globs' '
143 + git config --add svn-remote.three.url "$svnrepo" &&
144 + git config --add svn-remote.three.fetch \
145 + trunk:refs/remotes/three/trunk &&
146 + git config --add svn-remote.three.branches \
147 + "branches/*/t/*:refs/remotes/three/branches/*/*" &&
148 + git config --add svn-remote.three.tags \
149 + "tags/*:refs/remotes/three/tags/*" &&
150 + (
151 + cd tmp &&
152 + echo "try try" >> tags/end/src/b/readme &&
153 + poke tags/end/src/b/readme &&
154 + svn commit -m "try to try"
155 + ) &&
156 + test_must_fail git-svn fetch three 2> stderr.three &&
157 + test_cmp expect.three stderr.three
158 + '
159 +
160 +test_done
t/t9125-git-svn-multi-glob-branch-names.sh new
+37
@@ -0,0 +1,37 @@
1 +#!/bin/sh
2 +# Copyright (c) 2008 Marcus Griep
3 +
4 +test_description='git-svn multi-glob branch names'
5 +. ./lib-git-svn.sh
6 +
7 +test_expect_success 'setup svnrepo' '
8 + mkdir project project/trunk project/branches \
9 + project/branches/v14.1 project/tags &&
10 + echo foo > project/trunk/foo &&
11 + svn import -m "$test_description" project "$svnrepo/project" &&
12 + rm -rf project &&
13 + svn cp -m "fun" "$svnrepo/project/trunk" \
14 + "$svnrepo/project/branches/v14.1/beta" &&
15 + svn cp -m "more fun!" "$svnrepo/project/branches/v14.1/beta" \
16 + "$svnrepo/project/branches/v14.1/gold"
17 + '
18 +
19 +test_expect_success 'test clone with multi-glob in branch names' '
20 + git svn clone -T trunk -b branches/*/* -t tags \
21 + "$svnrepo/project" project &&
22 + cd project &&
23 + git rev-parse "refs/remotes/v14.1/beta" &&
24 + git rev-parse "refs/remotes/v14.1/gold" &&
25 + cd ..
26 + '
27 +
28 +test_expect_success 'test dcommit to multi-globbed branch' "
29 + cd project &&
30 + git reset --hard 'refs/remotes/v14.1/gold' &&
31 + echo hello >> foo &&
32 + git commit -m 'hello' -- foo &&
33 + git svn dcommit &&
34 + cd ..
35 + "
36 +
37 +test_done