# HG changeset patch # User Idan Kamara # Date 2011-06-07 22:39:20 # Node ID afccc64eea735b127848c12a91a4d918ebcd5b77 # Parent ea8938d3a5aa6efa01f7d26566f20bdcae5d51ad 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 diff --git a/mercurial/hgweb/protocol.py b/mercurial/hgweb/protocol.py --- a/mercurial/hgweb/protocol.py +++ b/mercurial/hgweb/protocol.py @@ -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 @@ class webproto(object): 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 @@ def iscmd(cmd): 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 @@ def call(repo, req, cmd): 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] diff --git a/mercurial/sshserver.py b/mercurial/sshserver.py --- a/mercurial/sshserver.py +++ b/mercurial/sshserver.py @@ -14,11 +14,11 @@ class sshserver(object): 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) diff --git a/mercurial/ui.py b/mercurial/ui.py --- a/mercurial/ui.py +++ b/mercurial/ui.py @@ -443,26 +443,26 @@ class ui(object): 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 @@ class ui(object): 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 @@ class ui(object): 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 @@ class ui(object): # 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': diff --git a/tests/test-ui-color.py b/tests/test-ui-color.py --- a/tests/test-ui-color.py +++ b/tests/test-ui-color.py @@ -19,13 +19,13 @@ hgrc.close() 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))