Commits

Greg Ward  committed de0e6e0

svn: fix handling of multiproject repositories (with new test repo)

If repos_path looks like "proj1/branches/1.0" or "proj1/trunk",
there's still an obvious branch name there. Cannot assume that
repos_path starts with "trunk" or "branches".

  • Participants
  • Parent commits 5f2de63

Comments (0)

Files changed (6)

 ^configure$
 ^Makefile$
 ^stamp-h
-^tests/\w+-repo(\.tar)?$
+^tests/\w+-repo.*(\.tar)?$
 
 hgrepo = tests/hg-repo.tar
 gitrepo = tests/git-repo.tar
-svnrepo = tests/svn-repo.tar
+svnrepos = tests/svn-repo-1.tar tests/svn-repo-2.tar
 fossilrepo = tests/fossil-repo
 
 check-simple: vcprompt
 $(gitrepo): tests/setup-git
 	cd tests && ./setup-git
 
-check-svn: vcprompt $(svnrepo)
+check-svn: vcprompt $(svnrepos)
 	cd tests && ./test-svn
 
-$(svnrepo): tests/setup-svn
+$(svnrepos): tests/setup-svn
 	cd tests && ./setup-svn
 
 check-fossil: vcprompt $(fossilrepo)
 For example, I keep multiple versions in /usr/local/subversion-1.x, so
 I can test them like this:
 
-  rm -f tests/svn-repo.tar && make check-svn TOOLPATH=/usr/local/subversion-1.6/bin
-  rm -f tests/svn-repo.tar && make check-svn TOOLPATH=/usr/local/subversion-1.7/bin
+  rm -f tests/svn-repo*.tar && make check-svn TOOLPATH=/usr/local/subversion-1.6/bin
+  rm -f tests/svn-repo*.tar && make check-svn TOOLPATH=/usr/local/subversion-1.7/bin
 
 Actually *building* multiple versions of Subversion is harder than you
 would believe. (In fact, I've been unable to build anything older than
 }
 
 static char *
