sapling/hgext3rd/extutil.py
Stanislau Hlebik 2a0e8205d4 extutil: create new package and move runshellfast here
Summary:
I'm going to use runshellfast in infinitepush.
To avoid copy-paste let's move it to the separate package.
Note: fastmanifest also has runshellfast but it's implementation
is a bit different and seems that it doesn't work with remotefilelog.
So I'll leave it alone for now.

Test Plan: python run-tests.py -j20

Reviewers: #sourcecontrol

Subscribers: mjpieters

Differential Revision: https://phabricator.intern.facebook.com/D4175836
2016-11-21 00:52:30 -08:00

81 lines
3.0 KiB
Python

# extutil.py - useful utility methods for extensions
#
# Copyright 2016 Facebook
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
import os
import platform
import subprocess
import sys
if platform.system() == 'Windows':
# 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(
script, shell=True, env=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 stdin to devnull to make sure the subprocess can't
# muck up that stream for mercurial.
subprocess.Popen(
script, shell=True, stdout=open(os.devnull, 'w'),
stderr=open(os.devnull, 'w'), stdin=open(os.devnull, 'r'),
env=env, close_fds=True, **newsession)
finally:
# mission accomplished, this child needs to exit and not
# continue the hg process here.
os._exit(0)
def replaceclass(container, classname):
'''Replace a class with another in a module, and interpose it into
the hierarchies of all loaded subclasses. This function is
intended for use as a decorator.
import mymodule
@replaceclass(mymodule, 'myclass')
class mysubclass(mymodule.myclass):
def foo(self):
f = super(mysubclass, self).foo()
return f + ' bar'
Existing instances of the class being replaced will not have their
__class__ modified, so call this function before creating any
objects of the target type.
'''
def wrap(cls):
oldcls = getattr(container, classname)
for subcls in oldcls.__subclasses__():
if subcls is not cls:
assert oldcls in subcls.__bases__
newbases = [oldbase
for oldbase in subcls.__bases__
if oldbase != oldcls]
newbases.append(cls)
subcls.__bases__ = tuple(newbases)
setattr(container, classname, cls)
return cls
return wrap