Details
Details
- Reviewers
indygreg - Group Reviewers
hg-reviewers - Commits
- rHG2e09d1cae90c: logtoprocess: use new runbgcommand from procutil
Diff Detail
Diff Detail
- Repository
- rHG Mercurial
- Lint
Lint Skipped - Unit
Unit Tests Skipped
indygreg |
hg-reviewers |
Lint Skipped |
Unit Tests Skipped |
Path | Packages | |||
---|---|---|---|---|
M | hgext/logtoprocess.py (53 lines) |
Commit | Parents | Author | Summary | Date |
---|---|---|---|---|
Augie Fackler | Oct 3 2018, 2:01 PM |
Status | Author | Revision | |
---|---|---|---|
Closed | pulkit | ||
Closed | pulkit | ||
Closed | pulkit | ||
Closed | pulkit | ||
Closed | pulkit | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 | ||
Closed | durin42 |
not ensure that they exit cleanly. | not ensure that they exit cleanly. | ||||
""" | """ | ||||
from __future__ import absolute_import | from __future__ import absolute_import | ||||
import itertools | import itertools | ||||
import os | import os | ||||
import subprocess | |||||
import sys | |||||
from mercurial import ( | |||||
pycompat, | |||||
) | |||||
from mercurial.utils import ( | from mercurial.utils import ( | ||||
procutil, | procutil, | ||||
) | ) | ||||
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for | ||||
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should | ||||
# be specifying the version(s) of Mercurial they are tested with, or | # be specifying the version(s) of Mercurial they are tested with, or | ||||
# leave the attribute unspecified. | # leave the attribute unspecified. | ||||
testedwith = 'ships-with-hg-core' | testedwith = 'ships-with-hg-core' | ||||
def uisetup(ui): | def uisetup(ui): | ||||
if pycompat.iswindows: | |||||
# no fork on Windows, but we can create a detached process | |||||
# https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863.aspx | |||||
# No stdlib constant exists for this value | |||||
DETACHED_PROCESS = 0x00000008 | |||||
_creationflags = DETACHED_PROCESS | subprocess.CREATE_NEW_PROCESS_GROUP | |||||
def runshellcommand(script, env): | |||||
# we can't use close_fds *and* redirect stdin. I'm not sure that we | |||||
# need to because the detached process has no console connection. | |||||
subprocess.Popen( | |||||
procutil.tonativestr(script), | |||||
indygreg: `tonativestr` is lost as part of the function port. Do we need it for Py3? | |||||
Yes, and also the environment fix up too for Windows. But it probably should go in D4938. mharbison72: Yes, and also the environment fix up too for Windows. But it probably should go in D4938. | |||||
shell=True, env=procutil.tonativeenv(env), close_fds=True, | |||||
creationflags=_creationflags) | |||||
else: | |||||
def runshellcommand(script, env): | |||||
# double-fork to completely detach from the parent process | |||||
# based on http://code.activestate.com/recipes/278731 | |||||
pid = os.fork() | |||||
if pid: | |||||
# parent | |||||
return | |||||
# subprocess.Popen() forks again, all we need to add is | |||||
# flag the new process as a new session. | |||||
if sys.version_info < (3, 2): | |||||
newsession = {'preexec_fn': os.setsid} | |||||
else: | |||||
newsession = {'start_new_session': True} | |||||
try: | |||||
# connect std* to devnull to make sure the subprocess can't | |||||
# muck up these stream for mercurial. | |||||
# Connect all the streams to be more close to Windows behavior | |||||
# and pager will wait for scripts to end if we don't do that | |||||
nullrfd = open(os.devnull, 'r') | |||||
nullwfd = open(os.devnull, 'w') | |||||
subprocess.Popen( | |||||
procutil.tonativestr(script), | |||||
shell=True, stdin=nullrfd, | |||||
stdout=nullwfd, stderr=nullwfd, | |||||
env=procutil.tonativeenv(env), | |||||
close_fds=True, **newsession) | |||||
finally: | |||||
# mission accomplished, this child needs to exit and not | |||||
# continue the hg process here. | |||||
os._exit(0) | |||||
class logtoprocessui(ui.__class__): | class logtoprocessui(ui.__class__): | ||||
def log(self, event, *msg, **opts): | def log(self, event, *msg, **opts): | ||||
"""Map log events to external commands | """Map log events to external commands | ||||
Arguments are passed on as environment variables. | Arguments are passed on as environment variables. | ||||
""" | """ | ||||
for i, m in enumerate(messages, 1)) | for i, m in enumerate(messages, 1)) | ||||
# keyword arguments get prefixed with OPT_ and uppercased | # keyword arguments get prefixed with OPT_ and uppercased | ||||
optpairs = ( | optpairs = ( | ||||
('OPT_{0}'.format(key.upper()), str(value)) | ('OPT_{0}'.format(key.upper()), str(value)) | ||||
for key, value in opts.iteritems()) | for key, value in opts.iteritems()) | ||||
env = dict(itertools.chain(procutil.shellenviron().items(), | env = dict(itertools.chain(procutil.shellenviron().items(), | ||||
msgpairs, optpairs), | msgpairs, optpairs), | ||||
EVENT=event, HGPID=str(os.getpid())) | EVENT=event, HGPID=str(os.getpid())) | ||||
runshellcommand(script, env) | procutil.runbgcommand(script, env, shell=True) | ||||
return super(logtoprocessui, self).log(event, *msg, **opts) | return super(logtoprocessui, self).log(event, *msg, **opts) | ||||
# Replace the class for this instance and all clones created from it: | # Replace the class for this instance and all clones created from it: | ||||
ui.__class__ = logtoprocessui | ui.__class__ = logtoprocessui |
tonativestr is lost as part of the function port. Do we need it for Py3?