Mercurial > public > mercurial-scm > hg
comparison mercurial/httppeer.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | c59eb1560c44 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
60 # Note: it is *NOT* a bug that the last bit here is a bytestring | 60 # Note: it is *NOT* a bug that the last bit here is a bytestring |
61 # and not a unicode: we're just getting the encoded length anyway, | 61 # and not a unicode: we're just getting the encoded length anyway, |
62 # and using an r-string to make it portable between Python 2 and 3 | 62 # and using an r-string to make it portable between Python 2 and 3 |
63 # doesn't work because then the \r is a literal backslash-r | 63 # doesn't work because then the \r is a literal backslash-r |
64 # instead of a carriage return. | 64 # instead of a carriage return. |
65 valuelen = limit - len(fmt % r'000') - len(': \r\n') | 65 valuelen = limit - len(fmt % r'000') - len(b': \r\n') |
66 result = [] | 66 result = [] |
67 | 67 |
68 n = 0 | 68 n = 0 |
69 for i in pycompat.xrange(0, len(value), valuelen): | 69 for i in pycompat.xrange(0, len(value), valuelen): |
70 n += 1 | 70 n += 1 |
74 | 74 |
75 | 75 |
76 class _multifile(object): | 76 class _multifile(object): |
77 def __init__(self, *fileobjs): | 77 def __init__(self, *fileobjs): |
78 for f in fileobjs: | 78 for f in fileobjs: |
79 if not util.safehasattr(f, 'length'): | 79 if not util.safehasattr(f, b'length'): |
80 raise ValueError( | 80 raise ValueError( |
81 '_multifile only supports file objects that ' | 81 b'_multifile only supports file objects that ' |
82 'have a length but this one does not:', | 82 b'have a length but this one does not:', |
83 type(f), | 83 type(f), |
84 f, | 84 f, |
85 ) | 85 ) |
86 self._fileobjs = fileobjs | 86 self._fileobjs = fileobjs |
87 self._index = 0 | 87 self._index = 0 |
90 def length(self): | 90 def length(self): |
91 return sum(f.length for f in self._fileobjs) | 91 return sum(f.length for f in self._fileobjs) |
92 | 92 |
93 def read(self, amt=None): | 93 def read(self, amt=None): |
94 if amt <= 0: | 94 if amt <= 0: |
95 return ''.join(f.read() for f in self._fileobjs) | 95 return b''.join(f.read() for f in self._fileobjs) |
96 parts = [] | 96 parts = [] |
97 while amt and self._index < len(self._fileobjs): | 97 while amt and self._index < len(self._fileobjs): |
98 parts.append(self._fileobjs[self._index].read(amt)) | 98 parts.append(self._fileobjs[self._index].read(amt)) |
99 got = len(parts[-1]) | 99 got = len(parts[-1]) |
100 if got < amt: | 100 if got < amt: |
101 self._index += 1 | 101 self._index += 1 |
102 amt -= got | 102 amt -= got |
103 return ''.join(parts) | 103 return b''.join(parts) |
104 | 104 |
105 def seek(self, offset, whence=os.SEEK_SET): | 105 def seek(self, offset, whence=os.SEEK_SET): |
106 if whence != os.SEEK_SET: | 106 if whence != os.SEEK_SET: |
107 raise NotImplementedError( | 107 raise NotImplementedError( |
108 '_multifile does not support anything other' | 108 b'_multifile does not support anything other' |
109 ' than os.SEEK_SET for whence on seek()' | 109 b' than os.SEEK_SET for whence on seek()' |
110 ) | 110 ) |
111 if offset != 0: | 111 if offset != 0: |
112 raise NotImplementedError( | 112 raise NotImplementedError( |
113 '_multifile only supports seeking to start, but that ' | 113 b'_multifile only supports seeking to start, but that ' |
114 'could be fixed if you need it' | 114 b'could be fixed if you need it' |
115 ) | 115 ) |
116 for f in self._fileobjs: | 116 for f in self._fileobjs: |
117 f.seek(0) | 117 f.seek(0) |
118 self._index = 0 | 118 self._index = 0 |
119 | 119 |
129 ``capablefn`` is a function to evaluate a capability. | 129 ``capablefn`` is a function to evaluate a capability. |
130 | 130 |
131 ``cmd``, ``args``, and ``data`` define the command, its arguments, and | 131 ``cmd``, ``args``, and ``data`` define the command, its arguments, and |
132 raw data to pass to it. | 132 raw data to pass to it. |
133 """ | 133 """ |
134 if cmd == 'pushkey': | 134 if cmd == b'pushkey': |
135 args['data'] = '' | 135 args[b'data'] = b'' |
136 data = args.pop('data', None) | 136 data = args.pop(b'data', None) |
137 headers = args.pop('headers', {}) | 137 headers = args.pop(b'headers', {}) |
138 | 138 |
139 ui.debug("sending %s command\n" % cmd) | 139 ui.debug(b"sending %s command\n" % cmd) |
140 q = [('cmd', cmd)] | 140 q = [(b'cmd', cmd)] |
141 headersize = 0 | 141 headersize = 0 |
142 # Important: don't use self.capable() here or else you end up | 142 # Important: don't use self.capable() here or else you end up |
143 # with infinite recursion when trying to look up capabilities | 143 # with infinite recursion when trying to look up capabilities |
144 # for the first time. | 144 # for the first time. |
145 postargsok = caps is not None and 'httppostargs' in caps | 145 postargsok = caps is not None and b'httppostargs' in caps |
146 | 146 |
147 # Send arguments via POST. | 147 # Send arguments via POST. |
148 if postargsok and args: | 148 if postargsok and args: |
149 strargs = urlreq.urlencode(sorted(args.items())) | 149 strargs = urlreq.urlencode(sorted(args.items())) |
150 if not data: | 150 if not data: |
160 headers[r'X-HgArgs-Post'] = len(strargs) | 160 headers[r'X-HgArgs-Post'] = len(strargs) |
161 elif args: | 161 elif args: |
162 # Calling self.capable() can infinite loop if we are calling | 162 # Calling self.capable() can infinite loop if we are calling |
163 # "capabilities". But that command should never accept wire | 163 # "capabilities". But that command should never accept wire |
164 # protocol arguments. So this should never happen. | 164 # protocol arguments. So this should never happen. |
165 assert cmd != 'capabilities' | 165 assert cmd != b'capabilities' |
166 httpheader = capablefn('httpheader') | 166 httpheader = capablefn(b'httpheader') |
167 if httpheader: | 167 if httpheader: |
168 headersize = int(httpheader.split(',', 1)[0]) | 168 headersize = int(httpheader.split(b',', 1)[0]) |
169 | 169 |
170 # Send arguments via HTTP headers. | 170 # Send arguments via HTTP headers. |
171 if headersize > 0: | 171 if headersize > 0: |
172 # The headers can typically carry more data than the URL. | 172 # The headers can typically carry more data than the URL. |
173 encargs = urlreq.urlencode(sorted(args.items())) | 173 encargs = urlreq.urlencode(sorted(args.items())) |
174 for header, value in encodevalueinheaders( | 174 for header, value in encodevalueinheaders( |
175 encargs, 'X-HgArg', headersize | 175 encargs, b'X-HgArg', headersize |
176 ): | 176 ): |
177 headers[header] = value | 177 headers[header] = value |
178 # Send arguments via query string (Mercurial <1.9). | 178 # Send arguments via query string (Mercurial <1.9). |
179 else: | 179 else: |
180 q += sorted(args.items()) | 180 q += sorted(args.items()) |
181 | 181 |
182 qs = '?%s' % urlreq.urlencode(q) | 182 qs = b'?%s' % urlreq.urlencode(q) |
183 cu = "%s%s" % (repobaseurl, qs) | 183 cu = b"%s%s" % (repobaseurl, qs) |
184 size = 0 | 184 size = 0 |
185 if util.safehasattr(data, 'length'): | 185 if util.safehasattr(data, b'length'): |
186 size = data.length | 186 size = data.length |
187 elif data is not None: | 187 elif data is not None: |
188 size = len(data) | 188 size = len(data) |
189 if data is not None and r'Content-Type' not in headers: | 189 if data is not None and r'Content-Type' not in headers: |
190 headers[r'Content-Type'] = r'application/mercurial-0.1' | 190 headers[r'Content-Type'] = r'application/mercurial-0.1' |
196 # protocol parameters should only occur after the handshake. | 196 # protocol parameters should only occur after the handshake. |
197 protoparams = set() | 197 protoparams = set() |
198 | 198 |
199 mediatypes = set() | 199 mediatypes = set() |
200 if caps is not None: | 200 if caps is not None: |
201 mt = capablefn('httpmediatype') | 201 mt = capablefn(b'httpmediatype') |
202 if mt: | 202 if mt: |
203 protoparams.add('0.1') | 203 protoparams.add(b'0.1') |
204 mediatypes = set(mt.split(',')) | 204 mediatypes = set(mt.split(b',')) |
205 | 205 |
206 protoparams.add('partial-pull') | 206 protoparams.add(b'partial-pull') |
207 | 207 |
208 if '0.2tx' in mediatypes: | 208 if b'0.2tx' in mediatypes: |
209 protoparams.add('0.2') | 209 protoparams.add(b'0.2') |
210 | 210 |
211 if '0.2tx' in mediatypes and capablefn('compression'): | 211 if b'0.2tx' in mediatypes and capablefn(b'compression'): |
212 # We /could/ compare supported compression formats and prune | 212 # We /could/ compare supported compression formats and prune |
213 # non-mutually supported or error if nothing is mutually supported. | 213 # non-mutually supported or error if nothing is mutually supported. |
214 # For now, send the full list to the server and have it error. | 214 # For now, send the full list to the server and have it error. |
215 comps = [ | 215 comps = [ |
216 e.wireprotosupport().name | 216 e.wireprotosupport().name |
217 for e in util.compengines.supportedwireengines(util.CLIENTROLE) | 217 for e in util.compengines.supportedwireengines(util.CLIENTROLE) |
218 ] | 218 ] |
219 protoparams.add('comp=%s' % ','.join(comps)) | 219 protoparams.add(b'comp=%s' % b','.join(comps)) |
220 | 220 |
221 if protoparams: | 221 if protoparams: |
222 protoheaders = encodevalueinheaders( | 222 protoheaders = encodevalueinheaders( |
223 ' '.join(sorted(protoparams)), 'X-HgProto', headersize or 1024 | 223 b' '.join(sorted(protoparams)), b'X-HgProto', headersize or 1024 |
224 ) | 224 ) |
225 for header, value in protoheaders: | 225 for header, value in protoheaders: |
226 headers[header] = value | 226 headers[header] = value |
227 | 227 |
228 varyheaders = [] | 228 varyheaders = [] |
234 headers[r'Vary'] = r','.join(sorted(varyheaders)) | 234 headers[r'Vary'] = r','.join(sorted(varyheaders)) |
235 | 235 |
236 req = requestbuilder(pycompat.strurl(cu), data, headers) | 236 req = requestbuilder(pycompat.strurl(cu), data, headers) |
237 | 237 |
238 if data is not None: | 238 if data is not None: |
239 ui.debug("sending %d bytes\n" % size) | 239 ui.debug(b"sending %d bytes\n" % size) |
240 req.add_unredirected_header(r'Content-Length', r'%d' % size) | 240 req.add_unredirected_header(r'Content-Length', r'%d' % size) |
241 | 241 |
242 return req, cu, qs | 242 return req, cu, qs |
243 | 243 |
244 | 244 |
255 """Send a prepared HTTP request. | 255 """Send a prepared HTTP request. |
256 | 256 |
257 Returns the response object. | 257 Returns the response object. |
258 """ | 258 """ |
259 dbg = ui.debug | 259 dbg = ui.debug |
260 if ui.debugflag and ui.configbool('devel', 'debug.peer-request'): | 260 if ui.debugflag and ui.configbool(b'devel', b'debug.peer-request'): |
261 line = 'devel-peer-request: %s\n' | 261 line = b'devel-peer-request: %s\n' |
262 dbg( | 262 dbg( |
263 line | 263 line |
264 % '%s %s' | 264 % b'%s %s' |
265 % ( | 265 % ( |
266 pycompat.bytesurl(req.get_method()), | 266 pycompat.bytesurl(req.get_method()), |
267 pycompat.bytesurl(req.get_full_url()), | 267 pycompat.bytesurl(req.get_full_url()), |
268 ) | 268 ) |
269 ) | 269 ) |
270 hgargssize = None | 270 hgargssize = None |
271 | 271 |
272 for header, value in sorted(req.header_items()): | 272 for header, value in sorted(req.header_items()): |
273 header = pycompat.bytesurl(header) | 273 header = pycompat.bytesurl(header) |
274 value = pycompat.bytesurl(value) | 274 value = pycompat.bytesurl(value) |
275 if header.startswith('X-hgarg-'): | 275 if header.startswith(b'X-hgarg-'): |
276 if hgargssize is None: | 276 if hgargssize is None: |
277 hgargssize = 0 | 277 hgargssize = 0 |
278 hgargssize += len(value) | 278 hgargssize += len(value) |
279 else: | 279 else: |
280 dbg(line % ' %s %s' % (header, value)) | 280 dbg(line % b' %s %s' % (header, value)) |
281 | 281 |
282 if hgargssize is not None: | 282 if hgargssize is not None: |
283 dbg( | 283 dbg( |
284 line | 284 line |
285 % ' %d bytes of commands arguments in headers' | 285 % b' %d bytes of commands arguments in headers' |
286 % hgargssize | 286 % hgargssize |
287 ) | 287 ) |
288 data = _reqdata(req) | 288 data = _reqdata(req) |
289 if data is not None: | 289 if data is not None: |
290 length = getattr(data, 'length', None) | 290 length = getattr(data, 'length', None) |
291 if length is None: | 291 if length is None: |
292 length = len(data) | 292 length = len(data) |
293 dbg(line % ' %d bytes of data' % length) | 293 dbg(line % b' %d bytes of data' % length) |
294 | 294 |
295 start = util.timer() | 295 start = util.timer() |
296 | 296 |
297 res = None | 297 res = None |
298 try: | 298 try: |
299 res = opener.open(req) | 299 res = opener.open(req) |
300 except urlerr.httperror as inst: | 300 except urlerr.httperror as inst: |
301 if inst.code == 401: | 301 if inst.code == 401: |
302 raise error.Abort(_('authorization failed')) | 302 raise error.Abort(_(b'authorization failed')) |
303 raise | 303 raise |
304 except httplib.HTTPException as inst: | 304 except httplib.HTTPException as inst: |
305 ui.debug( | 305 ui.debug( |
306 'http error requesting %s\n' % util.hidepassword(req.get_full_url()) | 306 b'http error requesting %s\n' |
307 % util.hidepassword(req.get_full_url()) | |
307 ) | 308 ) |
308 ui.traceback() | 309 ui.traceback() |
309 raise IOError(None, inst) | 310 raise IOError(None, inst) |
310 finally: | 311 finally: |
311 if ui.debugflag and ui.configbool('devel', 'debug.peer-request'): | 312 if ui.debugflag and ui.configbool(b'devel', b'debug.peer-request'): |
312 code = res.code if res else -1 | 313 code = res.code if res else -1 |
313 dbg( | 314 dbg( |
314 line | 315 line |
315 % ' finished in %.4f seconds (%d)' | 316 % b' finished in %.4f seconds (%d)' |
316 % (util.timer() - start, code) | 317 % (util.timer() - start, code) |
317 ) | 318 ) |
318 | 319 |
319 # Insert error handlers for common I/O failures. | 320 # Insert error handlers for common I/O failures. |
320 urlmod.wrapresponse(res) | 321 urlmod.wrapresponse(res) |
338 respurl = respurl[: -len(qs)] | 339 respurl = respurl[: -len(qs)] |
339 qsdropped = False | 340 qsdropped = False |
340 else: | 341 else: |
341 qsdropped = True | 342 qsdropped = True |
342 | 343 |
343 if baseurl.rstrip('/') != respurl.rstrip('/'): | 344 if baseurl.rstrip(b'/') != respurl.rstrip(b'/'): |
344 redirected = True | 345 redirected = True |
345 if not ui.quiet: | 346 if not ui.quiet: |
346 ui.warn(_('real URL is %s\n') % respurl) | 347 ui.warn(_(b'real URL is %s\n') % respurl) |
347 | 348 |
348 try: | 349 try: |
349 proto = pycompat.bytesurl(resp.getheader(r'content-type', r'')) | 350 proto = pycompat.bytesurl(resp.getheader(r'content-type', r'')) |
350 except AttributeError: | 351 except AttributeError: |
351 proto = pycompat.bytesurl(resp.headers.get(r'content-type', r'')) | 352 proto = pycompat.bytesurl(resp.headers.get(r'content-type', r'')) |
352 | 353 |
353 safeurl = util.hidepassword(baseurl) | 354 safeurl = util.hidepassword(baseurl) |
354 if proto.startswith('application/hg-error'): | 355 if proto.startswith(b'application/hg-error'): |
355 raise error.OutOfBandError(resp.read()) | 356 raise error.OutOfBandError(resp.read()) |
356 | 357 |
357 # Pre 1.0 versions of Mercurial used text/plain and | 358 # Pre 1.0 versions of Mercurial used text/plain and |
358 # application/hg-changegroup. We don't support such old servers. | 359 # application/hg-changegroup. We don't support such old servers. |
359 if not proto.startswith('application/mercurial-'): | 360 if not proto.startswith(b'application/mercurial-'): |
360 ui.debug("requested URL: '%s'\n" % util.hidepassword(requrl)) | 361 ui.debug(b"requested URL: '%s'\n" % util.hidepassword(requrl)) |
361 msg = _( | 362 msg = _( |
362 "'%s' does not appear to be an hg repository:\n" | 363 b"'%s' does not appear to be an hg repository:\n" |
363 "---%%<--- (%s)\n%s\n---%%<---\n" | 364 b"---%%<--- (%s)\n%s\n---%%<---\n" |
364 ) % (safeurl, proto or 'no content-type', resp.read(1024)) | 365 ) % (safeurl, proto or b'no content-type', resp.read(1024)) |
365 | 366 |
366 # Some servers may strip the query string from the redirect. We | 367 # Some servers may strip the query string from the redirect. We |
367 # raise a special error type so callers can react to this specially. | 368 # raise a special error type so callers can react to this specially. |
368 if redirected and qsdropped: | 369 if redirected and qsdropped: |
369 raise RedirectedRepoError(msg, respurl) | 370 raise RedirectedRepoError(msg, respurl) |
370 else: | 371 else: |
371 raise error.RepoError(msg) | 372 raise error.RepoError(msg) |
372 | 373 |
373 try: | 374 try: |
374 subtype = proto.split('-', 1)[1] | 375 subtype = proto.split(b'-', 1)[1] |
375 | 376 |
376 # Unless we end up supporting CBOR in the legacy wire protocol, | 377 # Unless we end up supporting CBOR in the legacy wire protocol, |
377 # this should ONLY be encountered for the initial capabilities | 378 # this should ONLY be encountered for the initial capabilities |
378 # request during handshake. | 379 # request during handshake. |
379 if subtype == 'cbor': | 380 if subtype == b'cbor': |
380 if allowcbor: | 381 if allowcbor: |
381 return respurl, proto, resp | 382 return respurl, proto, resp |
382 else: | 383 else: |
383 raise error.RepoError( | 384 raise error.RepoError( |
384 _('unexpected CBOR response from ' 'server') | 385 _(b'unexpected CBOR response from ' b'server') |
385 ) | 386 ) |
386 | 387 |
387 version_info = tuple([int(n) for n in subtype.split('.')]) | 388 version_info = tuple([int(n) for n in subtype.split(b'.')]) |
388 except ValueError: | 389 except ValueError: |
389 raise error.RepoError( | 390 raise error.RepoError( |
390 _("'%s' sent a broken Content-Type " "header (%s)") | 391 _(b"'%s' sent a broken Content-Type " b"header (%s)") |
391 % (safeurl, proto) | 392 % (safeurl, proto) |
392 ) | 393 ) |
393 | 394 |
394 # TODO consider switching to a decompression reader that uses | 395 # TODO consider switching to a decompression reader that uses |
395 # generators. | 396 # generators. |
396 if version_info == (0, 1): | 397 if version_info == (0, 1): |
397 if compressible: | 398 if compressible: |
398 resp = util.compengines['zlib'].decompressorreader(resp) | 399 resp = util.compengines[b'zlib'].decompressorreader(resp) |
399 | 400 |
400 elif version_info == (0, 2): | 401 elif version_info == (0, 2): |
401 # application/mercurial-0.2 always identifies the compression | 402 # application/mercurial-0.2 always identifies the compression |
402 # engine in the payload header. | 403 # engine in the payload header. |
403 elen = struct.unpack('B', util.readexactly(resp, 1))[0] | 404 elen = struct.unpack(b'B', util.readexactly(resp, 1))[0] |
404 ename = util.readexactly(resp, elen) | 405 ename = util.readexactly(resp, elen) |
405 engine = util.compengines.forwiretype(ename) | 406 engine = util.compengines.forwiretype(ename) |
406 | 407 |
407 resp = engine.decompressorreader(resp) | 408 resp = engine.decompressorreader(resp) |
408 else: | 409 else: |
409 raise error.RepoError( | 410 raise error.RepoError( |
410 _("'%s' uses newer protocol %s") % (safeurl, subtype) | 411 _(b"'%s' uses newer protocol %s") % (safeurl, subtype) |
411 ) | 412 ) |
412 | 413 |
413 return respurl, proto, resp | 414 return respurl, proto, resp |
414 | 415 |
415 | 416 |
417 def __init__(self, ui, path, url, opener, requestbuilder, caps): | 418 def __init__(self, ui, path, url, opener, requestbuilder, caps): |
418 self.ui = ui | 419 self.ui = ui |
419 self._path = path | 420 self._path = path |
420 self._url = url | 421 self._url = url |
421 self._caps = caps | 422 self._caps = caps |
422 self.limitedarguments = caps is not None and 'httppostargs' not in caps | 423 self.limitedarguments = caps is not None and b'httppostargs' not in caps |
423 self._urlopener = opener | 424 self._urlopener = opener |
424 self._requestbuilder = requestbuilder | 425 self._requestbuilder = requestbuilder |
425 | 426 |
426 def __del__(self): | 427 def __del__(self): |
427 for h in self._urlopener.handlers: | 428 for h in self._urlopener.handlers: |
451 ) | 452 ) |
452 except AttributeError: | 453 except AttributeError: |
453 return | 454 return |
454 self.ui.note( | 455 self.ui.note( |
455 _( | 456 _( |
456 '(sent %d HTTP requests and %d bytes; ' | 457 b'(sent %d HTTP requests and %d bytes; ' |
457 'received %d bytes in responses)\n' | 458 b'received %d bytes in responses)\n' |
458 ) | 459 ) |
459 % (reqs, sent, recv) | 460 % (reqs, sent, recv) |
460 ) | 461 ) |
461 | 462 |
462 # End of ipeerconnection interface. | 463 # End of ipeerconnection interface. |
499 | 500 |
500 def _callpush(self, cmd, cg, **args): | 501 def _callpush(self, cmd, cg, **args): |
501 # have to stream bundle to a temp file because we do not have | 502 # have to stream bundle to a temp file because we do not have |
502 # http 1.1 chunked transfer. | 503 # http 1.1 chunked transfer. |
503 | 504 |
504 types = self.capable('unbundle') | 505 types = self.capable(b'unbundle') |
505 try: | 506 try: |
506 types = types.split(',') | 507 types = types.split(b',') |
507 except AttributeError: | 508 except AttributeError: |
508 # servers older than d1b16a746db6 will send 'unbundle' as a | 509 # servers older than d1b16a746db6 will send 'unbundle' as a |
509 # boolean capability. They only support headerless/uncompressed | 510 # boolean capability. They only support headerless/uncompressed |
510 # bundles. | 511 # bundles. |
511 types = [""] | 512 types = [b""] |
512 for x in types: | 513 for x in types: |
513 if x in bundle2.bundletypes: | 514 if x in bundle2.bundletypes: |
514 type = x | 515 type = x |
515 break | 516 break |
516 | 517 |
517 tempname = bundle2.writebundle(self.ui, cg, None, type) | 518 tempname = bundle2.writebundle(self.ui, cg, None, type) |
518 fp = httpconnection.httpsendfile(self.ui, tempname, "rb") | 519 fp = httpconnection.httpsendfile(self.ui, tempname, b"rb") |
519 headers = {r'Content-Type': r'application/mercurial-0.1'} | 520 headers = {r'Content-Type': r'application/mercurial-0.1'} |
520 | 521 |
521 try: | 522 try: |
522 r = self._call(cmd, data=fp, headers=headers, **args) | 523 r = self._call(cmd, data=fp, headers=headers, **args) |
523 vals = r.split('\n', 1) | 524 vals = r.split(b'\n', 1) |
524 if len(vals) < 2: | 525 if len(vals) < 2: |
525 raise error.ResponseError(_("unexpected response:"), r) | 526 raise error.ResponseError(_(b"unexpected response:"), r) |
526 return vals | 527 return vals |
527 except urlerr.httperror: | 528 except urlerr.httperror: |
528 # Catch and re-raise these so we don't try and treat them | 529 # Catch and re-raise these so we don't try and treat them |
529 # like generic socket errors. They lack any values in | 530 # like generic socket errors. They lack any values in |
530 # .args on Python 3 which breaks our socket.error block. | 531 # .args on Python 3 which breaks our socket.error block. |
531 raise | 532 raise |
532 except socket.error as err: | 533 except socket.error as err: |
533 if err.args[0] in (errno.ECONNRESET, errno.EPIPE): | 534 if err.args[0] in (errno.ECONNRESET, errno.EPIPE): |
534 raise error.Abort(_('push failed: %s') % err.args[1]) | 535 raise error.Abort(_(b'push failed: %s') % err.args[1]) |
535 raise error.Abort(err.args[1]) | 536 raise error.Abort(err.args[1]) |
536 finally: | 537 finally: |
537 fp.close() | 538 fp.close() |
538 os.unlink(tempname) | 539 os.unlink(tempname) |
539 | 540 |
540 def _calltwowaystream(self, cmd, fp, **args): | 541 def _calltwowaystream(self, cmd, fp, **args): |
541 filename = None | 542 filename = None |
542 try: | 543 try: |
543 # dump bundle to disk | 544 # dump bundle to disk |
544 fd, filename = pycompat.mkstemp(prefix="hg-bundle-", suffix=".hg") | 545 fd, filename = pycompat.mkstemp(prefix=b"hg-bundle-", suffix=b".hg") |
545 with os.fdopen(fd, r"wb") as fh: | 546 with os.fdopen(fd, r"wb") as fh: |
546 d = fp.read(4096) | 547 d = fp.read(4096) |
547 while d: | 548 while d: |
548 fh.write(d) | 549 fh.write(d) |
549 d = fp.read(4096) | 550 d = fp.read(4096) |
550 # start http push | 551 # start http push |
551 with httpconnection.httpsendfile(self.ui, filename, "rb") as fp_: | 552 with httpconnection.httpsendfile(self.ui, filename, b"rb") as fp_: |
552 headers = {r'Content-Type': r'application/mercurial-0.1'} | 553 headers = {r'Content-Type': r'application/mercurial-0.1'} |
553 return self._callstream(cmd, data=fp_, headers=headers, **args) | 554 return self._callstream(cmd, data=fp_, headers=headers, **args) |
554 finally: | 555 finally: |
555 if filename is not None: | 556 if filename is not None: |
556 os.unlink(filename) | 557 os.unlink(filename) |
596 | 597 |
597 handler = wireprotov2peer.clienthandler( | 598 handler = wireprotov2peer.clienthandler( |
598 ui, reactor, opener=opener, requestbuilder=requestbuilder | 599 ui, reactor, opener=opener, requestbuilder=requestbuilder |
599 ) | 600 ) |
600 | 601 |
601 url = '%s/%s' % (apiurl, permission) | 602 url = b'%s/%s' % (apiurl, permission) |
602 | 603 |
603 if len(requests) > 1: | 604 if len(requests) > 1: |
604 url += '/multirequest' | 605 url += b'/multirequest' |
605 else: | 606 else: |
606 url += '/%s' % requests[0][0] | 607 url += b'/%s' % requests[0][0] |
607 | 608 |
608 ui.debug('sending %d commands\n' % len(requests)) | 609 ui.debug(b'sending %d commands\n' % len(requests)) |
609 for command, args, f in requests: | 610 for command, args, f in requests: |
610 ui.debug( | 611 ui.debug( |
611 'sending command %s: %s\n' | 612 b'sending command %s: %s\n' |
612 % (command, stringutil.pprint(args, indent=2)) | 613 % (command, stringutil.pprint(args, indent=2)) |
613 ) | 614 ) |
614 assert not list( | 615 assert not list( |
615 handler.callcommand(command, args, f, redirect=redirect) | 616 handler.callcommand(command, args, f, redirect=redirect) |
616 ) | 617 ) |
629 | 630 |
630 try: | 631 try: |
631 res = opener.open(req) | 632 res = opener.open(req) |
632 except urlerr.httperror as e: | 633 except urlerr.httperror as e: |
633 if e.code == 401: | 634 if e.code == 401: |
634 raise error.Abort(_('authorization failed')) | 635 raise error.Abort(_(b'authorization failed')) |
635 | 636 |
636 raise | 637 raise |
637 except httplib.HTTPException as e: | 638 except httplib.HTTPException as e: |
638 ui.traceback() | 639 ui.traceback() |
639 raise IOError(None, e) | 640 raise IOError(None, e) |
681 self.close() | 682 self.close() |
682 | 683 |
683 def callcommand(self, command, args): | 684 def callcommand(self, command, args): |
684 if self._sent: | 685 if self._sent: |
685 raise error.ProgrammingError( | 686 raise error.ProgrammingError( |
686 'callcommand() cannot be used after ' 'commands are sent' | 687 b'callcommand() cannot be used after ' b'commands are sent' |
687 ) | 688 ) |
688 | 689 |
689 if self._closed: | 690 if self._closed: |
690 raise error.ProgrammingError( | 691 raise error.ProgrammingError( |
691 'callcommand() cannot be used after ' 'close()' | 692 b'callcommand() cannot be used after ' b'close()' |
692 ) | 693 ) |
693 | 694 |
694 # The service advertises which commands are available. So if we attempt | 695 # The service advertises which commands are available. So if we attempt |
695 # to call an unknown command or pass an unknown argument, we can screen | 696 # to call an unknown command or pass an unknown argument, we can screen |
696 # for this. | 697 # for this. |
697 if command not in self._descriptor['commands']: | 698 if command not in self._descriptor[b'commands']: |
698 raise error.ProgrammingError( | 699 raise error.ProgrammingError( |
699 'wire protocol command %s is not available' % command | 700 b'wire protocol command %s is not available' % command |
700 ) | 701 ) |
701 | 702 |
702 cmdinfo = self._descriptor['commands'][command] | 703 cmdinfo = self._descriptor[b'commands'][command] |
703 unknownargs = set(args.keys()) - set(cmdinfo.get('args', {})) | 704 unknownargs = set(args.keys()) - set(cmdinfo.get(b'args', {})) |
704 | 705 |
705 if unknownargs: | 706 if unknownargs: |
706 raise error.ProgrammingError( | 707 raise error.ProgrammingError( |
707 'wire protocol command %s does not accept argument: %s' | 708 b'wire protocol command %s does not accept argument: %s' |
708 % (command, ', '.join(sorted(unknownargs))) | 709 % (command, b', '.join(sorted(unknownargs))) |
709 ) | 710 ) |
710 | 711 |
711 self._neededpermissions |= set(cmdinfo['permissions']) | 712 self._neededpermissions |= set(cmdinfo[b'permissions']) |
712 | 713 |
713 # TODO we /could/ also validate types here, since the API descriptor | 714 # TODO we /could/ also validate types here, since the API descriptor |
714 # includes types... | 715 # includes types... |
715 | 716 |
716 f = pycompat.futures.Future() | 717 f = pycompat.futures.Future() |
754 if not calls: | 755 if not calls: |
755 return | 756 return |
756 | 757 |
757 permissions = set(self._neededpermissions) | 758 permissions = set(self._neededpermissions) |
758 | 759 |
759 if 'push' in permissions and 'pull' in permissions: | 760 if b'push' in permissions and b'pull' in permissions: |
760 permissions.remove('pull') | 761 permissions.remove(b'pull') |
761 | 762 |
762 if len(permissions) > 1: | 763 if len(permissions) > 1: |
763 raise error.RepoError( | 764 raise error.RepoError( |
764 _('cannot make request requiring multiple ' 'permissions: %s') | 765 _(b'cannot make request requiring multiple ' b'permissions: %s') |
765 % _(', ').join(sorted(permissions)) | 766 % _(b', ').join(sorted(permissions)) |
766 ) | 767 ) |
767 | 768 |
768 permission = {'push': 'rw', 'pull': 'ro',}[permissions.pop()] | 769 permission = {b'push': b'rw', b'pull': b'ro',}[permissions.pop()] |
769 | 770 |
770 handler, resp = sendv2request( | 771 handler, resp = sendv2request( |
771 self._ui, | 772 self._ui, |
772 self._opener, | 773 self._opener, |
773 self._requestbuilder, | 774 self._requestbuilder, |
807 # If any of our futures are still in progress, mark them as | 808 # If any of our futures are still in progress, mark them as |
808 # errored, otherwise a result() could wait indefinitely. | 809 # errored, otherwise a result() could wait indefinitely. |
809 for f in self._futures: | 810 for f in self._futures: |
810 if not f.done(): | 811 if not f.done(): |
811 f.set_exception( | 812 f.set_exception( |
812 error.ResponseError(_('unfulfilled command response')) | 813 error.ResponseError(_(b'unfulfilled command response')) |
813 ) | 814 ) |
814 | 815 |
815 self._futures = None | 816 self._futures = None |
816 | 817 |
817 def _handleresponse(self, handler, resp): | 818 def _handleresponse(self, handler, resp): |
830 self, ui, repourl, apipath, opener, requestbuilder, apidescriptor | 831 self, ui, repourl, apipath, opener, requestbuilder, apidescriptor |
831 ): | 832 ): |
832 self.ui = ui | 833 self.ui = ui |
833 self.apidescriptor = apidescriptor | 834 self.apidescriptor = apidescriptor |
834 | 835 |
835 if repourl.endswith('/'): | 836 if repourl.endswith(b'/'): |
836 repourl = repourl[:-1] | 837 repourl = repourl[:-1] |
837 | 838 |
838 self._url = repourl | 839 self._url = repourl |
839 self._apipath = apipath | 840 self._apipath = apipath |
840 self._apiurl = '%s/%s' % (repourl, apipath) | 841 self._apiurl = b'%s/%s' % (repourl, apipath) |
841 self._opener = opener | 842 self._opener = opener |
842 self._requestbuilder = requestbuilder | 843 self._requestbuilder = requestbuilder |
843 | 844 |
844 self._redirect = wireprotov2peer.supportedredirects(ui, apidescriptor) | 845 self._redirect = wireprotov2peer.supportedredirects(ui, apidescriptor) |
845 | 846 |
859 return False | 860 return False |
860 | 861 |
861 def close(self): | 862 def close(self): |
862 self.ui.note( | 863 self.ui.note( |
863 _( | 864 _( |
864 '(sent %d HTTP requests and %d bytes; ' | 865 b'(sent %d HTTP requests and %d bytes; ' |
865 'received %d bytes in responses)\n' | 866 b'received %d bytes in responses)\n' |
866 ) | 867 ) |
867 % ( | 868 % ( |
868 self._opener.requestscount, | 869 self._opener.requestscount, |
869 self._opener.sentbytescount, | 870 self._opener.sentbytescount, |
870 self._opener.receivedbytescount, | 871 self._opener.receivedbytescount, |
879 # The capabilities used internally historically map to capabilities | 880 # The capabilities used internally historically map to capabilities |
880 # advertised from the "capabilities" wire protocol command. However, | 881 # advertised from the "capabilities" wire protocol command. However, |
881 # version 2 of that command works differently. | 882 # version 2 of that command works differently. |
882 | 883 |
883 # Maps to commands that are available. | 884 # Maps to commands that are available. |
884 if name in ('branchmap', 'getbundle', 'known', 'lookup', 'pushkey'): | 885 if name in ( |
886 b'branchmap', | |
887 b'getbundle', | |
888 b'known', | |
889 b'lookup', | |
890 b'pushkey', | |
891 ): | |
885 return True | 892 return True |
886 | 893 |
887 # Other concepts. | 894 # Other concepts. |
888 if name in 'bundle2': | 895 if name in b'bundle2': |
889 return True | 896 return True |
890 | 897 |
891 # Alias command-* to presence of command of that name. | 898 # Alias command-* to presence of command of that name. |
892 if name.startswith('command-'): | 899 if name.startswith(b'command-'): |
893 return name[len('command-') :] in self.apidescriptor['commands'] | 900 return name[len(b'command-') :] in self.apidescriptor[b'commands'] |
894 | 901 |
895 return False | 902 return False |
896 | 903 |
897 def requirecap(self, name, purpose): | 904 def requirecap(self, name, purpose): |
898 if self.capable(name): | 905 if self.capable(name): |
899 return | 906 return |
900 | 907 |
901 raise error.CapabilityError( | 908 raise error.CapabilityError( |
902 _( | 909 _( |
903 'cannot %s; client or remote repository does not support the ' | 910 b'cannot %s; client or remote repository does not support the ' |
904 '\'%s\' capability' | 911 b'\'%s\' capability' |
905 ) | 912 ) |
906 % (purpose, name) | 913 % (purpose, name) |
907 ) | 914 ) |
908 | 915 |
909 # End of ipeercapabilities. | 916 # End of ipeercapabilities. |
933 # | 940 # |
934 # priority | 941 # priority |
935 # Integer priority for the service. If we could choose from multiple | 942 # Integer priority for the service. If we could choose from multiple |
936 # services, we choose the one with the highest priority. | 943 # services, we choose the one with the highest priority. |
937 API_PEERS = { | 944 API_PEERS = { |
938 wireprototypes.HTTP_WIREPROTO_V2: {'init': httpv2peer, 'priority': 50,}, | 945 wireprototypes.HTTP_WIREPROTO_V2: {b'init': httpv2peer, b'priority': 50,}, |
939 } | 946 } |
940 | 947 |
941 | 948 |
942 def performhandshake(ui, url, opener, requestbuilder): | 949 def performhandshake(ui, url, opener, requestbuilder): |
943 # The handshake is a request to the capabilities command. | 950 # The handshake is a request to the capabilities command. |
944 | 951 |
945 caps = None | 952 caps = None |
946 | 953 |
947 def capable(x): | 954 def capable(x): |
948 raise error.ProgrammingError('should not be called') | 955 raise error.ProgrammingError(b'should not be called') |
949 | 956 |
950 args = {} | 957 args = {} |
951 | 958 |
952 # The client advertises support for newer protocols by adding an | 959 # The client advertises support for newer protocols by adding an |
953 # X-HgUpgrade-* header with a list of supported APIs and an | 960 # X-HgUpgrade-* header with a list of supported APIs and an |
954 # X-HgProto-* header advertising which serializing formats it supports. | 961 # X-HgProto-* header advertising which serializing formats it supports. |
955 # We only support the HTTP version 2 transport and CBOR responses for | 962 # We only support the HTTP version 2 transport and CBOR responses for |
956 # now. | 963 # now. |
957 advertisev2 = ui.configbool('experimental', 'httppeer.advertise-v2') | 964 advertisev2 = ui.configbool(b'experimental', b'httppeer.advertise-v2') |
958 | 965 |
959 if advertisev2: | 966 if advertisev2: |
960 args['headers'] = { | 967 args[b'headers'] = { |
961 r'X-HgProto-1': r'cbor', | 968 r'X-HgProto-1': r'cbor', |
962 } | 969 } |
963 | 970 |
964 args['headers'].update( | 971 args[b'headers'].update( |
965 encodevalueinheaders( | 972 encodevalueinheaders( |
966 ' '.join(sorted(API_PEERS)), | 973 b' '.join(sorted(API_PEERS)), |
967 'X-HgUpgrade', | 974 b'X-HgUpgrade', |
968 # We don't know the header limit this early. | 975 # We don't know the header limit this early. |
969 # So make it small. | 976 # So make it small. |
970 1024, | 977 1024, |
971 ) | 978 ) |
972 ) | 979 ) |
973 | 980 |
974 req, requrl, qs = makev1commandrequest( | 981 req, requrl, qs = makev1commandrequest( |
975 ui, requestbuilder, caps, capable, url, 'capabilities', args | 982 ui, requestbuilder, caps, capable, url, b'capabilities', args |
976 ) | 983 ) |
977 resp = sendrequest(ui, opener, req) | 984 resp = sendrequest(ui, opener, req) |
978 | 985 |
979 # The server may redirect us to the repo root, stripping the | 986 # The server may redirect us to the repo root, stripping the |
980 # ?cmd=capabilities query string from the URL. The server would likely | 987 # ?cmd=capabilities query string from the URL. The server would likely |
992 respurl, ct, resp = parsev1commandresponse( | 999 respurl, ct, resp = parsev1commandresponse( |
993 ui, url, requrl, qs, resp, compressible=False, allowcbor=advertisev2 | 1000 ui, url, requrl, qs, resp, compressible=False, allowcbor=advertisev2 |
994 ) | 1001 ) |
995 except RedirectedRepoError as e: | 1002 except RedirectedRepoError as e: |
996 req, requrl, qs = makev1commandrequest( | 1003 req, requrl, qs = makev1commandrequest( |
997 ui, requestbuilder, caps, capable, e.respurl, 'capabilities', args | 1004 ui, requestbuilder, caps, capable, e.respurl, b'capabilities', args |
998 ) | 1005 ) |
999 resp = sendrequest(ui, opener, req) | 1006 resp = sendrequest(ui, opener, req) |
1000 respurl, ct, resp = parsev1commandresponse( | 1007 respurl, ct, resp = parsev1commandresponse( |
1001 ui, url, requrl, qs, resp, compressible=False, allowcbor=advertisev2 | 1008 ui, url, requrl, qs, resp, compressible=False, allowcbor=advertisev2 |
1002 ) | 1009 ) |
1004 try: | 1011 try: |
1005 rawdata = resp.read() | 1012 rawdata = resp.read() |
1006 finally: | 1013 finally: |
1007 resp.close() | 1014 resp.close() |
1008 | 1015 |
1009 if not ct.startswith('application/mercurial-'): | 1016 if not ct.startswith(b'application/mercurial-'): |
1010 raise error.ProgrammingError('unexpected content-type: %s' % ct) | 1017 raise error.ProgrammingError(b'unexpected content-type: %s' % ct) |
1011 | 1018 |
1012 if advertisev2: | 1019 if advertisev2: |
1013 if ct == 'application/mercurial-cbor': | 1020 if ct == b'application/mercurial-cbor': |
1014 try: | 1021 try: |
1015 info = cborutil.decodeall(rawdata)[0] | 1022 info = cborutil.decodeall(rawdata)[0] |
1016 except cborutil.CBORDecodeError: | 1023 except cborutil.CBORDecodeError: |
1017 raise error.Abort( | 1024 raise error.Abort( |
1018 _('error decoding CBOR from remote server'), | 1025 _(b'error decoding CBOR from remote server'), |
1019 hint=_( | 1026 hint=_( |
1020 'try again and consider contacting ' | 1027 b'try again and consider contacting ' |
1021 'the server operator' | 1028 b'the server operator' |
1022 ), | 1029 ), |
1023 ) | 1030 ) |
1024 | 1031 |
1025 # We got a legacy response. That's fine. | 1032 # We got a legacy response. That's fine. |
1026 elif ct in ('application/mercurial-0.1', 'application/mercurial-0.2'): | 1033 elif ct in (b'application/mercurial-0.1', b'application/mercurial-0.2'): |
1027 info = {'v1capabilities': set(rawdata.split())} | 1034 info = {b'v1capabilities': set(rawdata.split())} |
1028 | 1035 |
1029 else: | 1036 else: |
1030 raise error.RepoError( | 1037 raise error.RepoError( |
1031 _('unexpected response type from server: %s') % ct | 1038 _(b'unexpected response type from server: %s') % ct |
1032 ) | 1039 ) |
1033 else: | 1040 else: |
1034 info = {'v1capabilities': set(rawdata.split())} | 1041 info = {b'v1capabilities': set(rawdata.split())} |
1035 | 1042 |
1036 return respurl, info | 1043 return respurl, info |
1037 | 1044 |
1038 | 1045 |
1039 def makepeer(ui, path, opener=None, requestbuilder=urlreq.request): | 1046 def makepeer(ui, path, opener=None, requestbuilder=urlreq.request): |
1046 It exists as an argument so extensions can override the default. | 1053 It exists as an argument so extensions can override the default. |
1047 """ | 1054 """ |
1048 u = util.url(path) | 1055 u = util.url(path) |
1049 if u.query or u.fragment: | 1056 if u.query or u.fragment: |
1050 raise error.Abort( | 1057 raise error.Abort( |
1051 _('unsupported URL component: "%s"') % (u.query or u.fragment) | 1058 _(b'unsupported URL component: "%s"') % (u.query or u.fragment) |
1052 ) | 1059 ) |
1053 | 1060 |
1054 # urllib cannot handle URLs with embedded user or passwd. | 1061 # urllib cannot handle URLs with embedded user or passwd. |
1055 url, authinfo = u.authinfo() | 1062 url, authinfo = u.authinfo() |
1056 ui.debug('using %s\n' % url) | 1063 ui.debug(b'using %s\n' % url) |
1057 | 1064 |
1058 opener = opener or urlmod.opener(ui, authinfo) | 1065 opener = opener or urlmod.opener(ui, authinfo) |
1059 | 1066 |
1060 respurl, info = performhandshake(ui, url, opener, requestbuilder) | 1067 respurl, info = performhandshake(ui, url, opener, requestbuilder) |
1061 | 1068 |
1066 # example, the caller could say "I want a peer that does X." It's quite | 1073 # example, the caller could say "I want a peer that does X." It's quite |
1067 # possible that not all peers would do that. Since we know the service | 1074 # possible that not all peers would do that. Since we know the service |
1068 # capabilities, we could filter out services not meeting the | 1075 # capabilities, we could filter out services not meeting the |
1069 # requirements. Possibly by consulting the interfaces defined by the | 1076 # requirements. Possibly by consulting the interfaces defined by the |
1070 # peer type. | 1077 # peer type. |
1071 apipeerchoices = set(info.get('apis', {}).keys()) & set(API_PEERS.keys()) | 1078 apipeerchoices = set(info.get(b'apis', {}).keys()) & set(API_PEERS.keys()) |
1072 | 1079 |
1073 preferredchoices = sorted( | 1080 preferredchoices = sorted( |
1074 apipeerchoices, key=lambda x: API_PEERS[x]['priority'], reverse=True | 1081 apipeerchoices, key=lambda x: API_PEERS[x][b'priority'], reverse=True |
1075 ) | 1082 ) |
1076 | 1083 |
1077 for service in preferredchoices: | 1084 for service in preferredchoices: |
1078 apipath = '%s/%s' % (info['apibase'].rstrip('/'), service) | 1085 apipath = b'%s/%s' % (info[b'apibase'].rstrip(b'/'), service) |
1079 | 1086 |
1080 return API_PEERS[service]['init']( | 1087 return API_PEERS[service][b'init']( |
1081 ui, respurl, apipath, opener, requestbuilder, info['apis'][service] | 1088 ui, respurl, apipath, opener, requestbuilder, info[b'apis'][service] |
1082 ) | 1089 ) |
1083 | 1090 |
1084 # Failed to construct an API peer. Fall back to legacy. | 1091 # Failed to construct an API peer. Fall back to legacy. |
1085 return httppeer( | 1092 return httppeer( |
1086 ui, path, respurl, opener, requestbuilder, info['v1capabilities'] | 1093 ui, path, respurl, opener, requestbuilder, info[b'v1capabilities'] |
1087 ) | 1094 ) |
1088 | 1095 |
1089 | 1096 |
1090 def instance(ui, path, create, intents=None, createopts=None): | 1097 def instance(ui, path, create, intents=None, createopts=None): |
1091 if create: | 1098 if create: |
1092 raise error.Abort(_('cannot create new http repository')) | 1099 raise error.Abort(_(b'cannot create new http repository')) |
1093 try: | 1100 try: |
1094 if path.startswith('https:') and not urlmod.has_https: | 1101 if path.startswith(b'https:') and not urlmod.has_https: |
1095 raise error.Abort( | 1102 raise error.Abort( |
1096 _('Python support for SSL and HTTPS ' 'is not installed') | 1103 _(b'Python support for SSL and HTTPS ' b'is not installed') |
1097 ) | 1104 ) |
1098 | 1105 |
1099 inst = makepeer(ui, path) | 1106 inst = makepeer(ui, path) |
1100 | 1107 |
1101 return inst | 1108 return inst |
1102 except error.RepoError as httpexception: | 1109 except error.RepoError as httpexception: |
1103 try: | 1110 try: |
1104 r = statichttprepo.instance(ui, "static-" + path, create) | 1111 r = statichttprepo.instance(ui, b"static-" + path, create) |
1105 ui.note(_('(falling back to static-http)\n')) | 1112 ui.note(_(b'(falling back to static-http)\n')) |
1106 return r | 1113 return r |
1107 except error.RepoError: | 1114 except error.RepoError: |
1108 raise httpexception # use the original http RepoError instead | 1115 raise httpexception # use the original http RepoError instead |