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.
--- 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:
--- 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])'
--- 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]
--- 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
--- 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)
--- 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):
--- 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)