changeset 5337:8c5ef3b87cb1

Don't try to determine interactivity if ui() called with interactive=False. WSGI applications are not supposed to refer to sys.stdin. In ed6df6b1c29a, hgweb and hgwebdir were fixed to pass interactive=False to their ui()'s, but sys.stdin.isatty() was still called by the ui objects. This change makes sure only the ui.fixconfig() method will call ui.isatty() (by making the ui._readline() method, which is currently only called from ui.prompt(), private). ui.fixconfig() is changed to let config files override the initial interactivity setting, but not check isatty() if interactive=False was specified in the creation of the ui.
author Dirkjan Ochtman <dirkjan@ochtman.nl>
date Tue, 25 Sep 2007 19:05:34 +0200
parents 24de027551c1
children f87685355c9c
files mercurial/ui.py tests/test-non-interactive-wsgi tests/test-non-interactive-wsgi.out
diffstat 3 files changed, 88 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -211,9 +211,11 @@ class ui(object):
             if name is None or name in ('quiet', 'verbose', 'debug'):
                 self.verbosity_constraints()
             if name is None or name == 'interactive':
-                self.interactive = self.configbool("ui", "interactive", None)
-                if self.interactive is None:
+                interactive = self.configbool("ui", "interactive", None)
+                if interactive is None and self.interactive:
                     self.interactive = self.isatty()
+                else:
+                    self.interactive = interactive
             if name is None or name == 'report_untrusted':
                 self.report_untrusted = (
                     self.configbool("ui", "report_untrusted", True))
@@ -391,7 +393,7 @@ class ui(object):
         try: sys.stderr.flush()
         except: pass
 
-    def readline(self, prompt=''):
+    def _readline(self, prompt=''):
         if self.isatty():
             try:
                 # magically add command line editing support, where
@@ -406,7 +408,7 @@ class ui(object):
     def prompt(self, msg, pat=None, default="y", matchflags=0):
         if not self.interactive: return default
         try:
-            r = self.readline(msg + ' ')
+            r = self._readline(msg + ' ')
             if not pat or re.match(pat, r, matchflags):
                 return r
             else:
new file mode 100755
--- /dev/null
+++ b/tests/test-non-interactive-wsgi
@@ -0,0 +1,70 @@
+#!/bin/sh
+
+mkdir repo
+cd repo
+hg init
+echo foo > bar
+hg add bar
+hg commit -m "test" -d "0 0"
+hg tip
+
+cat > request.py <<EOF
+from mercurial import dispatch
+from mercurial.hgweb.hgweb_mod import hgweb
+from mercurial.hgweb.request import _wsgirequest
+from mercurial.ui import ui
+from mercurial import hg
+from StringIO import StringIO
+import sys
+
+class FileLike(object):
+    def __init__(self, real):
+        self.real = real
+    def fileno(self):
+        print >> sys.__stdout__, 'FILENO'
+        return self.real.fileno()
+    def read(self):
+        print >> sys.__stdout__, 'READ'
+        return self.real.read()
+    def readline(self):
+        print >> sys.__stdout__, 'READLINE'
+        return self.real.readline()
+    def isatty(self):
+        print >> sys.__stdout__, 'ISATTY'
+        return False
+
+sys.stdin = FileLike(sys.stdin)
+errors = StringIO()
+input = StringIO()
+output = StringIO()
+
+def startrsp(headers, data):
+	print '---- HEADERS'
+	print headers
+	print '---- DATA'
+	print data
+	return output.write
+
+env = {
+	'wsgi.version': (1, 0),
+	'wsgi.url_scheme': 'http',
+	'wsgi.errors': errors,
+	'wsgi.input': input,
+	'wsgi.multithread': False,
+	'wsgi.multiprocess': False,
+	'wsgi.run_once': False,
+	'REQUEST_METHOD': 'GET',
+	'SCRIPT_NAME': '',
+	'PATH_INFO': '',
+	'QUERY_STRING': '',
+	'SERVER_NAME': '127.0.0.1',
+	'SERVER_PORT': '20059',
+	'SERVER_PROTOCOL': 'HTTP/1.0'
+}
+
+_wsgirequest(hgweb('.'), env, startrsp)
+print '---- ERRORS'
+print errors.getvalue()
+EOF
+
+python request.py
new file mode 100644
--- /dev/null
+++ b/tests/test-non-interactive-wsgi.out
@@ -0,0 +1,12 @@
+changeset:   0:61c9426e69fe
+tag:         tip
+user:        test
+date:        Thu Jan 01 00:00:00 1970 +0000
+summary:     test
+
+---- HEADERS
+200 Script output follows
+---- DATA
+[('content-type', 'text/html; charset=ascii')]
+---- ERRORS
+