##// END OF EJS Templates
wireproto: use maybecapturestdio() for push responses (API)...
Gregory Szorc -
r36084:caca3ac2 default
parent child Browse files
Show More
@@ -34,27 +34,26 b' httpoldcallstream = None'
34 34 def putlfile(repo, proto, sha):
35 35 '''Server command for putting a largefile into a repository's local store
36 36 and into the user cache.'''
37 proto.redirect()
38
39 path = lfutil.storepath(repo, sha)
40 util.makedirs(os.path.dirname(path))
41 tmpfp = util.atomictempfile(path, createmode=repo.store.createmode)
37 with proto.mayberedirectstdio() as output:
38 path = lfutil.storepath(repo, sha)
39 util.makedirs(os.path.dirname(path))
40 tmpfp = util.atomictempfile(path, createmode=repo.store.createmode)
42 41
43 try:
44 proto.getfile(tmpfp)
45 tmpfp._fp.seek(0)
46 if sha != lfutil.hexsha1(tmpfp._fp):
47 raise IOError(0, _('largefile contents do not match hash'))
48 tmpfp.close()
49 lfutil.linktousercache(repo, sha)
50 except IOError as e:
51 repo.ui.warn(_('largefiles: failed to put %s into store: %s\n') %
52 (sha, e.strerror))
53 return wireproto.pushres(1)
54 finally:
55 tmpfp.discard()
42 try:
43 proto.getfile(tmpfp)
44 tmpfp._fp.seek(0)
45 if sha != lfutil.hexsha1(tmpfp._fp):
46 raise IOError(0, _('largefile contents do not match hash'))
47 tmpfp.close()
48 lfutil.linktousercache(repo, sha)
49 except IOError as e:
50 repo.ui.warn(_('largefiles: failed to put %s into store: %s\n') %
51 (sha, e.strerror))
52 return wireproto.pushres(1, output.getvalue() if output else '')
53 finally:
54 tmpfp.discard()
56 55
57 return wireproto.pushres(0)
56 return wireproto.pushres(0, output.getvalue() if output else '')
58 57
59 58 def getlfile(repo, proto, sha):
60 59 '''Server command for retrieving a largefile from the repository-local
@@ -510,16 +510,18 b' class pushres(object):'
510 510
511 511 The call was successful and returned an integer contained in `self.res`.
512 512 """
513 def __init__(self, res):
513 def __init__(self, res, output):
514 514 self.res = res
515 self.output = output
515 516
516 517 class pusherr(object):
517 518 """wireproto reply: failure
518 519
519 520 The call failed. The `self.res` attribute contains the error message.
520 521 """
521 def __init__(self, res):
522 def __init__(self, res, output):
522 523 self.res = res
524 self.output = output
523 525
524 526 class ooberror(object):
525 527 """wireproto reply: failure of a batch of operation
@@ -997,97 +999,98 b' def stream(repo, proto):'
997 999 def unbundle(repo, proto, heads):
998 1000 their_heads = decodelist(heads)
999 1001
1000 try:
1001 proto.redirect()
1002
1003 exchange.check_heads(repo, their_heads, 'preparing changes')
1004
1005 # write bundle data to temporary file because it can be big
1006 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
1007 fp = os.fdopen(fd, pycompat.sysstr('wb+'))
1008 r = 0
1002 with proto.mayberedirectstdio() as output:
1009 1003 try:
1010 proto.getfile(fp)
1011 fp.seek(0)
1012 gen = exchange.readbundle(repo.ui, fp, None)
1013 if (isinstance(gen, changegroupmod.cg1unpacker)
1014 and not bundle1allowed(repo, 'push')):
1015 if proto.name == 'http':
1016 # need to special case http because stderr do not get to
1017 # the http client on failed push so we need to abuse some
1018 # other error type to make sure the message get to the
1019 # user.
1020 return ooberror(bundle2required)
1021 raise error.Abort(bundle2requiredmain,
1022 hint=bundle2requiredhint)
1004 exchange.check_heads(repo, their_heads, 'preparing changes')
1023 1005
1024 r = exchange.unbundle(repo, gen, their_heads, 'serve',
1025 proto._client())
1026 if util.safehasattr(r, 'addpart'):
1027 # The return looks streamable, we are in the bundle2 case and
1028 # should return a stream.
1029 return streamres_legacy(gen=r.getchunks())
1030 return pushres(r)
1031
1032 finally:
1033 fp.close()
1034 os.unlink(tempname)
1035
1036 except (error.BundleValueError, error.Abort, error.PushRaced) as exc:
1037 # handle non-bundle2 case first
1038 if not getattr(exc, 'duringunbundle2', False):
1006 # write bundle data to temporary file because it can be big
1007 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
1008 fp = os.fdopen(fd, pycompat.sysstr('wb+'))
1009 r = 0
1039 1010 try:
1040 raise
1041 except error.Abort:
1042 # The old code we moved used util.stderr directly.
1043 # We did not change it to minimise code change.
1044 # This need to be moved to something proper.
1045 # Feel free to do it.
1046 util.stderr.write("abort: %s\n" % exc)
1047 if exc.hint is not None:
1048 util.stderr.write("(%s)\n" % exc.hint)
1049 return pushres(0)
1050 except error.PushRaced:
1051 return pusherr(str(exc))
1011 proto.getfile(fp)
1012 fp.seek(0)
1013 gen = exchange.readbundle(repo.ui, fp, None)
1014 if (isinstance(gen, changegroupmod.cg1unpacker)
1015 and not bundle1allowed(repo, 'push')):
1016 if proto.name == 'http':
1017 # need to special case http because stderr do not get to
1018 # the http client on failed push so we need to abuse
1019 # some other error type to make sure the message get to
1020 # the user.
1021 return ooberror(bundle2required)
1022 raise error.Abort(bundle2requiredmain,
1023 hint=bundle2requiredhint)
1052 1024
1053 bundler = bundle2.bundle20(repo.ui)
1054 for out in getattr(exc, '_bundle2salvagedoutput', ()):
1055 bundler.addpart(out)
1056 try:
1057 try:
1058 raise
1059 except error.PushkeyFailed as exc:
1060 # check client caps
1061 remotecaps = getattr(exc, '_replycaps', None)
1062 if (remotecaps is not None
1063 and 'pushkey' not in remotecaps.get('error', ())):
1064 # no support remote side, fallback to Abort handler.
1025 r = exchange.unbundle(repo, gen, their_heads, 'serve',
1026 proto._client())
1027 if util.safehasattr(r, 'addpart'):
1028 # The return looks streamable, we are in the bundle2 case
1029 # and should return a stream.
1030 return streamres_legacy(gen=r.getchunks())
1031 return pushres(r, output.getvalue() if output else '')
1032
1033 finally:
1034 fp.close()
1035 os.unlink(tempname)
1036
1037 except (error.BundleValueError, error.Abort, error.PushRaced) as exc:
1038 # handle non-bundle2 case first
1039 if not getattr(exc, 'duringunbundle2', False):
1040 try:
1065 1041 raise
1066 part = bundler.newpart('error:pushkey')
1067 part.addparam('in-reply-to', exc.partid)
1068 if exc.namespace is not None:
1069 part.addparam('namespace', exc.namespace, mandatory=False)
1070 if exc.key is not None:
1071 part.addparam('key', exc.key, mandatory=False)
1072 if exc.new is not None:
1073 part.addparam('new', exc.new, mandatory=False)
1074 if exc.old is not None:
1075 part.addparam('old', exc.old, mandatory=False)
1076 if exc.ret is not None:
1077 part.addparam('ret', exc.ret, mandatory=False)
1078 except error.BundleValueError as exc:
1079 errpart = bundler.newpart('error:unsupportedcontent')
1080 if exc.parttype is not None:
1081 errpart.addparam('parttype', exc.parttype)
1082 if exc.params:
1083 errpart.addparam('params', '\0'.join(exc.params))
1084 except error.Abort as exc:
1085 manargs = [('message', str(exc))]
1086 advargs = []
1087 if exc.hint is not None:
1088 advargs.append(('hint', exc.hint))
1089 bundler.addpart(bundle2.bundlepart('error:abort',
1090 manargs, advargs))
1091 except error.PushRaced as exc:
1092 bundler.newpart('error:pushraced', [('message', str(exc))])
1093 return streamres_legacy(gen=bundler.getchunks())
1042 except error.Abort:
1043 # The old code we moved used util.stderr directly.
1044 # We did not change it to minimise code change.
1045 # This need to be moved to something proper.
1046 # Feel free to do it.
1047 util.stderr.write("abort: %s\n" % exc)
1048 if exc.hint is not None:
1049 util.stderr.write("(%s)\n" % exc.hint)
1050 return pushres(0, output.getvalue() if output else '')
1051 except error.PushRaced:
1052 return pusherr(str(exc),
1053 output.getvalue() if output else '')
1054
1055 bundler = bundle2.bundle20(repo.ui)
1056 for out in getattr(exc, '_bundle2salvagedoutput', ()):
1057 bundler.addpart(out)
1058 try:
1059 try:
1060 raise
1061 except error.PushkeyFailed as exc:
1062 # check client caps
1063 remotecaps = getattr(exc, '_replycaps', None)
1064 if (remotecaps is not None
1065 and 'pushkey' not in remotecaps.get('error', ())):
1066 # no support remote side, fallback to Abort handler.
1067 raise
1068 part = bundler.newpart('error:pushkey')
1069 part.addparam('in-reply-to', exc.partid)
1070 if exc.namespace is not None:
1071 part.addparam('namespace', exc.namespace,
1072 mandatory=False)
1073 if exc.key is not None:
1074 part.addparam('key', exc.key, mandatory=False)
1075 if exc.new is not None:
1076 part.addparam('new', exc.new, mandatory=False)
1077 if exc.old is not None:
1078 part.addparam('old', exc.old, mandatory=False)
1079 if exc.ret is not None:
1080 part.addparam('ret', exc.ret, mandatory=False)
1081 except error.BundleValueError as exc:
1082 errpart = bundler.newpart('error:unsupportedcontent')
1083 if exc.parttype is not None:
1084 errpart.addparam('parttype', exc.parttype)
1085 if exc.params:
1086 errpart.addparam('params', '\0'.join(exc.params))
1087 except error.Abort as exc:
1088 manargs = [('message', str(exc))]
1089 advargs = []
1090 if exc.hint is not None:
1091 advargs.append(('hint', exc.hint))
1092 bundler.addpart(bundle2.bundlepart('error:abort',
1093 manargs, advargs))
1094 except error.PushRaced as exc:
1095 bundler.newpart('error:pushraced', [('message', str(exc))])
1096 return streamres_legacy(gen=bundler.getchunks())
@@ -320,15 +320,13 b' def _callhttp(repo, req, proto, cmd):'
320 320 req.respond(HTTP_OK, mediatype)
321 321 return gen
322 322 elif isinstance(rsp, wireproto.pushres):
323 val = proto.restore()
324 rsp = '%d\n%s' % (rsp.res, val)
323 rsp = '%d\n%s' % (rsp.res, rsp.output)
325 324 req.respond(HTTP_OK, HGTYPE, body=rsp)
326 325 return []
327 326 elif isinstance(rsp, wireproto.pusherr):
328 327 # This is the httplib workaround documented in _handlehttperror().
329 328 req.drain()
330 329
331 proto.restore()
332 330 rsp = '0\n%s\n' % rsp.res
333 331 req.respond(HTTP_OK, HGTYPE, body=rsp)
334 332 return []
General Comments 0
You need to be logged in to leave comments. Login now