-get_branch_name(const char *repos_path)
+get_branch_name(char *repos_path)
 {
-    if (strcmp(repos_path, "trunk") == 0) {
-        return strdup(repos_path);
+    // if repos_path endswith "trunk"
+    //     return "trunk"
+    // else if repos_path endswith "branches/*"
+    //     return whatever matched "*"
+    // else
+    //     no idea
+
+    // if the final component is "trunk", that's where we are
+    char *slash = strrchr(repos_path, '/');
+    char *name = slash ? slash + 1 : repos_path;
+    if (strcmp(name, "trunk") == 0) {
+        debug("found svn trunk");
+        return strdup(name);
     }
-    else if (strncmp(repos_path, "trunk/", 6) == 0) {
-        return strndup(repos_path, 5);
-    }
-    else if (strcmp(repos_path, "branches") == 0 ||
-             strcmp(repos_path, "tags") == 0) {
-        // checking out /branches or /tags is legal but weird: there
-        // is certainly no single branch name for this working dir
-        debug("no svn branch due to peculiar repos_path: '%s'", repos_path);
+    if (slash == NULL) {
+        debug("no branch in svn repos_path '%s'", repos_path);
         return NULL;
     }
-    else if (strncmp(repos_path, "branches/", 9) == 0) {
-        char *slash2 = strchr(repos_path + 9, '/');
-        if (slash2 == NULL) {
-            return strdup(repos_path + 9);
-        }
-        else {
-            return strndup(repos_path + 9, slash2 - repos_path + 9);
-        }
+
+    // backup and see if the previous component is "branches", in which
+    // case 'name' points to the branch name
+    *slash = 0;
+    slash = strrchr(repos_path, '/');
+    char *prev = slash ? slash + 1 : repos_path;
+    if (strncmp(prev, "branches", 8) == 0) {
+        debug("found svn branch name: %s", name);
+        return strdup(name);
     }
-    else {
-        debug("no svn branch: unexpected repos_path '%s'", repos_path);
-        return NULL;
-    }
+    debug("could not find branch name in svn repos_path '%s'", repos_path);
+    return NULL;
 }
 
 
     sqlite3 *conn = NULL;
     sqlite3_stmt *res = NULL;
     const char *tail;
+    char * repos_path = NULL;
 
     retval = sqlite3_open(".svn/wc.db", &conn);
     if (retval != SQLITE_OK) {
         goto err;
     }
     sqlite3_step(res);
-    const unsigned char *repos_path = sqlite3_column_text(res, 0);
-    result->branch = get_branch_name((const char *)repos_path);
+    repos_path = strdup((const char *) sqlite3_column_text(res, 0));
+    result->branch = get_branch_name(repos_path);
 
     ok = 1;
 
         sqlite3_finalize(res);
     if (conn != NULL)
         sqlite3_close(conn);
+    if (repos_path != NULL)
+        free(repos_path);
     return ok;
 }
 #else

File tests/setup-svn

 
 # Setup the test svn repository that will be used by test-svn.
 #
-# Output is svn-repo.tar, which will be unpacked for each test run.
+# Output is svn-repo-1.tar, which will be unpacked for each test run.
 
 . ./common.sh
 
 set -ex
 cd `dirname $`
 dir=`pwd`
-rm -rf svn-repo svn-wc
+rm -rf svn-repo-1 svn-wc
 
-svnadmin create svn-repo
-url=file://$dir/svn-repo
+# repo-1 is a simple one-project repo: the only top-level dirs
+# are trunk/, branches/, and tags/
+svnadmin create svn-repo-1
+url=file://$dir/svn-repo-1
 svn mkdir -m"setup" $url/trunk $url/tags $url/branches
 svn checkout $url/trunk svn-wc
 cd svn-wc
 svn switch $url/trunk
 
 cd ..
-tar -cf svn-repo.tar svn-repo
-rm -rf svn-repo svn-wc
+tar -cf svn-repo-1.tar svn-repo-1
+rm -rf svn-repo-1 svn-wc
+
+# repo-2 is a more complex multi-project repo: proj1 has
+# tags/branches/trunk, but junk1 and junk2 do not
+rm -rf svn-repo-2
+svnadmin create svn-repo-2
+url=file://$dir/svn-repo-2
+svn mkdir \
+  --parents \
+  -m"setup" \
+  $url/proj1/tags $url/proj1/branches $url/proj1/trunk \
+  $url/junk/junk1 $url/junk/junk2
+svn mkdir -m"make a branch" $url/proj1/branches/1.0
+tar -cf svn-repo-2.tar svn-repo-2
+rm -rf svn-repo-2

File tests/test-svn

 
 find_svnrepo()
 {
-    svnrepo="$testdir/svn-repo.tar"
-    if [ ! -f $svnrepo ]; then
-        echo "$svnrepo not found" >&2
+    if [ ! -f $testdir/svn-repo-1.tar ]; then
+        echo "svn-repo-1.tar not found" >&2
+        exit 1
+    fi
+    if [ ! -f $testdir/svn-repo-2.tar ]; then
+        echo "svn-repo-2.tar not found" >&2
         exit 1
     fi
 }
 
 pretest()
 {
-    checkout_path=$1
+    repobase=$1
+    checkout_path=$2
     [ -d $tmpdir ] || die "tmpdir ($tmpdir) does not exist"
     cd $tmpdir
-    rm -rf svn-repo svn-wc
+    svnrepo=$testdir/$repobase.tar
+    rm -rf $repobase svn-wc
     tar -xf $svnrepo
-    repourl=file://$tmpdir/svn-repo
+    repourl=file://$tmpdir/$repobase
     svn -q checkout $repourl/$checkout_path svn-wc
     cd svn-wc
 }
 posttest()
 {
     cd $tmpdir
-    rm -rf svn-repo svn-wc
+    rm -rf svn-repo-* svn-wc
 }
 
 # default prompt format in test repo
 test_basics()
 {
     echo "test_basics:"
-    pretest "trunk"
+    pretest "svn-repo-1" "trunk"
     assert_vcprompt "vc name" "svn" "%n"
     assert_vcprompt "branch name on trunk" "trunk" "%b"
     assert_vcprompt "rev num on trunk" "2" "%r"
 {
     # checkout the whole repo, ie. parent of trunk/, tags/, branches/
     echo "test_weird_checkout:"
-    pretest ""
+    pretest "svn-repo-1" ""
     assert_vcprompt "vc name" "svn" "%n"
     assert_vcprompt "no branch name (in project root)" "" "%b"
 
     posttest
 }
 
+test_multiproject_repo()
+{
+    echo "test_multiproject_repo"
+    pretest "svn-repo-2" "proj1/trunk"
+    assert_vcprompt "trunk in multiproject repo" "[svn,1,trunk]" "[%n,%r,%b]"
+
+    # argh, 'svn switch' doesn't work reliably (in 1.7 it requires
+    # --ignore-ancestry, and in 1.6 that option doesn't exist) -- so
+    # avoid it
+    cd ..
+    svn checkout $repourl/proj1/branches/1.0 wc2
+    cd wc2
+    assert_vcprompt "branch in multiproject repo" "[svn,2,1.0]" "[%n,%r,%b]"
+
+    posttest
+}
+
 find_vcprompt
 check_svn
 find_svnrepo
 
 test_basics
 test_weird_checkout
+test_multiproject_repo