[PATCH] Flush password prompts for non-terminal callers

Steven Streeting steve at stevestreeting.com
Sat Jan 15 09:40:31 CST 2011


# HG changeset patch
# User Steve Streeting <steve at stevestreeting.com>
# Date 1295105307 0
# Node ID 407ab604cbb7b923f8e517e5f4858b0005bc14d0
# Parent  8f72d2f6c26322c235602280ea0a2b3debf37b06
Ensure that password prompts are flushed so that any non-terminal waiting for them on stderr can reliably see them. This is required to do interactive login from non-terminal clients, without forcing the user to pre-populate their configuration parameters. Without this feature, hg commands which require authentication which hasn't been pre-configured will simply randomly hang waiting for input without the calling program being any the wiser. Flushing the prompt means it always has a chance to know that hg is waiting for a response.
This is discussed in more detail in this tracker item: http://mercurial.selenic.com/bts/issue2590

diff --git a/mercurial/ui.py b/mercurial/ui.py
--- a/mercurial/ui.py
+++ b/mercurial/ui.py
@@ -468,7 +468,12 @@
                 # windows sometimes raises something other than ImportError
             except Exception:
                 pass
-        line = raw_input(prompt)
+        # prompt using read_line instead of raw_input which ensures prompt is flushed
+        self.write_err(prompt)
+        line = sys.stdin.readline()
+        # get rid of \r
+        if line and line[-1] == '\r':
+            line = line[:-1]
         # 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':
@@ -508,7 +513,13 @@
         if not self.interactive():
             return default
         try:
-            return getpass.getpass(prompt or _('password: '))
+            # Ensure we flush so that we can read prompt in non-terminal
+            self.write_err('password:')
+            pwd = sys.stdin.readline() 
+            # get rid of \r
+            if pwd and pwd[-1] == '\r':
+                pwd = pwd[:-1]
+            return pwd
         except EOFError:
             raise util.Abort(_('response expected'))
     def status(self, *msg, **opts):



More information about the Mercurial-devel mailing list