convert/svn: delegate to svn bindings if HTTP probe fails
convert extension tries to guess the remote repository type with HTTP probes.
Unfortunately, it does not handle authentication or HTTPS handshakes, so regular
svn repositories may be excluded. Instead, when a non-404 error is retrieved,
we keep trying with the svn bindings. The drawback is missing svn bindings will
make the conversion to fail even for non-svn targets. This can be avoided with
--source.
--- a/hgext/convert/subversion.py Wed Nov 11 18:32:56 2009 +0100
+++ b/hgext/convert/subversion.py Wed Nov 11 19:45:00 2009 +0100
@@ -8,6 +8,7 @@
import cPickle as pickle
import tempfile
import urllib
+import urllib2
from mercurial import strutil, util, encoding
from mercurial.i18n import _
@@ -136,7 +137,7 @@
# Check to see if the given path is a local Subversion repo. Verify this by
# looking for several svn-specific files and directories in the given
# directory.
-def filecheck(path, proto):
+def filecheck(ui, path, proto):
for x in ('locks', 'hooks', 'format', 'db', ):
if not os.path.exists(os.path.join(path, x)):
return False
@@ -145,15 +146,27 @@
# Check to see if a given path is the root of an svn repo over http. We verify
# this by requesting a version-controlled URL we know can't exist and looking
# for the svn-specific "not found" XML.
-def httpcheck(path, proto):
- return ('<m:human-readable errcode="160013">' in
- urllib.urlopen('%s://%s/!svn/ver/0/.svn' % (proto, path)).read())
+def httpcheck(ui, path, proto):
+ try:
+ opener = urllib2.build_opener()
+ rsp = opener.open('%s://%s/!svn/ver/0/.svn' % (proto, path))
+ return '<m:human-readable errcode="160013">' in rsp.read()
+ except urllib2.HTTPError, inst:
+ if inst.code == 404:
+ return False
+ # Except for 404 we cannot know for sure this is not an svn repo
+ ui.warn(_('svn: cannot probe remote repository, assume it could be '
+ 'a subversion repository. Use --source if you know better.\n'))
+ return True
+ except:
+ # Could be urllib2.URLError if the URL is invalid or anything else.
+ return False
protomap = {'http': httpcheck,
'https': httpcheck,
'file': filecheck,
}
-def issvnurl(url):
+def issvnurl(ui, url):
try:
proto, path = url.split('://', 1)
if proto == 'file':
@@ -165,7 +178,7 @@
path = path.replace(os.sep, '/')
check = protomap.get(proto, lambda p, p2: False)
while '/' in path:
- if check(path, proto):
+ if check(ui, path, proto):
return True
path = path.rsplit('/', 1)[0]
return False
@@ -191,7 +204,7 @@
if not (url.startswith('svn://') or url.startswith('svn+ssh://') or
(os.path.exists(url) and
os.path.exists(os.path.join(url, '.svn'))) or
- issvnurl(url)):
+ issvnurl(ui, url)):
raise NoRepo("%s does not look like a Subversion repo" % url)
try: