[PATCH] pager: preserve Hg's exit code (and fix Windows support) (issue3225)
Brodie Rao
brodie at bitheap.org
Fri May 11 08:51:25 CDT 2012
On Fri, May 11, 2012 at 3:49 PM, <brodie at bitheap.org> wrote:
> # HG changeset patch
> # User Brodie Rao <brodie at sf.io>
> # Date 1336743937 -7200
> # Branch stable
FYI: This was supposed to be flagged for stable in the email subject,
but I messed up my patchbomb command.
> # Node ID e11b4d33bf59e5f51fe5224e590f85bbfce8bde0
> # Parent e22d6b1dec1d4bda684a8d90e8d4852500d69495
> pager: preserve Hg's exit code (and fix Windows support) (issue3225)
>
> This changes how the pager extension invokes the pager. Prior to this change,
> the extension would fork Hg and exec the pager in the parent process. This
> loses Hg exit code, and it doesn't work on Windows.
>
> Now the pager is invoked using the subprocess library, and an atexit handler is
> registered that makes Hg wait for the pager to exit before it exits itself.
>
> Note that if you exit the pager before Hg is done running, you'll get an exit
> code of 255, which is caused by Python blowing up due to a broken pipe. If you
> set pager.quiet=True, you'll get the OS-level return code of 141.
>
> diff --git a/hgext/pager.py b/hgext/pager.py
> --- a/hgext/pager.py
> +++ b/hgext/pager.py
> @@ -53,37 +53,27 @@ used. Use a boolean value like yes, no,
> normal behavior.
> '''
>
> -import sys, os, signal, shlex, errno
> +import atexit, sys, os, signal, subprocess
> from mercurial import commands, dispatch, util, extensions
> from mercurial.i18n import _
>
> def _runpager(p):
> - if not util.safehasattr(os, 'fork'):
> - sys.stdout = util.popen(p, 'wb')
> - if util.isatty(sys.stderr):
> - sys.stderr = sys.stdout
> - return
> - fdin, fdout = os.pipe()
> - pid = os.fork()
> - if pid == 0:
> - os.close(fdin)
> - os.dup2(fdout, sys.stdout.fileno())
> - if util.isatty(sys.stderr):
> - os.dup2(fdout, sys.stderr.fileno())
> - os.close(fdout)
> - return
> - os.dup2(fdin, sys.stdin.fileno())
> - os.close(fdin)
> - os.close(fdout)
> - try:
> - os.execvp('/bin/sh', ['/bin/sh', '-c', p])
> - except OSError, e:
> - if e.errno == errno.ENOENT:
> - # no /bin/sh, try executing the pager directly
> - args = shlex.split(p)
> - os.execvp(args[0], args)
> - else:
> - raise
> + pager = subprocess.Popen(p, shell=True, bufsize=-1,
> + close_fds=util.closefds, stdin=subprocess.PIPE,
> + stdout=sys.stdout, stderr=sys.stderr)
> +
> + stdout = os.dup(sys.stdout.fileno())
> + stderr = os.dup(sys.stderr.fileno())
> + os.dup2(pager.stdin.fileno(), sys.stdout.fileno())
> + if util.isatty(sys.stderr):
> + os.dup2(pager.stdin.fileno(), sys.stderr.fileno())
> +
> + @atexit.register
> + def killpager():
> + pager.stdin.close()
> + os.dup2(stdout, sys.stdout.fileno())
> + os.dup2(stderr, sys.stderr.fileno())
> + pager.wait()
>
> def uisetup(ui):
> if ui.plain() or '--debugger' in sys.argv or not util.isatty(sys.stdout):
More information about the Mercurial-devel
mailing list