comparison hgext/convert/subversion.py @ 9829:1b2516a547d4

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.
author Patrick Mezard <pmezard@gmail.com>
date Wed, 11 Nov 2009 19:45:00 +0100
parents dec177286deb
children 2e51cc30fc30
comparison
equal deleted inserted replaced
9828:4761e6203b77 9829:1b2516a547d4
6 import re 6 import re
7 import sys 7 import sys
8 import cPickle as pickle 8 import cPickle as pickle
9 import tempfile 9 import tempfile
10 import urllib 10 import urllib
11 import urllib2
11 12
12 from mercurial import strutil, util, encoding 13 from mercurial import strutil, util, encoding
13 from mercurial.i18n import _ 14 from mercurial.i18n import _
14 15
15 # Subversion stuff. Works best with very recent Python SVN bindings 16 # Subversion stuff. Works best with very recent Python SVN bindings
134 135
135 136
136 # Check to see if the given path is a local Subversion repo. Verify this by 137 # Check to see if the given path is a local Subversion repo. Verify this by
137 # looking for several svn-specific files and directories in the given 138 # looking for several svn-specific files and directories in the given
138 # directory. 139 # directory.
139 def filecheck(path, proto): 140 def filecheck(ui, path, proto):
140 for x in ('locks', 'hooks', 'format', 'db', ): 141 for x in ('locks', 'hooks', 'format', 'db', ):
141 if not os.path.exists(os.path.join(path, x)): 142 if not os.path.exists(os.path.join(path, x)):
142 return False 143 return False
143 return True 144 return True
144 145
145 # Check to see if a given path is the root of an svn repo over http. We verify 146 # Check to see if a given path is the root of an svn repo over http. We verify
146 # this by requesting a version-controlled URL we know can't exist and looking 147 # this by requesting a version-controlled URL we know can't exist and looking
147 # for the svn-specific "not found" XML. 148 # for the svn-specific "not found" XML.
148 def httpcheck(path, proto): 149 def httpcheck(ui, path, proto):
149 return ('<m:human-readable errcode="160013">' in 150 try:
150 urllib.urlopen('%s://%s/!svn/ver/0/.svn' % (proto, path)).read()) 151 opener = urllib2.build_opener()
152 rsp = opener.open('%s://%s/!svn/ver/0/.svn' % (proto, path))
153 return '<m:human-readable errcode="160013">' in rsp.read()
154 except urllib2.HTTPError, inst:
155 if inst.code == 404:
156 return False
157 # Except for 404 we cannot know for sure this is not an svn repo
158 ui.warn(_('svn: cannot probe remote repository, assume it could be '
159 'a subversion repository. Use --source if you know better.\n'))
160 return True
161 except:
162 # Could be urllib2.URLError if the URL is invalid or anything else.
163 return False
151 164
152 protomap = {'http': httpcheck, 165 protomap = {'http': httpcheck,
153 'https': httpcheck, 166 'https': httpcheck,
154 'file': filecheck, 167 'file': filecheck,
155 } 168 }
156 def issvnurl(url): 169 def issvnurl(ui, url):
157 try: 170 try:
158 proto, path = url.split('://', 1) 171 proto, path = url.split('://', 1)
159 if proto == 'file': 172 if proto == 'file':
160 path = urllib.url2pathname(path) 173 path = urllib.url2pathname(path)
161 except ValueError: 174 except ValueError:
163 path = os.path.abspath(url) 176 path = os.path.abspath(url)
164 if proto == 'file': 177 if proto == 'file':
165 path = path.replace(os.sep, '/') 178 path = path.replace(os.sep, '/')
166 check = protomap.get(proto, lambda p, p2: False) 179 check = protomap.get(proto, lambda p, p2: False)
167 while '/' in path: 180 while '/' in path:
168 if check(path, proto): 181 if check(ui, path, proto):
169 return True 182 return True
170 path = path.rsplit('/', 1)[0] 183 path = path.rsplit('/', 1)[0]
171 return False 184 return False
172 185
173 # SVN conversion code stolen from bzr-svn and tailor 186 # SVN conversion code stolen from bzr-svn and tailor
189 super(svn_source, self).__init__(ui, url, rev=rev) 202 super(svn_source, self).__init__(ui, url, rev=rev)
190 203
191 if not (url.startswith('svn://') or url.startswith('svn+ssh://') or 204 if not (url.startswith('svn://') or url.startswith('svn+ssh://') or
192 (os.path.exists(url) and 205 (os.path.exists(url) and
193 os.path.exists(os.path.join(url, '.svn'))) or 206 os.path.exists(os.path.join(url, '.svn'))) or
194 issvnurl(url)): 207 issvnurl(ui, url)):
195 raise NoRepo("%s does not look like a Subversion repo" % url) 208 raise NoRepo("%s does not look like a Subversion repo" % url)
196 209
197 try: 210 try:
198 SubversionException 211 SubversionException
199 except NameError: 212 except NameError: