comparison svnrepo.py @ 331:75f082b5897e

Switch to using url scheme wrappers instead of duplicating each command we wrap. The 'hg svn url' command has been killed; the replacement is '.hg/hgrc'. More stuff related to its disappearance has been stripped, including two tests. HgChangeReceiver now takes a UUID argument, which it uses to ensure that remote repositories remain unchanged. This is a temporary solution, and I'm not entirely satisfied with how it's done either. Access to the UUID file has been isolated in a HgChangeReceiver property. Some more tests have been updated to use ui.pushbuffer()/popbuffer(), and to pass through the Mercurial API. Moved the arguments to wrappers.pull() to the UI configuration. Also, remove HgChangeReceiver.opts in favour of a 'usebranchnames' instance & configuration variable. The name is taken from the ConvertExtension.
author Dan Villiom Podlaski Christiansen <danchr@gmail.com>
date Fri, 15 May 2009 19:18:43 +0200
parents 48ec2d62dc29
children
comparison
equal deleted inserted replaced
330:5f8f2fd4fd54 331:75f082b5897e
1 """
2 repository class-based interface for hgsubversion
3
4 Copyright (C) 2009, Dan Villiom Podlaski Christiansen <danchr@gmail.com>
5 See parent package for licensing.
6
7 Internally, Mercurial assumes that every single repository is a localrepository
8 subclass: pull() is called on the instance pull *to*, but not the one pulled
9 *from*. To work around this, we create two classes:
10
11 - svnremoterepo for Subversion repositories, but it doesn't really do anything.
12 - svnlocalrepo for local repositories which handles both operations on itself --
13 the local, hgsubversion-enabled clone -- and the remote repository. Decorators
14 are used to distinguish and filter these operations from others.
15 """
16
1 from mercurial import node 17 from mercurial import node
2 from mercurial import util as hgutil 18 from mercurial import util as hgutil
3 import mercurial.repo 19 import mercurial.repo
4 20
5 import hg_delta_editor 21 import hg_delta_editor
6 import util 22 import util
7 import wrappers 23 import wrappers
8 24
9 def generate_repo_class(ui, repo): 25 def generate_repo_class(ui, repo):
26 """ This function generates the local repository wrapper. """
27
10 def localsvn(fn): 28 def localsvn(fn):
11 ''' 29 """
12 Filter for instance methods which only apply to local Subversion 30 Filter for instance methods which only apply to local Subversion
13 repositories. 31 repositories.
14 ''' 32 """
15 if util.is_svn_repo(repo): 33 if util.is_svn_repo(repo):
16 return fn 34 return fn
17 else: 35 else:
18 original = repo.__getattribute__(fn.__name__) 36 return getattr(repo, fn.__name__)
19 return original
20 37
21 def remotesvn(fn): 38 def remotesvn(fn):
22 ''' 39 """
23 Filter for instance methods which require the first argument 40 Filter for instance methods which require the first argument
24 to be a remote Subversion repository instance. 41 to be a remote Subversion repository instance.
25 ''' 42 """
26 original = repo.__getattribute__(fn.__name__) 43 original = getattr(repo.__class__, fn.__name__)
27 def wrapper(self, *args, **opts): 44 def wrapper(self, *args, **opts):
28 if not isinstance(args[0], svnremoterepo): 45 if 'subversion' in getattr(args[0], 'capabilities', []):
29 return original(*args, **opts) 46 return fn(self, *args, **opts)
30 else: 47 else:
31 return fn(self, *args, **opts) 48 return original(self, *args, **opts)
32 wrapper.__name__ = fn.__name__ + '_wrapper' 49 wrapper.__name__ = fn.__name__ + '_wrapper'
33 wrapper.__doc__ = fn.__doc__ 50 wrapper.__doc__ = fn.__doc__
34 return wrapper 51 return wrapper
35 52
36 class svnlocalrepo(repo.__class__): 53 class svnlocalrepo(repo.__class__):
37 @remotesvn 54 @remotesvn
55 def push(self, remote, force=False, revs=None):
56 # TODO: pass on revs
57 wrappers.push(self, dest=remote.svnurl, force=force, revs=None)
58
59 @remotesvn
38 def pull(self, remote, heads=None, force=False): 60 def pull(self, remote, heads=None, force=False):
39 try: 61 try:
40 lock = self.wlock() 62 lock = self.wlock()
41 wrappers.pull(None, self.ui, self, source=remote.path, 63 wrappers.pull(self, source=remote.svnurl, rev=heads, force=force)
42 svn=True, rev=heads, force=force)
43 except KeyboardInterrupt: 64 except KeyboardInterrupt:
44 pass 65 pass
45 finally: 66 finally:
46 lock.release() 67 lock.release()
47 68
49 def tags(self): 70 def tags(self):
50 tags = super(svnlocalrepo, self).tags() 71 tags = super(svnlocalrepo, self).tags()
51 hg_editor = hg_delta_editor.HgChangeReceiver(repo=self) 72 hg_editor = hg_delta_editor.HgChangeReceiver(repo=self)
52 for tag, source in hg_editor.tags.iteritems(): 73 for tag, source in hg_editor.tags.iteritems():
53 target = hg_editor.get_parent_revision(source[1]+1, source[0]) 74 target = hg_editor.get_parent_revision(source[1]+1, source[0])
54 tags['tag/%s' % tag] = node.hex(target) 75 tags['tag/%s' % tag] = target
55 return tags 76 return tags
56 77
57 repo.__class__ = svnlocalrepo 78 repo.__class__ = svnlocalrepo
58 79
59 class svnremoterepo(mercurial.repo.repository): 80 class svnremoterepo(mercurial.repo.repository):
81 """ the dumb wrapper for actual Subversion repositories """
82
60 def __init__(self, ui, path): 83 def __init__(self, ui, path):
61 self.ui = ui 84 self.ui = ui
62 self.path = path 85 self.path = path
63 self.capabilities = set(['lookup']) 86 self.capabilities = set(['lookup', 'subversion'])
87
88 @property
89 def svnurl(self):
90 return util.normalize_url(self.path)
64 91
65 def url(self): 92 def url(self):
66 return self.path 93 return self.path
67 94
68 def lookup(self, key): 95 def lookup(self, key):
80 107
81 def instance(ui, url, create): 108 def instance(ui, url, create):
82 if create: 109 if create:
83 raise hgutil.Abort('cannot create new remote Subversion repository') 110 raise hgutil.Abort('cannot create new remote Subversion repository')
84 111
85 if url.startswith('svn+') and not url.startswith('svn+ssh:'): 112 return svnremoterepo(ui, url)
86 url = url[4:]
87 return svnremoterepo(ui, util.normalize_url(url))