diff 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 diff
--- a/tag_repo.py
+++ b/tag_repo.py
@@ -1,23 +1,100 @@
 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 tags_from_tag_info(repo):
-    hg_editor = hg_delta_editor.HgChangeReceiver(repo=repo)
-    for tag, source in hg_editor.tags.iteritems():
-        source_ha = hg_editor.get_parent_revision(source[1]+1, source[0])
-        yield 'tag/%s'%tag, node.hex(source_ha)
-
+    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
 
-def generate_repo_class(ui, repo):
+    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()
 
-    class svntagrepo(repo.__class__):
+        @localsvn
         def tags(self):
-            tags = dict((k, node.bin(v))
-                        for k,v in tags_from_tag_info(self))
-            hg_tags = super(svntagrepo, self).tags()
-            tags.update(hg_tags)
+            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
 
-    return svntagrepo
+        @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))