# HG changeset patch # User David Schleimer # Date 1370455594 25200 # Node ID 513f2b607b061027113fc04081db806c907f2120 # Parent c4b25a903ad3f1afb52b3ed05bf5a2438ebe75a4 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. diff --git a/hgsubversion/layouts/base.py b/hgsubversion/layouts/base.py --- 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') diff --git a/hgsubversion/layouts/single.py b/hgsubversion/layouts/single.py --- 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 diff --git a/hgsubversion/layouts/standard.py b/hgsubversion/layouts/standard.py --- 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 diff --git a/hgsubversion/svnmeta.py b/hgsubversion/svnmeta.py --- 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: