Mercurial > hgsubversion
diff hgsubversion/layouts/custom.py @ 1092:cd0d14e25757
layouts: add custom layout for those of us that need weird mappings
This adds a config-driven custom layout, targeted at the case where
you need to fetch a small subset of a large number of subversion
branches, or where your subversion layout doesn't match the standard
trunk/branches/tags layout very well.
author | David Schleimer <dschleimer@fb.com> |
---|---|
date | Mon, 26 Aug 2013 16:40:31 -0700 |
parents | |
children | c3c4518e00aa |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/hgsubversion/layouts/custom.py @@ -0,0 +1,105 @@ +"""Layout that allows you to define arbitrary subversion to mercurial mappings. + +This is the simplest layout to use if your layout is just plain weird. +Also useful if your layout is pretty normal, but you personally only +want a couple of branches. + + +""" + +import base + + +class CustomLayout(base.BaseLayout): + + def __init__(self, ui): + base.BaseLayout.__init__(self, ui) + + self.svn_to_hg = {} + self.hg_to_svn = {} + + for hg_branch, svn_path in ui.configitems('hgsubversionbranch'): + + hg_branch = hg_branch.strip() + if hg_branch == 'default' or not hg_branch: + hg_branch = None + svn_path = svn_path.strip('/') + + for other_svn in self.svn_to_hg: + if other_svn == svn_path: + msg = 'specified two hg branches for svn path %s: %s and %s' + raise hgutil.Abort(msg % (svn_path, other_hg, hg_branch)) + + if (other_svn.startswith(svn_path + '/') or + svn_path.startswith(other_svn + '/')): + msg = 'specified mappings for nested svn paths: %s and %s' + raise hgutl.Abort(msg % (svn_path, other_svn)) + + self.svn_to_hg[svn_path] = hg_branch + self.hg_to_svn[hg_branch] = svn_path + + def localname(self, path): + if path in self.svn_to_hg: + return self.svn_to_hg[path] + children = [] + for svn_path in self.svn_to_hg: + if svn_path.startswith(path + '/'): + children.append(svn_path) + if len(children) == 1: + return self.svn_to_hg[children[0]] + + return '../%s' % path + + def remotename(self, branch): + if branch =='default': + branch = None + if branch and branch.startswith('../'): + return branch[3:] + if branch not in self.hg_to_svn: + raise KeyError('Unknown mercurial branch: %s' % branch) + return self.hg_to_svn[branch] + + def remotepath(self, branch, subdir='/'): + if not subdir.endswith('/'): + subdir += '/' + return subdir + self.remotename(branch) + + def taglocations(self, meta_data_dir): + return [] + + def get_path_tag(self, path, taglocations): + return None + + def split_remote_name(self, path, known_branches): + if path in self.svn_to_hg: + return path, '' + children = [] + for svn_path in self.svn_to_hg: + if path.startswith(svn_path + '/'): + return svn_path, path[len(svn_path)+1:] + if svn_path.startswith(path + '/'): + children.append(svn_path) + + # if the path represents the parent of exactly one of our svn + # branches, treat it as though it were that branch, because + # that means we are probably pulling in a subproject of an svn + # project, and someone copied the parent svn project. + if len(children) == 1: + return children[0], '' + + for branch in known_branches: + if branch and branch.startswith('../'): + if path.startswith(branch[3:] + '/'): + # -3 for the leading ../, plus one for the trailing / + return branch[3:], path[len(branch) - 2:] + if branch[3:].startswith(path + '/'): + children.append(branch[3:]) + + if len(children) == 1: + return children[0], '' + + + # this splits on the rightmost '/' but considers the entire + # string to be the branch component of the path if there is no '/' + components = path.rsplit('/', 1) + return components[0], '/'.join(components[1:])