# HG changeset patch # User Dan Villiom Podlaski Christiansen # Date 1241865377 -7200 # Node ID 235022089da60e0a3b59eba92e69d7b8624c4331 # Parent 48ec2d62dc297a8a494c69b26854a1b69fa4e4d3# Parent 067914ecb4eb6beb49f7a19962997989ba5487d5 merge with stable diff --git a/__init__.py b/__init__.py --- a/__init__.py +++ b/__init__.py @@ -18,22 +18,17 @@ import traceback from mercurial import commands from mercurial import extensions +from mercurial import hg from mercurial import util as hgutil from svn import core import svncommands -import tag_repo +import svnrepo import util import wrappers import svnexternals -def reposetup(ui, repo): - if not util.is_svn_repo(repo): - return - - repo.__class__ = tag_repo.generate_repo_class(ui, repo) - def uisetup(ui): """Do our UI setup. @@ -55,21 +50,6 @@ def uisetup(ui): wrappers.push) entry[1].append(('', 'svn', None, "push to subversion")) entry[1].append(('', 'svn-stupid', None, "use stupid replay during push to svn")) - entry = extensions.wrapcommand(commands.table, 'pull', - wrappers.pull) - entry[1].append(('', 'svn', None, "pull from subversion")) - entry[1].append(('', 'svn-stupid', None, "use stupid replay during pull from svn")) - - entry = extensions.wrapcommand(commands.table, 'clone', - wrappers.clone) - entry[1].extend([#('', 'skipto-rev', '0', 'skip commits before this revision.'), - ('', 'svn-stupid', False, 'be stupid and use diffy replay.'), - ('', 'svn-tag-locations', 'tags', 'Relative path to Subversion tags.'), - ('', 'svn-authors', '', 'username mapping filename'), - ('', 'svn-filemap', '', - 'remap file to exclude paths or include only certain paths'), - ('', 'svn-no-branchnames', False, "don't record branch names in hg"), - ]) try: rebase = extensions.find('rebase') @@ -116,7 +96,12 @@ def svn(ui, repo, subcommand, *args, **o else: raise +def reposetup(ui, repo): + if repo.local(): + svnrepo.generate_repo_class(ui, repo) +for scheme in ('svn', 'svn+ssh', 'svn+http', 'svn+file'): + hg.schemes[scheme] = svnrepo cmdtable = { "svn": diff --git a/hg_delta_editor.py b/hg_delta_editor.py --- a/hg_delta_editor.py +++ b/hg_delta_editor.py @@ -89,12 +89,11 @@ class HgChangeReceiver(delta.Editor): self.ui = ui_ if repo: self.repo = repo + self.__setup_repo(repo) self.path = os.path.normpath(os.path.join(self.repo.path, '..')) elif path: self.path = path self.__setup_repo(path) - else: #pragma: no cover - raise TypeError("Expected either path or repo argument") self.subdir = subdir if self.subdir and self.subdir[0] == '/': @@ -144,19 +143,27 @@ class HgChangeReceiver(delta.Editor): date = self.lastdate return date - def __setup_repo(self, repo_path): + def __setup_repo(self, arg): """Verify the repo is going to work out for us. This method will fail an assertion if the repo exists but doesn't have the Subversion metadata. """ - if os.path.isdir(repo_path) and len(os.listdir(repo_path)): - self.repo = hg.repository(self.ui, repo_path) + if isinstance(arg, basestring): + self.path = arg + self.repo = hg.repository(self.ui, self.path, create=True) + elif arg: + self.repo = arg + self.path = os.path.normpath(os.path.join(self.repo.path, '..')) + else: #pragma: no cover + raise TypeError("editor requires either a path or a repository " + "specified") + + if os.path.isdir(self.meta_data_dir) and os.listdir(self.meta_data_dir): assert os.path.isfile(self.revmap_file) assert os.path.isfile(self.svn_url_file) assert os.path.isfile(self.uuid_file) else: - self.repo = hg.repository(self.ui, repo_path, create=True) os.makedirs(os.path.dirname(self.uuid_file)) f = open(self.revmap_file, 'w') f.write('%s\n' % util.REVMAP_FILE_VERSION) diff --git a/tag_repo.py b/svnrepo.py rename from tag_repo.py rename to svnrepo.py --- a/tag_repo.py +++ b/svnrepo.py @@ -1,23 +1,87 @@ 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): + 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) return tags - return svntagrepo + 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)) diff --git a/tests/test_fetch_branches.py b/tests/test_fetch_branches.py --- a/tests/test_fetch_branches.py +++ b/tests/test_fetch_branches.py @@ -5,7 +5,6 @@ from mercurial import node from mercurial import ui import test_util -import wrappers class TestFetchBranches(test_util.TestBase): @@ -18,7 +17,7 @@ class TestFetchBranches(test_util.TestBa def _load_fixture_and_fetch_with_anchor(self, fixture_name, anchor): test_util.load_svndump_fixture(self.repo_path, fixture_name) source = '%s#%s' % (test_util.fileurl(self.repo_path), anchor) - wrappers.clone(None, ui.ui(), source=source, dest=self.wc_path) + repo = hg.clone(ui.ui(), source=source, dest=self.wc_path) return hg.repository(ui.ui(), self.wc_path) def test_unrelatedbranch(self, stupid=False): diff --git a/tests/test_util.py b/tests/test_util.py --- a/tests/test_util.py +++ b/tests/test_util.py @@ -30,7 +30,7 @@ def fileurl(path): path = urllib.pathname2url(path) if drive: drive = '/' + drive - url = 'file://%s%s' % (drive, path) + url = 'svn+file://%s%s' % (drive, path) return url def load_svndump_fixture(path, fixture_name): diff --git a/util.py b/util.py --- a/util.py +++ b/util.py @@ -24,7 +24,7 @@ def version(ui): def normalize_url(svnurl): - if svnurl.startswith('svn+http'): + if svnurl.startswith('svn+') and not svnurl.startswith('svn+ssh'): svnurl = svnurl[4:] url, revs, checkout = hg.parseurl(svnurl) url = url.rstrip('/') diff --git a/wrappers.py b/wrappers.py --- a/wrappers.py +++ b/wrappers.py @@ -243,7 +243,7 @@ def pull(orig, ui, repo, source="default svn_stupid = opts.pop('svn_stupid', False) create_new_dest = opts.pop('create_new_dest', False) url = ((repo and repo.ui) or ui).expandpath(source) - if not (cmdutil.issvnurl(url) or svn or create_new_dest): + if orig and not (cmdutil.issvnurl(url) or svn or create_new_dest): return orig(ui, repo, source=source, *args, **opts) svn_url = url svn_url = util.normalize_url(svn_url)