changeset 464:0f7095f53ca3

Extend svnrepos with SubversionRepo and SVNMeta SubversionRepo and SVNMeta are now hidden behind svnremoterepo and svnlocalrepo. It unifies the way svn credentials are read from the command line and configuration file, at the cost of import cycle between svnrepo and wrappers. It is currently not a big deal thanks to demandimport.
author Patrick Mezard <pmezard@gmail.com>
date Sat, 18 Jul 2009 20:44:33 -0500
parents c82d5a9acecf
children d487bbe0e8af
files hgsubversion/svncommands.py hgsubversion/svnrepo.py hgsubversion/util.py hgsubversion/utility_commands.py hgsubversion/wrappers.py
diffstat 5 files changed, 56 insertions(+), 58 deletions(-) [+]
line wrap: on
line diff
--- a/hgsubversion/svncommands.py
+++ b/hgsubversion/svncommands.py
@@ -7,7 +7,7 @@ from mercurial import util as hgutil
 
 import maps
 import svnwrap
-import svnmeta
+import svnrepo
 import util
 import utility_commands
 import svnexternals
@@ -16,12 +16,6 @@ import svnexternals
 def verify(ui, repo, *args, **opts):
     '''verify current revision against Subversion repository
     '''
-
-    if not args:
-        url = repo.ui.expandpath('default')
-    else:
-        url = args[0]
-
     ctx = repo[opts.get('rev', '.')]
     if 'close' in ctx.extra():
         ui.write('cannot verify closed branch')
@@ -33,9 +27,11 @@ def verify(ui, repo, *args, **opts):
     srev = int(srev.split('@')[1])
     ui.write('verifying %s against r%i\n' % (ctx, srev))
 
-    url = util.normalize_url(url.rstrip('/'))
-    user, passwd = util.getuserpass(ui)
-    svn = svnwrap.SubversionRepo(url, user, passwd)
+    
+    url = repo.ui.expandpath('default')
+    if args:
+        url = args[0]
+    svn = svnrepo.svnremoterepo(ui, url).svn
 
     btypes = {'default': 'trunk'}
     branchpath = btypes.get(ctx.branch(), 'branches/%s' % ctx.branch())
