view tag_repo.py @ 326:33736e2e25f0

alternate approach for supporting svn schemes for repository paths We now intercept the operations in the local repo class, and handle the relevant operation ourselves. This frees us from wrapping all relevant commands and replicating their functionality. The implementation is incomplete; only one test has been modified to use the standard Mercurial API with the changed URLs. Once changed, those tests will likely reveal bugs or missing features in the new wrappers. Also, new wrappers will be needed for handling conversion flags such as -A/--authormap.
author Dan Villiom Podlaski Christiansen <danchr@gmail.com>
date Thu, 07 May 2009 20:50:53 +0200
parents 91c818377703
children 98740f66a70c
line wrap: on
line source

from mercurial import node
from mercurial import util as hgutil
import mercurial.repo

import hg_delta_editor
import util
import wrappers

def generate_repo_class(ui, repo):
    def localsvn(fn):
        '''
        Filter for instance methods which only apply to local Subversion
        repositories.
        '''
        if util.is_svn_repo(repo):
            return fn
        else:
            original = repo.__getattribute__(fn.__name__)
            return original

    def remotesvn(fn):
        '''
        Filter for instance methods which require the first argument
        to be a remote Subversion repository instance.
        '''
        original = repo.__getattribute__(fn.__name__)
        def wrapper(self, *args, **opts):
            print args
            if not isinstance(args[0], svnremoterepo):
                return original(*args, **opts)
            else:
                return fn(self, *args, **opts)
        wrapper.__name__ = fn.__name__ + '_wrapper'
        wrapper.__doc__ = fn.__doc__
        return wrapper

    class svnlocalrepo(repo.__class__):
        @remotesvn
        def pull(self, remote, heads=None, force=False):
            try:
                lock = self.wlock()
                wrappers.pull(None, self.ui, self, source=remote.path,
                              svn=True, rev=heads, force=force)
            except KeyboardInterrupt:
                pass
            finally:
                lock.release()

        @localsvn
        def tags(self):
            tags = super(svnlocalrepo, self).tags()
            hg_editor = hg_delta_editor.HgChangeReceiver(repo=self)
            for tag, source in hg_editor.tags.iteritems():
                target = hg_editor.get_parent_revision(source[1]+1, source[0])
                tags['tag/%s' % tag] = node.hex(target)
            # TODO: should we even generate these tags?
            if not hasattr(self, '_nofaketags'):
                for (revnum, branch), node_hash in hg_editor.revmap.iteritems():
                    tags['%s@r%d' % (branch or 'trunk', revnum)] = node_hash
            return tags

        @localsvn
        def tagslist(self):
            try:
                self._nofaketags = True
                return super(svnlocalrepo, self).tagslist()
            finally:
                del self._nofaketags

    repo.__class__ = svnlocalrepo

class svnremoterepo(mercurial.repo.repository):
    def __init__(self, ui, path):
        self.ui = ui
        self.path = path
        self.capabilities = set(['lookup'])

    def url(self):
        return self.path

    def lookup(self, key):
        return key

    def cancopy(self):
        return False

    def heads(self, *args, **opts):
        """
        Whenever this function is hit, we abort. The traceback is useful for
        figuring out where to intercept the functionality.
        """
        raise hgutil.Abort('command unavailable for Subversion repositories')

def instance(ui, url, create):
    if create:
        raise hgutil.Abort('cannot create new remote Subversion repository')

    if url.startswith('svn+') and not url.startswith('svn+ssh:'):
        url = url[4:]
    return svnremoterepo(ui, util.normalize_url(url))