changeset 11182:3c368a1c962d stable

pager: fork and exec pager as parent process With the pager as the child process instead of the parent process, the termination of the parent Mercurial process can cause the terminal to return before the pager exits. Inverting the relationship prevents that issue. Platforms without fork() will continue to use util.popen().
author Brodie Rao <brodie@bitheap.org>
date Mon, 03 May 2010 14:00:34 -0500
parents 3b3261f6d9ba
children a890cc501501 db2897926d14
files hgext/color.py hgext/pager.py
diffstat 2 files changed, 24 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/hgext/color.py	Thu May 13 11:30:50 2010 -0500
+++ b/hgext/color.py	Mon May 03 14:00:34 2010 -0500
@@ -333,11 +333,14 @@
 
 def _setupcmd(ui, cmd, table, func, effectsmap):
     '''patch in command to command table and load effect map'''
+    # check isatty() before anything else changes it (like pager)
+    isatty = sys.__stdout__.isatty()
+
     def nocolor(orig, *args, **opts):
 
         if (opts['no_color'] or opts['color'] == 'never' or
             (opts['color'] == 'auto' and (os.environ.get('TERM') == 'dumb'
-                                          or not sys.__stdout__.isatty()))):
+                                          or not isatty))):
             del opts['no_color']
             del opts['color']
             return orig(*args, **opts)
--- a/hgext/pager.py	Thu May 13 11:30:50 2010 -0500
+++ b/hgext/pager.py	Mon May 03 14:00:34 2010 -0500
@@ -49,9 +49,27 @@
 specify them in the global .hgrc
 '''
 
-import sys, os, signal
+import sys, os, signal, shlex
 from mercurial import dispatch, util, extensions
 
+def _runpager(p):
+    if not hasattr(os, 'fork'):
+        sys.stderr = sys.stdout = util.popen(p, 'wb')
+        return
+    fdin, fdout = os.pipe()
+    pid = os.fork()
+    if pid == 0:
+        os.close(fdin)
+        os.dup2(fdout, sys.stdout.fileno())
+        os.dup2(fdout, sys.stderr.fileno())
+        os.close(fdout)
+        return
+    os.dup2(fdin, sys.stdin.fileno())
+    os.close(fdin)
+    os.close(fdout)
+    args = shlex.split(p)
+    os.execvp(args[0], args)
+
 def uisetup(ui):
     def pagecmd(orig, ui, options, cmd, cmdfunc):
         p = ui.config("pager", "pager", os.environ.get("PAGER"))
@@ -60,7 +78,7 @@
             if (cmd in attend or
                 (cmd not in ui.configlist('pager', 'ignore') and not attend)):
                 ui.setconfig('ui', 'interactive', False)
-                sys.stderr = sys.stdout = util.popen(p, "wb")
+                _runpager(p)
                 if ui.configbool('pager', 'quiet'):
                     signal.signal(signal.SIGPIPE, signal.SIG_DFL)
         return orig(ui, options, cmd, cmdfunc)