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
--- 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))