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? | |||||
mharbison72Unsubmitted Not Done 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?