changeset 28511:ff5f923fca3c

cmdserver: write early exception to 'e' channel in 'unix' mode In 'unix' mode, the server is typically detached from the console. Therefore a client couldn't see the exception that occurred while instantiating the server object. This patch tries to catch the early error and send it to 'e' channel even if the server isn't instantiated yet. This means the error may be sent before the initial hello message. So it's up to the client implementation whether to handle the early error message or error out as protocol violation. The error handling code is also copied to chgserver.py. I'll factor out them later if we manage to get chg passes the test suite.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 12 Mar 2016 22:03:30 +0900
parents ade330deb39a
children b957b4c6cad8
files hgext/chgserver.py mercurial/commandserver.py tests/test-commandserver.t
diffstat 3 files changed, 44 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/chgserver.py	Sun Mar 13 01:32:42 2016 +0530
+++ b/hgext/chgserver.py	Sat Mar 12 22:03:30 2016 +0900
@@ -525,9 +525,10 @@
         os.setpgid(0, 0)
         ui = self.server.ui
         repo = self.server.repo
-        sv = chgcmdserver(ui, repo, self.rfile, self.wfile, self.connection,
-                          self.server.hashstate, self.server.baseaddress)
+        sv = None
         try:
+            sv = chgcmdserver(ui, repo, self.rfile, self.wfile, self.connection,
+                              self.server.hashstate, self.server.baseaddress)
             try:
                 sv.serve()
             # handle exceptions that may be raised by command server. most of
@@ -544,7 +545,11 @@
         except: # re-raises
             # also write traceback to error channel. otherwise client cannot
             # see it because it is written to server's stderr by default.
-            traceback.print_exc(file=sv.cerr)
+            if sv:
+                cerr = sv.cerr
+            else:
+                cerr = commandserver.channeledoutput(self.wfile, 'e')
+            traceback.print_exc(file=cerr)
             raise
 
 def _tempaddress(address):
--- a/mercurial/commandserver.py	Sun Mar 13 01:32:42 2016 +0530
+++ b/mercurial/commandserver.py	Sat Mar 12 22:03:30 2016 +0900
@@ -338,8 +338,9 @@
     def handle(self):
         ui = self.server.ui
         repo = self.server.repo
-        sv = server(ui, repo, self.rfile, self.wfile)
+        sv = None
         try:
+            sv = server(ui, repo, self.rfile, self.wfile)
             try:
                 sv.serve()
             # handle exceptions that may be raised by command server. most of
@@ -354,7 +355,11 @@
         except: # re-raises
             # also write traceback to error channel. otherwise client cannot
             # see it because it is written to server's stderr by default.
-            traceback.print_exc(file=sv.cerr)
+            if sv:
+                cerr = sv.cerr
+            else:
+                cerr = channeledoutput(self.wfile, 'e')
+            traceback.print_exc(file=cerr)
             raise
 
 class unixservice(object):
--- a/tests/test-commandserver.t	Sun Mar 13 01:32:42 2016 +0530
+++ b/tests/test-commandserver.t	Sat Mar 12 22:03:30 2016 +0900
@@ -717,6 +717,35 @@
   listening at .hg/server.sock
   abort: unknown command unknowncommand
   killed!
+  $ rm .hg/server.log
+
+ if server crashed before hello, traceback will be sent to 'e' channel as
+ last ditch:
+
+  $ cat <<EOF >> .hg/hgrc
+  > [cmdserver]
+  > log = inexistent/path.log
+  > EOF
+  >>> from hgclient import unixserver, readchannel, check
+  >>> server = unixserver('.hg/server.sock', '.hg/server.log')
+  >>> def earlycrash(conn):
+  ...     while True:
+  ...         try:
+  ...             ch, data = readchannel(conn)
+  ...             if not data.startswith('  '):
+  ...                 print '%c, %r' % (ch, data)
+  ...         except EOFError:
+  ...             break
+  >>> check(earlycrash, server.connect)
+  e, 'Traceback (most recent call last):\n'
+  e, "IOError: *" (glob)
+  >>> server.shutdown()
+
+  $ cat .hg/server.log | grep -v '^  '
+  listening at .hg/server.sock
+  Traceback (most recent call last):
+  IOError: * (glob)
+  killed!
 #endif
 #if no-unix-socket