changeset 536:460eb781d840

Handle subdirectory tags in stupid mode (issue119) Current solution add an alternate behaviour to svnmeta.split_branch_path(), which unfortunately looks like the expected behaviour. Other calls will be changed to make it the default behaviour.
author Patrick Mezard <pmezard@gmail.com>
date Sat, 30 Jan 2010 10:01:03 +0100
parents 715d2e3e153b
children 3c8b86949072
files hgsubversion/stupid.py hgsubversion/svnmeta.py tests/test_tags.py
diffstat 3 files changed, 40 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/stupid.py
+++ b/hgsubversion/stupid.py
@@ -103,25 +103,19 @@ def diff_branchrev(ui, svn, meta, branch
     callable to retrieve individual file information. Raise BadPatchApply upon
     error.
     """
-    def make_diff_path(branch):
-        if meta.layout == 'single':
-            return ''
-        if branch == 'trunk' or branch is None:
-            return 'trunk'
-        elif branch.startswith('../'):
-            return branch[3:]
-        return 'branches/%s' % branch
-    parent_rev, br_p = meta.get_parent_svn_branch_and_rev(r.revnum, branch)
     try:
-        if br_p == branch:
+        prev, pbranch, ppath = meta.get_source_rev(ctx=parentctx)
+    except KeyError:
+        prev, pbranch, ppath = None, None, None
+    try:
+        if prev is None or pbranch == branch:
             # letting patch handle binaries sounded
             # cool, but it breaks patch in sad ways
             d = svn.get_unified_diff(branchpath, r.revnum, deleted=False,
                                      ignore_type=False)
         else:
             d = svn.get_unified_diff(branchpath, r.revnum,
-                                     other_path=make_diff_path(br_p),
-                                     other_rev=parent_rev,
+                                     other_path=ppath, other_rev=prev,
                                      deleted=True, ignore_type=True)
             if d:
                 raise BadPatchApply('branch creation with mods')
@@ -473,7 +467,7 @@ def branches_in_paths(meta, tbdelta, pat
     branches = {}
     paths_need_discovery = []
     for p in paths:
-        relpath, branch, branchpath = meta.split_branch_path(p)
+        relpath, branch, branchpath = meta.split_branch_path(p, exacttag=True)
         if relpath is not None:
             branches[branch] = branchpath
         elif paths[p].action == 'D' and not meta.get_path_tag(p):
@@ -572,14 +566,13 @@ def convert_rev(ui, meta, svn, r, tbdelt
     check_deleted_branches = set(tbdelta['branches'][1])
     for b in branches:
         parentctx = meta.repo[meta.get_parent_revision(r.revnum, b)]
-        if parentctx.branch() != (b or 'default'):
-            check_deleted_branches.add(b)
-
+        tag = meta.get_path_tag(meta.remotename(b))
         kind = svn.checkpath(branches[b], r.revnum)
         if kind != 'd':
-            # Branch does not exist at this revision. Get parent revision and
-            # remove everything.
-            deleted_branches[b] = parentctx.node()
+            if not tag:
+                # Branch does not exist at this revision. Get parent
+                # revision and remove everything.
+                deleted_branches[b] = parentctx.node()
             continue
 
         try:
@@ -615,6 +608,14 @@ def convert_rev(ui, meta, svn, r, tbdelt
         for f in excluded:
             files_touched.remove(f)
 
+        if b:
+            # Regular tag without modifications, it will be committed by
+            # svnmeta.committag(), we can skip the whole branch for now
+            if (tag and tag not in meta.tags and
+                b not in meta.branches
+                and b not in meta.repo.branchtags()):
+                continue
+
         if parentctx.node() == node.nullid and not files_touched:
             meta.repo.ui.debug('skipping commit since parent is null and no files touched.\n')
             continue
@@ -626,8 +627,6 @@ def convert_rev(ui, meta, svn, r, tbdelt
                 assert f[0] != '/'
 
         extra = meta.genextra(r.revnum, b)
-
-        tag = meta.get_path_tag(meta.remotename(b))
         if tag:
             if parentctx.node() == node.nullid:
                 continue
--- a/hgsubversion/svnmeta.py
+++ b/hgsubversion/svnmeta.py
@@ -247,7 +247,7 @@ class SVNMeta(object):
                         return tag
         return None
 
-    def split_branch_path(self, path, existing=True):
+    def split_branch_path(self, path, existing=True, exacttag=False):
         """Figure out which branch inside our repo this path represents, and
         also figure out which path inside that branch it is.
 
@@ -256,6 +256,11 @@ class SVNMeta(object):
         If existing=True, will return None, None, None if the file isn't on some known
         branch. If existing=False, then it will guess what the branch would be if it were
         known. Server-side branch path should be relative to our subdirectory.
+
+        If exacttag=True and path matches exactly a new or existing
+        tag, then return it as an empty relative path. Otherwise,
+        ignore the path and return (None, None, None). Only subpaths
+        of supplied tag path will be split.
         """
         path = self.normalize(path)
         if self.layout == 'single':
@@ -265,12 +270,20 @@ class SVNMeta(object):
             # consider the new tags when dispatching entries
             matched = []
             for tags in (self.tags, self.addedtags):
-                matched += [t for t in tags if tag.startswith(t + '/')]
+                if exacttag:
+                    matched += [t for t in tags
+                                if (tag == t or tag.startswith(t + '/'))]
+                else:
+                    matched += [t for t in tags if tag.startswith(t + '/')]
             if not matched:
                 return None, None, None
             matched.sort(key=len, reverse=True)
-            brpath = tag[len(matched[0])+1:]
-            svrpath = path[:-(len(brpath)+1)]
+            if tag == matched[0]:
+                brpath = ''
+                svrpath = path
+            else:
+                brpath = tag[len(matched[0])+1:]
+                svrpath = path[:-(len(brpath)+1)]
             ln = self.localname(svrpath)
             return brpath, ln, svrpath
         test = ''
--- a/tests/test_tags.py
+++ b/tests/test_tags.py
@@ -235,7 +235,7 @@ rename a tag
         diff = difflib.unified_diff(expected, output, 'expected', 'output')
         self.assert_(False, '\n' + '\n'.join(diff))
 
-    def test_tagging_into_tag(self, expected=None, stupid=False):
+    def test_tagging_into_tag(self, stupid=False):
         expected = """\
 node: hg=test@2:svn=branches/test@4
 First tag.
@@ -246,28 +246,10 @@ Weird tag.
   test-0.1: hg=test@1:svn=branches/test@3
   test-0.1/test: hg=test@1:svn=branches/test@3
 """
-        self._test_tags('renametagdir.svndump', expected)
+        self._test_tags('renametagdir.svndump', expected, stupid=stupid)
 
     def test_tagging_into_tag_stupid(self):
-        # This test exposed existing flaws with tag handling in stupid mode.
-        # They will be resolved in the future.
-        expected = """\
-node: hg=test@2:svn=branches/test@4
-First tag.
-  test-0.1: hg=test@1:svn=branches/test@3
-
-node: hg=test@4:svn=branches/test@4
-Weird tag.
-  test-0.1: hg=test@1:svn=branches/test@3
-  test-0.1: hg=test@3:svn=tags/test-0.1@5
-
-node: hg=test@5:svn=branches/test@5
-Weird tag.
-  test-0.1: hg=test@1:svn=branches/test@3
-  test-0.1: hg=test@3:svn=tags/test-0.1@5
-  test-0.1/test: hg=test@1:svn=branches/test@3
-"""
-        self._test_tags('renametagdir.svndump', expected, True)
+        self.test_tagging_into_tag(True)
     
 
 def suite():