ui: use I/O descriptors internally
authorIdan Kamara <idankk86@gmail.com>
Wed, 08 Jun 2011 01:39:20 +0300
changeset 14614 afccc64eea73
parent 14613 ea8938d3a5aa
child 14615 9fba795dd030
ui: use I/O descriptors internally and as a result: - fix webproto to redirect the ui descriptors instead of sys.stdout/err - fix sshserver to use the ui descriptors
mercurial/hgweb/protocol.py
mercurial/sshserver.py
mercurial/ui.py
tests/test-ui-color.py
--- a/mercurial/hgweb/protocol.py	Tue Jun 07 13:39:09 2011 +0300
+++ b/mercurial/hgweb/protocol.py	Wed Jun 08 01:39:20 2011 +0300
@@ -5,16 +5,17 @@
 # This software may be used and distributed according to the terms of the
 # GNU General Public License version 2 or any later version.
 
-import cgi, cStringIO, zlib, sys, urllib
+import cgi, cStringIO, zlib, urllib
 from mercurial import util, wireproto
 from common import HTTP_OK
 
 HGTYPE = 'application/mercurial-0.1'
 
 class webproto(object):
-    def __init__(self, req):
+    def __init__(self, req, ui):
         self.req = req
         self.response = ''
+        self.ui = ui
     def getargs(self, args):
         knownargs = self._args()
         data = {}
@@ -46,8 +47,12 @@
         for s in util.filechunkiter(self.req, limit=length):
             fp.write(s)
     def redirect(self):
-        self.oldio = sys.stdout, sys.stderr
-        sys.stderr = sys.stdout = cStringIO.StringIO()
+        self.oldio = self.ui.fout, self.ui.ferr
+        self.ui.ferr = self.ui.fout = cStringIO.StringIO()
+    def restore(self):
+        val = self.ui.fout.getvalue()
+        self.ui.ferr, self.ui.fout = self.oldio
+        return val
     def groupchunks(self, cg):
         z = zlib.compressobj()
         while True:
@@ -66,7 +71,7 @@
     return cmd in wireproto.commands
 
 def call(repo, req, cmd):
-    p = webproto(req)
+    p = webproto(req, repo.ui)
     rsp = wireproto.dispatch(repo, p, cmd)
     if isinstance(rsp, str):
         req.respond(HTTP_OK, HGTYPE, length=len(rsp))
@@ -75,14 +80,13 @@
         req.respond(HTTP_OK, HGTYPE)
         return rsp.gen
     elif isinstance(rsp, wireproto.pushres):
-        val = sys.stdout.getvalue()
-        sys.stdout, sys.stderr = p.oldio
+        val = p.restore()
         req.respond(HTTP_OK, HGTYPE)
         return ['%d\n%s' % (rsp.res, val)]
     elif isinstance(rsp, wireproto.pusherr):
         # drain the incoming bundle
         req.drain()
-        sys.stdout, sys.stderr = p.oldio
+        p.restore()
         rsp = '0\n%s\n' % rsp.res
         req.respond(HTTP_OK, HGTYPE, length=len(rsp))
         return [rsp]
--- a/mercurial/sshserver.py	Tue Jun 07 13:39:09 2011 +0300
+++ b/mercurial/sshserver.py	Wed Jun 08 01:39:20 2011 +0300
@@ -14,11 +14,11 @@
         self.ui = ui
         self.repo = repo
         self.lock = None
-        self.fin = sys.stdin
-        self.fout = sys.stdout
+        self.fin = ui.fin
+        self.fout = ui.fout
 
         hook.redirect(True)
-        sys.stdout = sys.stderr
+        ui.fout = repo.ui.fout = ui.ferr
 
         # Prevent insertion/deletion of CRs
         util.setbinary(self.fin)
--- a/mercurial/ui.py	Tue Jun 07 13:39:09 2011 +0300
+++ b/mercurial/ui.py	Wed Jun 08 01:39:20 2011 +0300
@@ -443,26 +443,26 @@
             self._buffers[-1].extend([str(a) for a in args])
         else:
             for a in args:
-                sys.stdout.write(str(a))
+                self.fout.write(str(a))
 
     def write_err(self, *args, **opts):
         try:
-            if not getattr(sys.stdout, 'closed', False):
-                sys.stdout.flush()
+            if not getattr(self.fout, 'closed', False):
+                self.fout.flush()
             for a in args:
-                sys.stderr.write(str(a))
+                self.ferr.write(str(a))
             # stderr may be buffered under win32 when redirected to files,
             # including stdout.
-            if not getattr(sys.stderr, 'closed', False):
-                sys.stderr.flush()
+            if not getattr(self.ferr, 'closed', False):
+                self.ferr.flush()
         except IOError, inst:
             if inst.errno not in (errno.EPIPE, errno.EIO):
                 raise
 
     def flush(self):
-        try: sys.stdout.flush()
+        try: self.fout.flush()
         except: pass
-        try: sys.stderr.flush()
+        try: self.ferr.flush()
         except: pass
 
     def interactive(self):
@@ -483,7 +483,7 @@
         if i is None:
             # some environments replace stdin without implementing isatty
             # usually those are non-interactive
-            return util.isatty(sys.stdin)
+            return util.isatty(self.fin)
 
         return i
 
@@ -521,12 +521,12 @@
         if i is None:
             # some environments replace stdout without implementing isatty
             # usually those are non-interactive
-            return util.isatty(sys.stdout)
+            return util.isatty(self.fout)
 
         return i
 
     def _readline(self, prompt=''):
-        if util.isatty(sys.stdin):
+        if util.isatty(self.fin):
             try:
                 # magically add command line editing support, where
                 # available
@@ -536,7 +536,14 @@
                 # windows sometimes raises something other than ImportError
             except Exception:
                 pass
+
+        # instead of trying to emulate raw_input, swap our in/out
+        # with sys.stdin/out
+        old = sys.stdout, sys.stdin
+        sys.stdout, sys.stdin = self.fout, self.fin
         line = raw_input(prompt)
+        sys.stdout, sys.stdin = old
+
         # When stdin is in binary mode on Windows, it can cause
         # raw_input() to emit an extra trailing carriage return
         if os.linesep == '\r\n' and line and line[-1] == '\r':
--- a/tests/test-ui-color.py	Tue Jun 07 13:39:09 2011 +0300
+++ b/tests/test-ui-color.py	Wed Jun 08 01:39:20 2011 +0300
@@ -19,13 +19,13 @@
 ui_ = ui.ui()
 ui_.setconfig('ui', 'formatted', 'True')
 
+# we're not interested in the output, so write that to devnull
+ui_.fout = open(os.devnull, 'w')
+
 # call some arbitrary command just so we go through
 # color's wrapped _runcommand twice.
-# we're not interested in the output, so write that to devnull
 def runcmd():
-    sys.stdout = open(os.devnull, 'w')
     dispatch.dispatch(dispatch.request(['version', '-q'], ui_))
-    sys.stdout = sys.__stdout__
 
 runcmd()
 print "colored? " + str(issubclass(ui_.__class__, color.colorui))