changeset 1029:513f2b607b06

layouts: pull out logic for splitting svn paths into branch and local parts There is a single method on svnmeta that is responsible for both splitting a subversion path into a local component, which specifies a path relative to the mercurial root, and a branch component, which specifies the path to the root of a subversion branch, and translating that branch path into a mercurial branch name. This pulls the logic for doing the path splitting into a layout object method that *only* splits the path, and changes the svnmeta to call the layout objects's localname method to do the subversion branch path to mercurial branch name translation.
author David Schleimer <dschleimer@fb.com>
date Wed, 05 Jun 2013 11:06:34 -0700
parents c4b25a903ad3
children 6fa55b6fa3f2
files hgsubversion/layouts/base.py hgsubversion/layouts/single.py hgsubversion/layouts/standard.py hgsubversion/svnmeta.py
diffstat 4 files changed, 60 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/layouts/base.py
+++ b/hgsubversion/layouts/base.py
@@ -63,3 +63,18 @@ class BaseLayout(object):
 
         """
         self.__unimplemented('get_path_tag')
+
+    def split_remote_name(self, path, known_branches):
+        """Split the path into a branch component and a local component.
+
+        path should be relative to our repo url
+
+        returns (branch_path, local_path)
+
+        branch_path should be suitable to pass into localname,
+        i.e. branch_path should NOT have a leading or trailing /
+
+        local_path should be relative to the root of the Mercurial working dir
+
+        """
+        self.unimplemented('split_branch_and_local_path')
--- a/hgsubversion/layouts/single.py
+++ b/hgsubversion/layouts/single.py
@@ -19,3 +19,6 @@ class SingleLayout(base.BaseLayout):
 
     def get_path_tag(self, path, taglocations):
         return None
+
+    def split_remote_name(self, path, known_branches):
+        return '', path
--- a/hgsubversion/layouts/standard.py
+++ b/hgsubversion/layouts/standard.py
@@ -64,3 +64,36 @@ class StandardLayout(base.BaseLayout):
                     if tag:
                         return tag
         return None
+
+    def split_remote_name(self, path, known_branches):
+
+        # this odd evolution is how we deal with people doing things like
+        # creating brances (note the typo), committing to a branch under it,
+        # and then moving it to branches
+
+        # we need to find the ../foo branch names, if they exist, before
+        # trying to create a normally-named branch
+
+        components = path.split('/')
+        candidate = ''
+        while self.localname(candidate) not in known_branches and components:
+            if not candidate:
+                candidate = components.pop(0)
+            else:
+                candidate += '/'
+                candidate += components.pop(0)
+        if self.localname(candidate) in known_branches:
+            return candidate, '/'.join(components)
+
+        if path == 'trunk' or path.startswith('trunk/'):
+            branch_path = 'trunk'
+            local_path = '/'.join(path.split('/')[1:])
+        elif path.startswith('branches/'):
+            components = path.split('/')
+            branch_path = '/'.join(components[:2])
+            local_path = '/'.join(components[2:])
+        else:
+            components = path.split('/')
+            branch_path = '/'.join(components[:-1])
+            local_path = components[-1]
+        return branch_path, local_path
--- a/hgsubversion/svnmeta.py
+++ b/hgsubversion/svnmeta.py
@@ -274,8 +274,6 @@ class SVNMeta(object):
         relative to our subdirectory.
         """
         path = self.normalize(path)
-        if self.layout == 'single':
-            return (path, None, '')
         tag = self.get_path_tag(path)
         if tag:
             # consider the new tags when dispatching entries
@@ -294,31 +292,17 @@ class SVNMeta(object):
                 svrpath = path[:-(len(brpath)+1)]
             ln = self.localname(svrpath)
             return brpath, ln, svrpath
-        test = ''
-        path_comps = path.split('/')
-        while self.localname(test) not in self.branches and len(path_comps):
-            if not test:
-                test = path_comps.pop(0)
-            else:
-                test += '/%s' % path_comps.pop(0)
-        if self.localname(test) in self.branches:
-            return path[len(test)+1:], self.localname(test), test
-        if existing:
+
+        branch_path, local_path = self.layoutobj.split_remote_name(path,
+                                                                   self.branches)
+        branch_name = self.layoutobj.localname(branch_path)
+
+        if branch_name in self.branches:
+            return local_path, branch_name, branch_path
+        elif existing or (branch_name and branch_name.startswith('../')):
             return None, None, None
-        if path == 'trunk' or path.startswith('trunk/'):
-            path = '/'.join(path.split('/')[1:])
-            test = 'trunk'
-        elif path.startswith('branches/'):
-            elts = path.split('/')
-            test = '/'.join(elts[:2])
-            path = '/'.join(elts[2:])
         else:
-            path = test.split('/')[-1]
-            test = '/'.join(test.split('/')[:-1])
-        ln = self.localname(test)
-        if ln and ln.startswith('../'):
-            return None, None, None
-        return path, ln, test
+            return local_path, branch_name, branch_path
 
     def _determine_parent_branch(self, p, src_path, src_rev, revnum):
         if src_path is not None: