# HG changeset patch # User Andrew Pritchard # Date 1312312870 14400 # Node ID f4522df38c658a1768ffe08c864575e119b327ce # Parent 871c77e78f5d6897778cea75a4fca6f19e979c85 wireproto: add out-of-band error class to allow remote repo to report errors Older clients will still print the provided error message and not much else: over ssh, this will be each line prefixed with 'remote: ' in addition to an "abort: unexpected response: '\n'"; over http, this will be the '---%<---' banners in addition to the 'does not appear to be a repository' message. Currently, clients with this patch will display 'abort: remote error:\n' and the provided error text, but it is trivial to style the error text however is deemed appropriate. diff -r 871c77e78f5d -r f4522df38c65 mercurial/dispatch.py --- a/mercurial/dispatch.py Wed Aug 03 16:41:14 2011 -0500 +++ b/mercurial/dispatch.py Tue Aug 02 15:21:10 2011 -0400 @@ -123,6 +123,9 @@ else: ui.warn(_("hg: %s\n") % inst.args[1]) commands.help_(ui, 'shortlist') + except error.OutOfBandError, inst: + ui.warn("abort: remote error:\n") + ui.warn(''.join(inst.args)) except error.RepoError, inst: ui.warn(_("abort: %s!\n") % inst) if inst.hint: diff -r 871c77e78f5d -r f4522df38c65 mercurial/error.py --- a/mercurial/error.py Wed Aug 03 16:41:14 2011 -0500 +++ b/mercurial/error.py Tue Aug 02 15:21:10 2011 -0400 @@ -39,6 +39,9 @@ class ConfigError(Abort): 'Exception raised when parsing config files' +class OutOfBandError(Exception): + 'Exception raised when a remote repo reports failure' + class ParseError(Exception): 'Exception raised when parsing config files (msg[, pos])' diff -r 871c77e78f5d -r f4522df38c65 mercurial/hgweb/protocol.py --- a/mercurial/hgweb/protocol.py Wed Aug 03 16:41:14 2011 -0500 +++ b/mercurial/hgweb/protocol.py Tue Aug 02 15:21:10 2011 -0400 @@ -10,6 +10,7 @@ from common import HTTP_OK HGTYPE = 'application/mercurial-0.1' +HGERRTYPE = 'application/hg-error' class webproto(object): def __init__(self, req, ui): @@ -90,3 +91,7 @@ rsp = '0\n%s\n' % rsp.res req.respond(HTTP_OK, HGTYPE, length=len(rsp)) return [rsp] + elif isinstance(rsp, wireproto.ooberror): + rsp = rsp.message + req.respond(HTTP_OK, HGERRTYPE, length=len(rsp)) + return [rsp] diff -r 871c77e78f5d -r f4522df38c65 mercurial/httprepo.py --- a/mercurial/httprepo.py Wed Aug 03 16:41:14 2011 -0500 +++ b/mercurial/httprepo.py Tue Aug 02 15:21:10 2011 -0400 @@ -136,6 +136,8 @@ proto = resp.headers.get('content-type', '') safeurl = util.hidepassword(self._url) + if proto.startswith('application/hg-error'): + raise error.OutOfBandError(resp.read()) # accept old "text/plain" and "application/hg-changegroup" for now if not (proto.startswith('application/mercurial-') or proto.startswith('text/plain') or diff -r 871c77e78f5d -r f4522df38c65 mercurial/sshrepo.py --- a/mercurial/sshrepo.py Wed Aug 03 16:41:14 2011 -0500 +++ b/mercurial/sshrepo.py Tue Aug 02 15:21:10 2011 -0400 @@ -164,6 +164,17 @@ def _recv(self): l = self.pipei.readline() + if l == '\n': + err = [] + while True: + line = self.pipee.readline() + if line == '-\n': + break + err.extend([line]) + if len(err) > 0: + # strip the trailing newline added to the last line server-side + err[-1] = err[-1][:-1] + self._abort(error.OutOfBandError(*err)) self.readerr() try: l = int(l) diff -r 871c77e78f5d -r f4522df38c65 mercurial/sshserver.py --- a/mercurial/sshserver.py Wed Aug 03 16:41:14 2011 -0500 +++ b/mercurial/sshserver.py Tue Aug 02 15:21:10 2011 -0400 @@ -82,6 +82,12 @@ def sendpusherror(self, rsp): self.sendresponse(rsp.res) + def sendooberror(self, rsp): + self.ui.ferr.write('%s\n-\n' % rsp.message) + self.ui.ferr.flush() + self.fout.write('\n') + self.fout.flush() + def serve_forever(self): try: while self.serve_one(): @@ -96,6 +102,7 @@ wireproto.streamres: sendstream, wireproto.pushres: sendpushresponse, wireproto.pusherr: sendpusherror, + wireproto.ooberror: sendooberror, } def serve_one(self): diff -r 871c77e78f5d -r f4522df38c65 mercurial/wireproto.py --- a/mercurial/wireproto.py Wed Aug 03 16:41:14 2011 -0500 +++ b/mercurial/wireproto.py Tue Aug 02 15:21:10 2011 -0400 @@ -335,6 +335,10 @@ def __init__(self, res): self.res = res +class ooberror(object): + def __init__(self, message): + self.message = message + def dispatch(repo, proto, command): func, spec = commands[command] args = proto.getargs(spec) @@ -376,6 +380,8 @@ result = func(repo, proto, *[data[k] for k in keys]) else: result = func(repo, proto) + if isinstance(result, ooberror): + return result res.append(escapearg(result)) return ';'.join(res)