##// END OF EJS Templates
Use the new UnexpectedOutput exception in httprepo, too.
Thomas Arendsen Hein -
r3565:9073d736 default
parent child Browse files
Show More
@@ -1,380 +1,377 b''
1 # httprepo.py - HTTP repository proxy classes for mercurial
1 # httprepo.py - HTTP repository proxy classes for mercurial
2 #
2 #
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms
6 # This software may be used and distributed according to the terms
7 # of the GNU General Public License, incorporated herein by reference.
7 # of the GNU General Public License, incorporated herein by reference.
8
8
9 from node import *
9 from node import *
10 from remoterepo import *
10 from remoterepo import *
11 from i18n import gettext as _
11 from i18n import gettext as _
12 from demandload import *
12 from demandload import *
13 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
13 demandload(globals(), "hg os urllib urllib2 urlparse zlib util httplib")
14 demandload(globals(), "errno keepalive tempfile socket")
14 demandload(globals(), "errno keepalive tempfile socket")
15
15
16 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
16 class passwordmgr(urllib2.HTTPPasswordMgrWithDefaultRealm):
17 def __init__(self, ui):
17 def __init__(self, ui):
18 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
18 urllib2.HTTPPasswordMgrWithDefaultRealm.__init__(self)
19 self.ui = ui
19 self.ui = ui
20
20
21 def find_user_password(self, realm, authuri):
21 def find_user_password(self, realm, authuri):
22 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
22 authinfo = urllib2.HTTPPasswordMgrWithDefaultRealm.find_user_password(
23 self, realm, authuri)
23 self, realm, authuri)
24 user, passwd = authinfo
24 user, passwd = authinfo
25 if user and passwd:
25 if user and passwd:
26 return (user, passwd)
26 return (user, passwd)
27
27
28 if not self.ui.interactive:
28 if not self.ui.interactive:
29 raise util.Abort(_('http authorization required'))
29 raise util.Abort(_('http authorization required'))
30
30
31 self.ui.write(_("http authorization required\n"))
31 self.ui.write(_("http authorization required\n"))
32 self.ui.status(_("realm: %s\n") % realm)
32 self.ui.status(_("realm: %s\n") % realm)
33 if user:
33 if user:
34 self.ui.status(_("user: %s\n") % user)
34 self.ui.status(_("user: %s\n") % user)
35 else:
35 else:
36 user = self.ui.prompt(_("user:"), default=None)
36 user = self.ui.prompt(_("user:"), default=None)
37
37
38 if not passwd:
38 if not passwd:
39 passwd = self.ui.getpass()
39 passwd = self.ui.getpass()
40
40
41 self.add_password(realm, authuri, user, passwd)
41 self.add_password(realm, authuri, user, passwd)
42 return (user, passwd)
42 return (user, passwd)
43
43
44 def netlocsplit(netloc):
44 def netlocsplit(netloc):
45 '''split [user[:passwd]@]host[:port] into 4-tuple.'''
45 '''split [user[:passwd]@]host[:port] into 4-tuple.'''
46
46
47 a = netloc.find('@')
47 a = netloc.find('@')
48 if a == -1:
48 if a == -1:
49 user, passwd = None, None
49 user, passwd = None, None
50 else:
50 else:
51 userpass, netloc = netloc[:a], netloc[a+1:]
51 userpass, netloc = netloc[:a], netloc[a+1:]
52 c = userpass.find(':')
52 c = userpass.find(':')
53 if c == -1:
53 if c == -1:
54 user, passwd = urllib.unquote(userpass), None
54 user, passwd = urllib.unquote(userpass), None
55 else:
55 else:
56 user = urllib.unquote(userpass[:c])
56 user = urllib.unquote(userpass[:c])
57 passwd = urllib.unquote(userpass[c+1:])
57 passwd = urllib.unquote(userpass[c+1:])
58 c = netloc.find(':')
58 c = netloc.find(':')
59 if c == -1:
59 if c == -1:
60 host, port = netloc, None
60 host, port = netloc, None
61 else:
61 else:
62 host, port = netloc[:c], netloc[c+1:]
62 host, port = netloc[:c], netloc[c+1:]
63 return host, port, user, passwd
63 return host, port, user, passwd
64
64
65 def netlocunsplit(host, port, user=None, passwd=None):
65 def netlocunsplit(host, port, user=None, passwd=None):
66 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
66 '''turn host, port, user, passwd into [user[:passwd]@]host[:port].'''
67 if port:
67 if port:
68 hostport = host + ':' + port
68 hostport = host + ':' + port
69 else:
69 else:
70 hostport = host
70 hostport = host
71 if user:
71 if user:
72 if passwd:
72 if passwd:
73 userpass = urllib.quote(user) + ':' + urllib.quote(passwd)
73 userpass = urllib.quote(user) + ':' + urllib.quote(passwd)
74 else:
74 else:
75 userpass = urllib.quote(user)
75 userpass = urllib.quote(user)
76 return userpass + '@' + hostport
76 return userpass + '@' + hostport
77 return hostport
77 return hostport
78
78
79 class httpconnection(keepalive.HTTPConnection):
79 class httpconnection(keepalive.HTTPConnection):
80 # must be able to send big bundle as stream.
80 # must be able to send big bundle as stream.
81
81
82 def send(self, data):
82 def send(self, data):
83 if isinstance(data, str):
83 if isinstance(data, str):
84 keepalive.HTTPConnection.send(self, data)
84 keepalive.HTTPConnection.send(self, data)
85 else:
85 else:
86 # if auth required, some data sent twice, so rewind here
86 # if auth required, some data sent twice, so rewind here
87 data.seek(0)
87 data.seek(0)
88 for chunk in util.filechunkiter(data):
88 for chunk in util.filechunkiter(data):
89 keepalive.HTTPConnection.send(self, chunk)
89 keepalive.HTTPConnection.send(self, chunk)
90
90
91 class basehttphandler(keepalive.HTTPHandler):
91 class basehttphandler(keepalive.HTTPHandler):
92 def http_open(self, req):
92 def http_open(self, req):
93 return self.do_open(httpconnection, req)
93 return self.do_open(httpconnection, req)
94
94
95 has_https = hasattr(urllib2, 'HTTPSHandler')
95 has_https = hasattr(urllib2, 'HTTPSHandler')
96 if has_https:
96 if has_https:
97 class httpsconnection(httplib.HTTPSConnection):
97 class httpsconnection(httplib.HTTPSConnection):
98 response_class = keepalive.HTTPResponse
98 response_class = keepalive.HTTPResponse
99 # must be able to send big bundle as stream.
99 # must be able to send big bundle as stream.
100
100
101 def send(self, data):
101 def send(self, data):
102 if isinstance(data, str):
102 if isinstance(data, str):
103 httplib.HTTPSConnection.send(self, data)
103 httplib.HTTPSConnection.send(self, data)
104 else:
104 else:
105 # if auth required, some data sent twice, so rewind here
105 # if auth required, some data sent twice, so rewind here
106 data.seek(0)
106 data.seek(0)
107 for chunk in util.filechunkiter(data):
107 for chunk in util.filechunkiter(data):
108 httplib.HTTPSConnection.send(self, chunk)
108 httplib.HTTPSConnection.send(self, chunk)
109
109
110 class httphandler(basehttphandler, urllib2.HTTPSHandler):
110 class httphandler(basehttphandler, urllib2.HTTPSHandler):
111 def https_open(self, req):
111 def https_open(self, req):
112 return self.do_open(httpsconnection, req)
112 return self.do_open(httpsconnection, req)
113 else:
113 else:
114 class httphandler(basehttphandler):
114 class httphandler(basehttphandler):
115 pass
115 pass
116
116
117 class httprepository(remoterepository):
117 class httprepository(remoterepository):
118 def __init__(self, ui, path):
118 def __init__(self, ui, path):
119 self.path = path
119 self.path = path
120 self.caps = None
120 self.caps = None
121 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
121 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
122 if query or frag:
122 if query or frag:
123 raise util.Abort(_('unsupported URL component: "%s"') %
123 raise util.Abort(_('unsupported URL component: "%s"') %
124 (query or frag))
124 (query or frag))
125 if not urlpath: urlpath = '/'
125 if not urlpath: urlpath = '/'
126 host, port, user, passwd = netlocsplit(netloc)
126 host, port, user, passwd = netlocsplit(netloc)
127
127
128 # urllib cannot handle URLs with embedded user or passwd
128 # urllib cannot handle URLs with embedded user or passwd
129 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
129 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
130 urlpath, '', ''))
130 urlpath, '', ''))
131 self.ui = ui
131 self.ui = ui
132
132
133 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
133 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
134 # XXX proxyauthinfo = None
134 # XXX proxyauthinfo = None
135 handler = httphandler()
135 handler = httphandler()
136
136
137 if proxyurl:
137 if proxyurl:
138 # proxy can be proper url or host[:port]
138 # proxy can be proper url or host[:port]
139 if not (proxyurl.startswith('http:') or
139 if not (proxyurl.startswith('http:') or
140 proxyurl.startswith('https:')):
140 proxyurl.startswith('https:')):
141 proxyurl = 'http://' + proxyurl + '/'
141 proxyurl = 'http://' + proxyurl + '/'
142 snpqf = urlparse.urlsplit(proxyurl)
142 snpqf = urlparse.urlsplit(proxyurl)
143 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
143 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
144 hpup = netlocsplit(proxynetloc)
144 hpup = netlocsplit(proxynetloc)
145
145
146 proxyhost, proxyport, proxyuser, proxypasswd = hpup
146 proxyhost, proxyport, proxyuser, proxypasswd = hpup
147 if not proxyuser:
147 if not proxyuser:
148 proxyuser = ui.config("http_proxy", "user")
148 proxyuser = ui.config("http_proxy", "user")
149 proxypasswd = ui.config("http_proxy", "passwd")
149 proxypasswd = ui.config("http_proxy", "passwd")
150
150
151 # see if we should use a proxy for this url
151 # see if we should use a proxy for this url
152 no_list = [ "localhost", "127.0.0.1" ]
152 no_list = [ "localhost", "127.0.0.1" ]
153 no_list.extend([p.lower() for
153 no_list.extend([p.lower() for
154 p in ui.configlist("http_proxy", "no")])
154 p in ui.configlist("http_proxy", "no")])
155 no_list.extend([p.strip().lower() for
155 no_list.extend([p.strip().lower() for
156 p in os.getenv("no_proxy", '').split(',')
156 p in os.getenv("no_proxy", '').split(',')
157 if p.strip()])
157 if p.strip()])
158 # "http_proxy.always" config is for running tests on localhost
158 # "http_proxy.always" config is for running tests on localhost
159 if (not ui.configbool("http_proxy", "always") and
159 if (not ui.configbool("http_proxy", "always") and
160 host.lower() in no_list):
160 host.lower() in no_list):
161 ui.debug(_('disabling proxy for %s\n') % host)
161 ui.debug(_('disabling proxy for %s\n') % host)
162 else:
162 else:
163 proxyurl = urlparse.urlunsplit((
163 proxyurl = urlparse.urlunsplit((
164 proxyscheme, netlocunsplit(proxyhost, proxyport,
164 proxyscheme, netlocunsplit(proxyhost, proxyport,
165 proxyuser, proxypasswd or ''),
165 proxyuser, proxypasswd or ''),
166 proxypath, proxyquery, proxyfrag))
166 proxypath, proxyquery, proxyfrag))
167 handler = urllib2.ProxyHandler({scheme: proxyurl})
167 handler = urllib2.ProxyHandler({scheme: proxyurl})
168 ui.debug(_('proxying through http://%s:%s\n') %
168 ui.debug(_('proxying through http://%s:%s\n') %
169 (proxyhost, proxyport))
169 (proxyhost, proxyport))
170
170
171 # urllib2 takes proxy values from the environment and those
171 # urllib2 takes proxy values from the environment and those
172 # will take precedence if found, so drop them
172 # will take precedence if found, so drop them
173 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
173 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
174 try:
174 try:
175 if os.environ.has_key(env):
175 if os.environ.has_key(env):
176 del os.environ[env]
176 del os.environ[env]
177 except OSError:
177 except OSError:
178 pass
178 pass
179
179
180 passmgr = passwordmgr(ui)
180 passmgr = passwordmgr(ui)
181 if user:
181 if user:
182 ui.debug(_('http auth: user %s, password %s\n') %
182 ui.debug(_('http auth: user %s, password %s\n') %
183 (user, passwd and '*' * len(passwd) or 'not set'))
183 (user, passwd and '*' * len(passwd) or 'not set'))
184 passmgr.add_password(None, host, user, passwd or '')
184 passmgr.add_password(None, host, user, passwd or '')
185
185
186 opener = urllib2.build_opener(
186 opener = urllib2.build_opener(
187 handler,
187 handler,
188 urllib2.HTTPBasicAuthHandler(passmgr),
188 urllib2.HTTPBasicAuthHandler(passmgr),
189 urllib2.HTTPDigestAuthHandler(passmgr))
189 urllib2.HTTPDigestAuthHandler(passmgr))
190
190
191 # 1.0 here is the _protocol_ version
191 # 1.0 here is the _protocol_ version
192 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
192 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
193 urllib2.install_opener(opener)
193 urllib2.install_opener(opener)
194
194
195 def url(self):
195 def url(self):
196 return self.path
196 return self.path
197
197
198 # look up capabilities only when needed
198 # look up capabilities only when needed
199
199
200 def get_caps(self):
200 def get_caps(self):
201 if self.caps is None:
201 if self.caps is None:
202 try:
202 try:
203 self.caps = self.do_read('capabilities').split()
203 self.caps = self.do_read('capabilities').split()
204 except hg.RepoError:
204 except hg.RepoError:
205 self.caps = ()
205 self.caps = ()
206 self.ui.debug(_('capabilities: %s\n') %
206 self.ui.debug(_('capabilities: %s\n') %
207 (' '.join(self.caps or ['none'])))
207 (' '.join(self.caps or ['none'])))
208 return self.caps
208 return self.caps
209
209
210 capabilities = property(get_caps)
210 capabilities = property(get_caps)
211
211
212 def lock(self):
212 def lock(self):
213 raise util.Abort(_('operation not supported over http'))
213 raise util.Abort(_('operation not supported over http'))
214
214
215 def do_cmd(self, cmd, **args):
215 def do_cmd(self, cmd, **args):
216 data = args.pop('data', None)
216 data = args.pop('data', None)
217 headers = args.pop('headers', {})
217 headers = args.pop('headers', {})
218 self.ui.debug(_("sending %s command\n") % cmd)
218 self.ui.debug(_("sending %s command\n") % cmd)
219 q = {"cmd": cmd}
219 q = {"cmd": cmd}
220 q.update(args)
220 q.update(args)
221 qs = '?%s' % urllib.urlencode(q)
221 qs = '?%s' % urllib.urlencode(q)
222 cu = "%s%s" % (self._url, qs)
222 cu = "%s%s" % (self._url, qs)
223 try:
223 try:
224 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
224 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
225 except urllib2.HTTPError, inst:
225 except urllib2.HTTPError, inst:
226 if inst.code == 401:
226 if inst.code == 401:
227 raise util.Abort(_('authorization failed'))
227 raise util.Abort(_('authorization failed'))
228 raise
228 raise
229 except httplib.HTTPException, inst:
229 except httplib.HTTPException, inst:
230 self.ui.debug(_('http error while sending %s command\n') % cmd)
230 self.ui.debug(_('http error while sending %s command\n') % cmd)
231 self.ui.print_exc()
231 self.ui.print_exc()
232 raise IOError(None, inst)
232 raise IOError(None, inst)
233 except IndexError:
233 except IndexError:
234 # this only happens with Python 2.3, later versions raise URLError
234 # this only happens with Python 2.3, later versions raise URLError
235 raise util.Abort(_('http error, possibly caused by proxy setting'))
235 raise util.Abort(_('http error, possibly caused by proxy setting'))
236 # record the url we got redirected to
236 # record the url we got redirected to
237 self._url = resp.geturl().rstrip(qs)
237 self._url = resp.geturl().rstrip(qs)
238 try:
238 try:
239 proto = resp.getheader('content-type')
239 proto = resp.getheader('content-type')
240 except AttributeError:
240 except AttributeError:
241 proto = resp.headers['content-type']
241 proto = resp.headers['content-type']
242
242
243 # accept old "text/plain" and "application/hg-changegroup" for now
243 # accept old "text/plain" and "application/hg-changegroup" for now
244 if not proto.startswith('application/mercurial') and \
244 if not proto.startswith('application/mercurial') and \
245 not proto.startswith('text/plain') and \
245 not proto.startswith('text/plain') and \
246 not proto.startswith('application/hg-changegroup'):
246 not proto.startswith('application/hg-changegroup'):
247 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
247 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
248 self._url)
248 self._url)
249
249
250 if proto.startswith('application/mercurial'):
250 if proto.startswith('application/mercurial'):
251 version = proto[22:]
251 version = proto[22:]
252 if float(version) > 0.1:
252 if float(version) > 0.1:
253 raise hg.RepoError(_("'%s' uses newer protocol %s") %
253 raise hg.RepoError(_("'%s' uses newer protocol %s") %
254 (self._url, version))
254 (self._url, version))
255
255
256 return resp
256 return resp
257
257
258 def do_read(self, cmd, **args):
258 def do_read(self, cmd, **args):
259 fp = self.do_cmd(cmd, **args)
259 fp = self.do_cmd(cmd, **args)
260 try:
260 try:
261 return fp.read()
261 return fp.read()
262 finally:
262 finally:
263 # if using keepalive, allow connection to be reused
263 # if using keepalive, allow connection to be reused
264 fp.close()
264 fp.close()
265
265
266 def lookup(self, key):
266 def lookup(self, key):
267 d = self.do_cmd("lookup", key = key).read()
267 d = self.do_cmd("lookup", key = key).read()
268 success, data = d[:-1].split(' ', 1)
268 success, data = d[:-1].split(' ', 1)
269 if int(success):
269 if int(success):
270 return bin(data)
270 return bin(data)
271 raise hg.RepoError(data)
271 raise hg.RepoError(data)
272
272
273 def heads(self):
273 def heads(self):
274 d = self.do_read("heads")
274 d = self.do_read("heads")
275 try:
275 try:
276 return map(bin, d[:-1].split(" "))
276 return map(bin, d[:-1].split(" "))
277 except:
277 except:
278 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
278 raise util.UnexpectedOutput(_("unexpected response:"), d)
279 raise
280
279
281 def branches(self, nodes):
280 def branches(self, nodes):
282 n = " ".join(map(hex, nodes))
281 n = " ".join(map(hex, nodes))
283 d = self.do_read("branches", nodes=n)
282 d = self.do_read("branches", nodes=n)
284 try:
283 try:
285 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
284 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
286 return br
285 return br
287 except:
286 except:
288 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
287 raise util.UnexpectedOutput(_("unexpected response:"), d)
289 raise
290
288
291 def between(self, pairs):
289 def between(self, pairs):
292 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
290 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
293 d = self.do_read("between", pairs=n)
291 d = self.do_read("between", pairs=n)
294 try:
292 try:
295 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
293 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
296 return p
294 return p
297 except:
295 except:
298 self.ui.warn(_("unexpected response:\n") + d[:400] + "\n...\n")
296 raise util.UnexpectedOutput(_("unexpected response:"), d)
299 raise
300
297
301 def changegroup(self, nodes, kind):
298 def changegroup(self, nodes, kind):
302 n = " ".join(map(hex, nodes))
299 n = " ".join(map(hex, nodes))
303 f = self.do_cmd("changegroup", roots=n)
300 f = self.do_cmd("changegroup", roots=n)
304
301
305 def zgenerator(f):
302 def zgenerator(f):
306 zd = zlib.decompressobj()
303 zd = zlib.decompressobj()
307 try:
304 try:
308 for chnk in f:
305 for chnk in f:
309 yield zd.decompress(chnk)
306 yield zd.decompress(chnk)
310 except httplib.HTTPException, inst:
307 except httplib.HTTPException, inst:
311 raise IOError(None, _('connection ended unexpectedly'))
308 raise IOError(None, _('connection ended unexpectedly'))
312 yield zd.flush()
309 yield zd.flush()
313
310
314 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
311 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
315
312
316 def changegroupsubset(self, bases, heads, source):
313 def changegroupsubset(self, bases, heads, source):
317 baselst = " ".join([hex(n) for n in bases])
314 baselst = " ".join([hex(n) for n in bases])
318 headlst = " ".join([hex(n) for n in heads])
315 headlst = " ".join([hex(n) for n in heads])
319 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
316 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
320
317
321 def zgenerator(f):
318 def zgenerator(f):
322 zd = zlib.decompressobj()
319 zd = zlib.decompressobj()
323 try:
320 try:
324 for chnk in f:
321 for chnk in f:
325 yield zd.decompress(chnk)
322 yield zd.decompress(chnk)
326 except httplib.HTTPException:
323 except httplib.HTTPException:
327 raise IOError(None, _('connection ended unexpectedly'))
324 raise IOError(None, _('connection ended unexpectedly'))
328 yield zd.flush()
325 yield zd.flush()
329
326
330 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
327 return util.chunkbuffer(zgenerator(util.filechunkiter(f)))
331
328
332 def unbundle(self, cg, heads, source):
329 def unbundle(self, cg, heads, source):
333 # have to stream bundle to a temp file because we do not have
330 # have to stream bundle to a temp file because we do not have
334 # http 1.1 chunked transfer.
331 # http 1.1 chunked transfer.
335
332
336 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
333 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
337 fp = os.fdopen(fd, 'wb+')
334 fp = os.fdopen(fd, 'wb+')
338 try:
335 try:
339 for chunk in util.filechunkiter(cg):
336 for chunk in util.filechunkiter(cg):
340 fp.write(chunk)
337 fp.write(chunk)
341 length = fp.tell()
338 length = fp.tell()
342 try:
339 try:
343 rfp = self.do_cmd(
340 rfp = self.do_cmd(
344 'unbundle', data=fp,
341 'unbundle', data=fp,
345 headers={'content-length': length,
342 headers={'content-length': length,
346 'content-type': 'application/octet-stream'},
343 'content-type': 'application/octet-stream'},
347 heads=' '.join(map(hex, heads)))
344 heads=' '.join(map(hex, heads)))
348 try:
345 try:
349 ret = int(rfp.readline())
346 ret = int(rfp.readline())
350 self.ui.write(rfp.read())
347 self.ui.write(rfp.read())
351 return ret
348 return ret
352 finally:
349 finally:
353 rfp.close()
350 rfp.close()
354 except socket.error, err:
351 except socket.error, err:
355 if err[0] in (errno.ECONNRESET, errno.EPIPE):
352 if err[0] in (errno.ECONNRESET, errno.EPIPE):
356 raise util.Abort(_('push failed: %s') % err[1])
353 raise util.Abort(_('push failed: %s') % err[1])
357 raise util.Abort(err[1])
354 raise util.Abort(err[1])
358 finally:
355 finally:
359 fp.close()
356 fp.close()
360 os.unlink(tempname)
357 os.unlink(tempname)
361
358
362 def stream_out(self):
359 def stream_out(self):
363 return self.do_cmd('stream_out')
360 return self.do_cmd('stream_out')
364
361
365 class httpsrepository(httprepository):
362 class httpsrepository(httprepository):
366 def __init__(self, ui, path):
363 def __init__(self, ui, path):
367 if not has_https:
364 if not has_https:
368 raise util.Abort(_('Python support for SSL and HTTPS '
365 raise util.Abort(_('Python support for SSL and HTTPS '
369 'is not installed'))
366 'is not installed'))
370 httprepository.__init__(self, ui, path)
367 httprepository.__init__(self, ui, path)
371
368
372 def instance(ui, path, create):
369 def instance(ui, path, create):
373 if create:
370 if create:
374 raise util.Abort(_('cannot create new http repository'))
371 raise util.Abort(_('cannot create new http repository'))
375 if path.startswith('hg:'):
372 if path.startswith('hg:'):
376 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
373 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
377 path = 'http:' + path[3:]
374 path = 'http:' + path[3:]
378 if path.startswith('https:'):
375 if path.startswith('https:'):
379 return httpsrepository(ui, path)
376 return httpsrepository(ui, path)
380 return httprepository(ui, path)
377 return httprepository(ui, path)
General Comments 0
You need to be logged in to leave comments. Login now