view hgsubversion/layouts/custom.py @ 1265:4744b7bfa476

layouts: change constructor to take a meta object This change is another step forward to centralize subversion configuration options and help refactor. I couldn't find an easier way to split up this change since there are many interdependent function calls. There is no functionality change in this patch, only renaming ui -> meta.
author Sean Farley <sean.michael.farley@gmail.com>
date Mon, 24 Mar 2014 11:20:49 -0500
parents c3c4518e00aa
children 7bbe120be193
line wrap: on
line source

"""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, meta):
        base.BaseLayout.__init__(self, meta)

        self.svn_to_hg = {}
        self.hg_to_svn = {}

        for hg_branch, svn_path in meta.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, metapath):
        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:])