@@ -72,11 +68,9 @@ def rebuildmeta(ui, repo, hg_repo_path, 
         dest = args[0]
     elif len(args) > 1:
         raise hgutil.Abort('rebuildmeta takes 1 or no arguments')
-    url = repo.ui.expandpath(dest or 'default-push', dest or 'default')
     uuid = None
-    url = util.normalize_url(url.rstrip('/'))
-    user, passwd = util.getuserpass(ui)
-    svn = svnwrap.SubversionRepo(url, user, passwd)
+    url = repo.ui.expandpath(dest or 'default-push', dest or 'default')
+    svn = svnrepo.svnremoterepo(ui, url).svn
     subdir = svn.subdir
     svnmetadir = os.path.join(repo.path, 'svn')
     if not os.path.exists(svnmetadir):
@@ -224,7 +218,7 @@ def update(ui, args, repo, clean=False, 
 
     assert len(args) == 1
     rev = int(args[0])
-    meta = svnmeta.SVNMeta(repo)
+    meta = repo.svnmeta()
 
     answers = []
     for k, v in meta.revmap.iteritems():
--- a/hgsubversion/svnrepo.py
+++ b/hgsubversion/svnrepo.py
@@ -21,6 +21,10 @@ import mercurial.repo
 
 import util
 import wrappers
+import svnwrap
+import svnmeta
+
+propertycache = hgutil.propertycache
 
 def generate_repo_class(ui, repo):
     """ This function generates the local repository wrapper. """
@@ -56,20 +60,39 @@ def generate_repo_class(ui, repo):
         def findoutgoing(self, remote, base=None, heads=None, force=False):
             return wrappers.outgoing(repo, remote, heads, force)
 
+        def svnmeta(self, uuid=None, subdir=''):
+            return svnmeta.SVNMeta(self, uuid, subdir)
+
     repo.__class__ = svnlocalrepo
 
 class svnremoterepo(mercurial.repo.repository):
     """ the dumb wrapper for actual Subversion repositories """
 
-    def __init__(self, ui, path):
+    def __init__(self, ui, path=None):
         self.ui = ui
+        if path is None:
+            path = self.ui.config('paths', 'default')
         self.path = path
         self.capabilities = set(['lookup', 'subversion'])
 
-    @property
+    @propertycache
     def svnurl(self):
         return util.normalize_url(self.path)
 
+    @propertycache
+    def svn(self):
+        # DO NOT default the user to hg's getuser(). If you provide
+        # *any* default username to Subversion, it won't use any remembered
+        # username for the desired realm, breaking OS X Keychain support,
+        # GNOME keyring support, and all similar tools.
+        user = self.ui.config('hgsubversion', 'username')
+        passwd = self.ui.config('hgsubversion', 'password')
+        return svnwrap.SubversionRepo(self.svnurl, user, passwd)
+
+    @property
+    def svnuuid(self):
+        return self.svn.uuid
+
     def url(self):
         return self.path
 
--- a/hgsubversion/util.py
+++ b/hgsubversion/util.py
@@ -60,15 +60,6 @@ def islocalrepo(url):
     return False
 
 
-def getuserpass(ui):
-    # DO NOT default the user to hg's getuser(). If you provide
-    # *any* default username to Subversion, it won't use any remembered
-    # username for the desired realm, breaking OS X Keychain support,
-    # GNOME keyring support, and all similar tools.
-    return (ui.config('hgsubversion', 'username'),
-            ui.config('hgsubversion', 'password'))
-
-
 def version(ui):
     """Guess the version of hgsubversion.
     """
--- a/hgsubversion/utility_commands.py
+++ b/hgsubversion/utility_commands.py
@@ -2,8 +2,8 @@ import os
 
 from mercurial import util as hgutil
 
-import svnmeta
 import svnwrap
+import svnrepo
 import util
 
 def genignore(ui, repo, force=False, **opts):
@@ -12,16 +12,15 @@ def genignore(ui, repo, force=False, **o
     ignpath = repo.wjoin('.hgignore')
     if not force and os.path.exists(ignpath):
         raise hgutil.Abort('not overwriting existing .hgignore, try --force?')
-    url = util.normalize_url(repo.ui.config('paths', 'default'))
-    user, passwd = util.getuserpass(ui)
-    svn = svnwrap.SubversionRepo(url, user, passwd)
-    meta = svnmeta.SVNMeta(repo, svn.uuid)
+    svn = svnrepo.svnremoterepo(repo.ui).svn
+    meta = repo.svnmeta()
     hashes = meta.revmap.hashes()
     parent = util.parentrev(ui, repo, meta, hashes)
     r, br = hashes[parent.node()]
     branchpath = br and ('branches/%s' % br) or 'trunk'
     ignorelines = ['.hgignore', 'syntax:glob']
-    dirs = [''] + [d[0] for d in svn.list_files(branchpath, r) if d[1] == 'd']
+    dirs = [''] + [d[0] for d in svn.list_files(branchpath, r)
+                   if d[1] == 'd']
     for dir in dirs:
         props = svn.list_props('%s/%s/' % (branchpath, dir), r)
         if 'svn:ignore' not in props:
@@ -35,10 +34,7 @@ def genignore(ui, repo, force=False, **o
 def info(ui, repo, hg_repo_path, **opts):
     """show Subversion details similar to `svn info'
     """
-    url = util.normalize_url(repo.ui.config('paths', 'default'))
-    user, passwd = util.getuserpass(ui)
-    svn = svnwrap.SubversionRepo(url, user, passwd)
-    meta = svnmeta.SVNMeta(repo, svn.uuid)
+    meta = repo.svnmeta()
     hashes = meta.revmap.hashes()
     parent = util.parentrev(ui, repo, meta, hashes)
     pn = parent.node()
@@ -54,10 +50,8 @@ def info(ui, repo, hg_repo_path, **opts)
         subdir = subdir.replace('branches/../', '')
     else:
         branchpath = '/branches/%s' % br
-    url = util.normalize_url(repo.ui.config('paths', 'default'))
-    if url[-1] == '/':
-        url = url[:-1]
-    url = '%s%s' % (url, branchpath)
+    remoterepo = svnrepo.svnremoterepo(repo.ui)
+    url = '%s%s' % (remoterepo.svnurl, branchpath)
     author = meta.authors.reverselookup(parent.user())
     # cleverly figure out repo root w/o actually contacting the server
     reporoot = url[:len(url)-len(subdir)]
@@ -86,7 +80,7 @@ def listauthors(ui, args, authors=None, 
     if not len(args):
         ui.status('No repository specified.\n')
         return
-    svn = svnwrap.SubversionRepo(util.normalize_url(args[0]))
+    svn = svnrepo.svnremoterepo(ui, args[0]).svn
     author_set = set()
     for rev in svn.revisions():
         author_set.add(str(rev.author)) # So None becomes 'None'
--- a/hgsubversion/wrappers.py
+++ b/hgsubversion/wrappers.py
@@ -10,11 +10,11 @@ from mercurial import i18n
 from svn import core
 from svn import delta
 
-import svnmeta
 import replay
 import pushmod
 import stupid as stupidmod
 import svnwrap
+import svnrepo
 import util
 
 pullfuns = {
@@ -34,7 +34,7 @@ def parents(orig, ui, repo, *args, **opt
     """
     if not opts.get('svn', False):
         return orig(ui, repo, *args, **opts)
-    meta = svnmeta.SVNMeta(repo)
+    meta = repo.svnmeta()
     hashes = meta.revmap.hashes()
     ha = util.parentrev(ui, repo, meta, hashes)
     if ha.node() == node.nullid:
@@ -53,12 +53,10 @@ def incoming(orig, ui, repo, source='def
     if 'subversion' not in other.capabilities:
         return orig(ui, repo, source, **opts)
 
-    user, passwd = util.getuserpass(ui)
-    svn = svnwrap.SubversionRepo(other.svnurl, user, passwd)
-    meta = svnmeta.SVNMeta(repo)
+    meta = repo.svnmeta()
 
     ui.status('incoming changes from %s\n' % other.svnurl)
-    for r in svn.revisions(start=meta.revmap.seen):
+    for r in other.svn.revisions(start=meta.revmap.seen):
         ui.status('\n')
         for label, attr in revmeta:
             l1 = label + ':'
@@ -75,7 +73,7 @@ def outgoing(repo, dest=None, heads=None
 
     # split off #rev; TODO implement --revision/#rev support
     svnurl, revs, checkout = hg.parseurl(dest.svnurl, heads)
-    meta = svnmeta.SVNMeta(repo)
+    meta = repo.svnmeta()
     parent = repo.parents()[0].node()
     hashes = meta.revmap.hashes()
     return util.outgoing_revisions(repo, hashes, parent)
@@ -86,7 +84,7 @@ def diff(orig, ui, repo, *args, **opts):
     """
     if not opts.get('svn', False) or opts.get('change', None):
         return orig(ui, repo, *args, **opts)
-    meta = svnmeta.SVNMeta(repo)
+    meta = repo.svnmeta()
     hashes = meta.revmap.hashes()
     if not opts.get('rev', None):
         parent = repo.parents()[0]
@@ -119,9 +117,8 @@ def push(repo, dest, force, revs):
     # split of #rev; TODO: implement --rev/#rev support
     svnurl, revs, checkout = hg.parseurl(svnurl, revs)
     # TODO: do credentials specified in the URL still work?
-    user, passwd = util.getuserpass(ui)
-    svn = svnwrap.SubversionRepo(svnurl, user, passwd)
-    meta = svnmeta.SVNMeta(repo, svn.uuid)
+    svn = svnrepo.svnremoterepo(repo.ui, svnurl).svn
+    meta = repo.svnmeta(svn.uuid)
 
     # Strategy:
     # 1. Find all outgoing commits from this head
@@ -156,7 +153,7 @@ def push(repo, dest, force, revs):
         base_revision = hashes[base_n][0]
         try:
             pushmod.commit(ui, repo, old_ctx, meta, svnurl,
-                           base_revision, user, passwd)
+                           base_revision, svn.username, svn.password)
         except pushmod.NoFilesException:
             ui.warn("Could not push revision %s because it had no changes in svn.\n" %
                      old_ctx)
@@ -194,7 +191,7 @@ def push(repo, dest, force, revs):
                             child = children[0]
                         rebasesrc = node.bin(child.extra().get('rebase_source', node.hex(node.nullid)))
         # TODO: stop constantly creating the SVNMeta instances.
-        meta = svnmeta.SVNMeta(meta.repo, svn.uuid)
+        meta = repo.svnmeta(svn.uuid)
         hashes = meta.revmap.hashes()
     util.swap_out_encoding(old_encoding)
     return 0
@@ -230,9 +227,8 @@ def pull(repo, source, heads=[], force=F
         repo.ui.note('fetching stupidly...\n')
 
     # TODO: do credentials specified in the URL still work?
-    user, passwd = util.getuserpass(repo.ui)
-    svn = svnwrap.SubversionRepo(svn_url, user, passwd)
-    meta = svnmeta.SVNMeta(repo, svn.uuid, svn.subdir)
+    svn = svnrepo.svnremoterepo(repo.ui, svn_url).svn
+    meta = repo.svnmeta(svn.uuid, svn.subdir)
 
     start = max(meta.revmap.seen, skipto_rev)
     initializing_repo = meta.revmap.seen <= 0
@@ -320,7 +316,7 @@ def rebase(orig, ui, repo, **opts):
         extra['branch'] = ctx.branch()
     extrafn = opts.get('svnextrafn', extrafn2)
     sourcerev = opts.get('svnsourcerev', repo.parents()[0].node())
-    meta = svnmeta.SVNMeta(repo)
+    meta = repo.svnmeta()
     hashes = meta.revmap.hashes()
     o_r = util.outgoing_revisions(repo, hashes, sourcerev=sourcerev)
     if not o_r: