##// END OF EJS Templates
fix push over HTTP to older servers
Alexis S. L. Carvalho -
r3703:e674cae8 default
parent child Browse files
Show More
@@ -1,379 +1,385
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 changegroup")
14 demandload(globals(), "errno keepalive tempfile socket changegroup")
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 def zgenerator(f):
117 def zgenerator(f):
118 zd = zlib.decompressobj()
118 zd = zlib.decompressobj()
119 try:
119 try:
120 for chunk in util.filechunkiter(f):
120 for chunk in util.filechunkiter(f):
121 yield zd.decompress(chunk)
121 yield zd.decompress(chunk)
122 except httplib.HTTPException, inst:
122 except httplib.HTTPException, inst:
123 raise IOError(None, _('connection ended unexpectedly'))
123 raise IOError(None, _('connection ended unexpectedly'))
124 yield zd.flush()
124 yield zd.flush()
125
125
126 class httprepository(remoterepository):
126 class httprepository(remoterepository):
127 def __init__(self, ui, path):
127 def __init__(self, ui, path):
128 self.path = path
128 self.path = path
129 self.caps = None
129 self.caps = None
130 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
130 scheme, netloc, urlpath, query, frag = urlparse.urlsplit(path)
131 if query or frag:
131 if query or frag:
132 raise util.Abort(_('unsupported URL component: "%s"') %
132 raise util.Abort(_('unsupported URL component: "%s"') %
133 (query or frag))
133 (query or frag))
134 if not urlpath: urlpath = '/'
134 if not urlpath: urlpath = '/'
135 host, port, user, passwd = netlocsplit(netloc)
135 host, port, user, passwd = netlocsplit(netloc)
136
136
137 # urllib cannot handle URLs with embedded user or passwd
137 # urllib cannot handle URLs with embedded user or passwd
138 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
138 self._url = urlparse.urlunsplit((scheme, netlocunsplit(host, port),
139 urlpath, '', ''))
139 urlpath, '', ''))
140 self.ui = ui
140 self.ui = ui
141
141
142 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
142 proxyurl = ui.config("http_proxy", "host") or os.getenv('http_proxy')
143 # XXX proxyauthinfo = None
143 # XXX proxyauthinfo = None
144 handlers = [httphandler()]
144 handlers = [httphandler()]
145
145
146 if proxyurl:
146 if proxyurl:
147 # proxy can be proper url or host[:port]
147 # proxy can be proper url or host[:port]
148 if not (proxyurl.startswith('http:') or
148 if not (proxyurl.startswith('http:') or
149 proxyurl.startswith('https:')):
149 proxyurl.startswith('https:')):
150 proxyurl = 'http://' + proxyurl + '/'
150 proxyurl = 'http://' + proxyurl + '/'
151 snpqf = urlparse.urlsplit(proxyurl)
151 snpqf = urlparse.urlsplit(proxyurl)
152 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
152 proxyscheme, proxynetloc, proxypath, proxyquery, proxyfrag = snpqf
153 hpup = netlocsplit(proxynetloc)
153 hpup = netlocsplit(proxynetloc)
154
154
155 proxyhost, proxyport, proxyuser, proxypasswd = hpup
155 proxyhost, proxyport, proxyuser, proxypasswd = hpup
156 if not proxyuser:
156 if not proxyuser:
157 proxyuser = ui.config("http_proxy", "user")
157 proxyuser = ui.config("http_proxy", "user")
158 proxypasswd = ui.config("http_proxy", "passwd")
158 proxypasswd = ui.config("http_proxy", "passwd")
159
159
160 # see if we should use a proxy for this url
160 # see if we should use a proxy for this url
161 no_list = [ "localhost", "127.0.0.1" ]
161 no_list = [ "localhost", "127.0.0.1" ]
162 no_list.extend([p.lower() for
162 no_list.extend([p.lower() for
163 p in ui.configlist("http_proxy", "no")])
163 p in ui.configlist("http_proxy", "no")])
164 no_list.extend([p.strip().lower() for
164 no_list.extend([p.strip().lower() for
165 p in os.getenv("no_proxy", '').split(',')
165 p in os.getenv("no_proxy", '').split(',')
166 if p.strip()])
166 if p.strip()])
167 # "http_proxy.always" config is for running tests on localhost
167 # "http_proxy.always" config is for running tests on localhost
168 if (not ui.configbool("http_proxy", "always") and
168 if (not ui.configbool("http_proxy", "always") and
169 host.lower() in no_list):
169 host.lower() in no_list):
170 ui.debug(_('disabling proxy for %s\n') % host)
170 ui.debug(_('disabling proxy for %s\n') % host)
171 else:
171 else:
172 proxyurl = urlparse.urlunsplit((
172 proxyurl = urlparse.urlunsplit((
173 proxyscheme, netlocunsplit(proxyhost, proxyport,
173 proxyscheme, netlocunsplit(proxyhost, proxyport,
174 proxyuser, proxypasswd or ''),
174 proxyuser, proxypasswd or ''),
175 proxypath, proxyquery, proxyfrag))
175 proxypath, proxyquery, proxyfrag))
176 handlers.append(urllib2.ProxyHandler({scheme: proxyurl}))
176 handlers.append(urllib2.ProxyHandler({scheme: proxyurl}))
177 ui.debug(_('proxying through http://%s:%s\n') %
177 ui.debug(_('proxying through http://%s:%s\n') %
178 (proxyhost, proxyport))
178 (proxyhost, proxyport))
179
179
180 # urllib2 takes proxy values from the environment and those
180 # urllib2 takes proxy values from the environment and those
181 # will take precedence if found, so drop them
181 # will take precedence if found, so drop them
182 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
182 for env in ["HTTP_PROXY", "http_proxy", "no_proxy"]:
183 try:
183 try:
184 if os.environ.has_key(env):
184 if os.environ.has_key(env):
185 del os.environ[env]
185 del os.environ[env]
186 except OSError:
186 except OSError:
187 pass
187 pass
188
188
189 passmgr = passwordmgr(ui)
189 passmgr = passwordmgr(ui)
190 if user:
190 if user:
191 ui.debug(_('http auth: user %s, password %s\n') %
191 ui.debug(_('http auth: user %s, password %s\n') %
192 (user, passwd and '*' * len(passwd) or 'not set'))
192 (user, passwd and '*' * len(passwd) or 'not set'))
193 passmgr.add_password(None, host, user, passwd or '')
193 passmgr.add_password(None, host, user, passwd or '')
194
194
195 handlers.extend((urllib2.HTTPBasicAuthHandler(passmgr),
195 handlers.extend((urllib2.HTTPBasicAuthHandler(passmgr),
196 urllib2.HTTPDigestAuthHandler(passmgr)))
196 urllib2.HTTPDigestAuthHandler(passmgr)))
197 opener = urllib2.build_opener(*handlers)
197 opener = urllib2.build_opener(*handlers)
198
198
199 # 1.0 here is the _protocol_ version
199 # 1.0 here is the _protocol_ version
200 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
200 opener.addheaders = [('User-agent', 'mercurial/proto-1.0')]
201 urllib2.install_opener(opener)
201 urllib2.install_opener(opener)
202
202
203 def url(self):
203 def url(self):
204 return self.path
204 return self.path
205
205
206 # look up capabilities only when needed
206 # look up capabilities only when needed
207
207
208 def get_caps(self):
208 def get_caps(self):
209 if self.caps is None:
209 if self.caps is None:
210 try:
210 try:
211 self.caps = self.do_read('capabilities').split()
211 self.caps = self.do_read('capabilities').split()
212 except hg.RepoError:
212 except hg.RepoError:
213 self.caps = ()
213 self.caps = ()
214 self.ui.debug(_('capabilities: %s\n') %
214 self.ui.debug(_('capabilities: %s\n') %
215 (' '.join(self.caps or ['none'])))
215 (' '.join(self.caps or ['none'])))
216 return self.caps
216 return self.caps
217
217
218 capabilities = property(get_caps)
218 capabilities = property(get_caps)
219
219
220 def lock(self):
220 def lock(self):
221 raise util.Abort(_('operation not supported over http'))
221 raise util.Abort(_('operation not supported over http'))
222
222
223 def do_cmd(self, cmd, **args):
223 def do_cmd(self, cmd, **args):
224 data = args.pop('data', None)
224 data = args.pop('data', None)
225 headers = args.pop('headers', {})
225 headers = args.pop('headers', {})
226 self.ui.debug(_("sending %s command\n") % cmd)
226 self.ui.debug(_("sending %s command\n") % cmd)
227 q = {"cmd": cmd}
227 q = {"cmd": cmd}
228 q.update(args)
228 q.update(args)
229 qs = '?%s' % urllib.urlencode(q)
229 qs = '?%s' % urllib.urlencode(q)
230 cu = "%s%s" % (self._url, qs)
230 cu = "%s%s" % (self._url, qs)
231 try:
231 try:
232 if data:
232 if data:
233 self.ui.debug(_("sending %s bytes\n") %
233 self.ui.debug(_("sending %s bytes\n") %
234 headers.get('content-length', 'X'))
234 headers.get('content-length', 'X'))
235 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
235 resp = urllib2.urlopen(urllib2.Request(cu, data, headers))
236 except urllib2.HTTPError, inst:
236 except urllib2.HTTPError, inst:
237 if inst.code == 401:
237 if inst.code == 401:
238 raise util.Abort(_('authorization failed'))
238 raise util.Abort(_('authorization failed'))
239 raise
239 raise
240 except httplib.HTTPException, inst:
240 except httplib.HTTPException, inst:
241 self.ui.debug(_('http error while sending %s command\n') % cmd)
241 self.ui.debug(_('http error while sending %s command\n') % cmd)
242 self.ui.print_exc()
242 self.ui.print_exc()
243 raise IOError(None, inst)
243 raise IOError(None, inst)
244 except IndexError:
244 except IndexError:
245 # this only happens with Python 2.3, later versions raise URLError
245 # this only happens with Python 2.3, later versions raise URLError
246 raise util.Abort(_('http error, possibly caused by proxy setting'))
246 raise util.Abort(_('http error, possibly caused by proxy setting'))
247 # record the url we got redirected to
247 # record the url we got redirected to
248 resp_url = resp.geturl()
248 resp_url = resp.geturl()
249 if resp_url.endswith(qs):
249 if resp_url.endswith(qs):
250 resp_url = resp_url[:-len(qs)]
250 resp_url = resp_url[:-len(qs)]
251 if self._url != resp_url:
251 if self._url != resp_url:
252 self.ui.status(_('real URL is %s\n') % resp_url)
252 self.ui.status(_('real URL is %s\n') % resp_url)
253 self._url = resp_url
253 self._url = resp_url
254 try:
254 try:
255 proto = resp.getheader('content-type')
255 proto = resp.getheader('content-type')
256 except AttributeError:
256 except AttributeError:
257 proto = resp.headers['content-type']
257 proto = resp.headers['content-type']
258
258
259 # accept old "text/plain" and "application/hg-changegroup" for now
259 # accept old "text/plain" and "application/hg-changegroup" for now
260 if not proto.startswith('application/mercurial') and \
260 if not proto.startswith('application/mercurial') and \
261 not proto.startswith('text/plain') and \
261 not proto.startswith('text/plain') and \
262 not proto.startswith('application/hg-changegroup'):
262 not proto.startswith('application/hg-changegroup'):
263 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
263 raise hg.RepoError(_("'%s' does not appear to be an hg repository") %
264 self._url)
264 self._url)
265
265
266 if proto.startswith('application/mercurial'):
266 if proto.startswith('application/mercurial'):
267 version = proto[22:]
267 version = proto[22:]
268 if float(version) > 0.1:
268 if float(version) > 0.1:
269 raise hg.RepoError(_("'%s' uses newer protocol %s") %
269 raise hg.RepoError(_("'%s' uses newer protocol %s") %
270 (self._url, version))
270 (self._url, version))
271
271
272 return resp
272 return resp
273
273
274 def do_read(self, cmd, **args):
274 def do_read(self, cmd, **args):
275 fp = self.do_cmd(cmd, **args)
275 fp = self.do_cmd(cmd, **args)
276 try:
276 try:
277 return fp.read()
277 return fp.read()
278 finally:
278 finally:
279 # if using keepalive, allow connection to be reused
279 # if using keepalive, allow connection to be reused
280 fp.close()
280 fp.close()
281
281
282 def lookup(self, key):
282 def lookup(self, key):
283 d = self.do_cmd("lookup", key = key).read()
283 d = self.do_cmd("lookup", key = key).read()
284 success, data = d[:-1].split(' ', 1)
284 success, data = d[:-1].split(' ', 1)
285 if int(success):
285 if int(success):
286 return bin(data)
286 return bin(data)
287 raise hg.RepoError(data)
287 raise hg.RepoError(data)
288
288
289 def heads(self):
289 def heads(self):
290 d = self.do_read("heads")
290 d = self.do_read("heads")
291 try:
291 try:
292 return map(bin, d[:-1].split(" "))
292 return map(bin, d[:-1].split(" "))
293 except:
293 except:
294 raise util.UnexpectedOutput(_("unexpected response:"), d)
294 raise util.UnexpectedOutput(_("unexpected response:"), d)
295
295
296 def branches(self, nodes):
296 def branches(self, nodes):
297 n = " ".join(map(hex, nodes))
297 n = " ".join(map(hex, nodes))
298 d = self.do_read("branches", nodes=n)
298 d = self.do_read("branches", nodes=n)
299 try:
299 try:
300 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
300 br = [ tuple(map(bin, b.split(" "))) for b in d.splitlines() ]
301 return br
301 return br
302 except:
302 except:
303 raise util.UnexpectedOutput(_("unexpected response:"), d)
303 raise util.UnexpectedOutput(_("unexpected response:"), d)
304
304
305 def between(self, pairs):
305 def between(self, pairs):
306 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
306 n = "\n".join(["-".join(map(hex, p)) for p in pairs])
307 d = self.do_read("between", pairs=n)
307 d = self.do_read("between", pairs=n)
308 try:
308 try:
309 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
309 p = [ l and map(bin, l.split(" ")) or [] for l in d.splitlines() ]
310 return p
310 return p
311 except:
311 except:
312 raise util.UnexpectedOutput(_("unexpected response:"), d)
312 raise util.UnexpectedOutput(_("unexpected response:"), d)
313
313
314 def changegroup(self, nodes, kind):
314 def changegroup(self, nodes, kind):
315 n = " ".join(map(hex, nodes))
315 n = " ".join(map(hex, nodes))
316 f = self.do_cmd("changegroup", roots=n)
316 f = self.do_cmd("changegroup", roots=n)
317 return util.chunkbuffer(zgenerator(f))
317 return util.chunkbuffer(zgenerator(f))
318
318
319 def changegroupsubset(self, bases, heads, source):
319 def changegroupsubset(self, bases, heads, source):
320 baselst = " ".join([hex(n) for n in bases])
320 baselst = " ".join([hex(n) for n in bases])
321 headlst = " ".join([hex(n) for n in heads])
321 headlst = " ".join([hex(n) for n in heads])
322 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
322 f = self.do_cmd("changegroupsubset", bases=baselst, heads=headlst)
323 return util.chunkbuffer(zgenerator(f))
323 return util.chunkbuffer(zgenerator(f))
324
324
325 def unbundle(self, cg, heads, source):
325 def unbundle(self, cg, heads, source):
326 # have to stream bundle to a temp file because we do not have
326 # have to stream bundle to a temp file because we do not have
327 # http 1.1 chunked transfer.
327 # http 1.1 chunked transfer.
328
328
329 type = ""
329 type = ""
330 types = self.capable('unbundle')
330 types = self.capable('unbundle')
331 # servers older than d1b16a746db6 will send 'unbundle' as a
332 # boolean capability
333 try:
334 types = types.split(',')
335 except AttributeError:
336 types = [""]
331 if types:
337 if types:
332 for x in types.split(','):
338 for x in types:
333 if x in changegroup.bundletypes:
339 if x in changegroup.bundletypes:
334 type = x
340 type = x
335 break
341 break
336
342
337 tempname = changegroup.writebundle(cg, None, type)
343 tempname = changegroup.writebundle(cg, None, type)
338 fp = file(tempname, "rb")
344 fp = file(tempname, "rb")
339 try:
345 try:
340 length = os.stat(tempname).st_size
346 length = os.stat(tempname).st_size
341 try:
347 try:
342 rfp = self.do_cmd(
348 rfp = self.do_cmd(
343 'unbundle', data=fp,
349 'unbundle', data=fp,
344 headers={'content-length': str(length),
350 headers={'content-length': str(length),
345 'content-type': 'application/octet-stream'},
351 'content-type': 'application/octet-stream'},
346 heads=' '.join(map(hex, heads)))
352 heads=' '.join(map(hex, heads)))
347 try:
353 try:
348 ret = int(rfp.readline())
354 ret = int(rfp.readline())
349 self.ui.write(rfp.read())
355 self.ui.write(rfp.read())
350 return ret
356 return ret
351 finally:
357 finally:
352 rfp.close()
358 rfp.close()
353 except socket.error, err:
359 except socket.error, err:
354 if err[0] in (errno.ECONNRESET, errno.EPIPE):
360 if err[0] in (errno.ECONNRESET, errno.EPIPE):
355 raise util.Abort(_('push failed: %s') % err[1])
361 raise util.Abort(_('push failed: %s') % err[1])
356 raise util.Abort(err[1])
362 raise util.Abort(err[1])
357 finally:
363 finally:
358 fp.close()
364 fp.close()
359 os.unlink(tempname)
365 os.unlink(tempname)
360
366
361 def stream_out(self):
367 def stream_out(self):
362 return self.do_cmd('stream_out')
368 return self.do_cmd('stream_out')
363
369
364 class httpsrepository(httprepository):
370 class httpsrepository(httprepository):
365 def __init__(self, ui, path):
371 def __init__(self, ui, path):
366 if not has_https:
372 if not has_https:
367 raise util.Abort(_('Python support for SSL and HTTPS '
373 raise util.Abort(_('Python support for SSL and HTTPS '
368 'is not installed'))
374 'is not installed'))
369 httprepository.__init__(self, ui, path)
375 httprepository.__init__(self, ui, path)
370
376
371 def instance(ui, path, create):
377 def instance(ui, path, create):
372 if create:
378 if create:
373 raise util.Abort(_('cannot create new http repository'))
379 raise util.Abort(_('cannot create new http repository'))
374 if path.startswith('hg:'):
380 if path.startswith('hg:'):
375 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
381 ui.warn(_("hg:// syntax is deprecated, please use http:// instead\n"))
376 path = 'http:' + path[3:]
382 path = 'http:' + path[3:]
377 if path.startswith('https:'):
383 if path.startswith('https:'):
378 return httpsrepository(ui, path)
384 return httpsrepository(ui, path)
379 return httprepository(ui, path)
385 return httprepository(ui, path)
General Comments 0
You need to be logged in to leave comments. Login now