[PATCH stable] pager: fork and exec pager as parent process

Augie Fackler durin42 at gmail.com
Sat May 15 11:04:11 CDT 2010


This looks reasonable to me, and I don't know that I ever commented on it.

Did you ever push it?

On May 3, 2010, at 2:06 PM, Brodie Rao wrote:

> # HG changeset patch
> # User Brodie Rao <brodie at bitheap.org>
> # Date 1272913234 18000
> # Branch stable
> # Node ID d7625733fa0f33b913f7432941ba436f4645cea9
> # Parent  b8d0b4721affa90241f304272e0836ba566d0b3a
> 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().
> 
> diff --git a/hgext/color.py b/hgext/color.py
> --- a/hgext/color.py
> +++ b/hgext/color.py
> @@ -333,11 +333,14 @@ def extsetup(ui):
> 
> 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)
> diff --git a/hgext/pager.py b/hgext/pager.py
> --- a/hgext/pager.py
> +++ b/hgext/pager.py
> @@ -49,9 +49,27 @@ To ignore global commands like "hg versi
> 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 @@ def uisetup(ui):
>             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)



More information about the Mercurial-devel mailing list