diff options
Diffstat (limited to 'engine/SCons/Action.py')
| -rw-r--r-- | engine/SCons/Action.py | 60 | 
1 files changed, 36 insertions, 24 deletions
diff --git a/engine/SCons/Action.py b/engine/SCons/Action.py index ce5471d..be4a5ff 100644 --- a/engine/SCons/Action.py +++ b/engine/SCons/Action.py @@ -77,7 +77,7 @@ way for wrapping up the functions.  """ -# Copyright (c) 2001 - 2017 The SCons Foundation +# Copyright (c) 2001 - 2019 The SCons Foundation  #  # Permission is hereby granted, free of charge, to any person obtaining  # a copy of this software and associated documentation files (the @@ -98,7 +98,7 @@ way for wrapping up the functions.  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -__revision__ = "src/engine/SCons/Action.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog" +__revision__ = "src/engine/SCons/Action.py 72ae09dc35ac2626f8ff711d8c4b30b6138e08e3 2019-08-08 14:50:06 bdeegan"  import os  import pickle @@ -107,6 +107,7 @@ import sys  import subprocess  import itertools  import inspect +from collections import OrderedDict  import SCons.Debug  from SCons.Debug import logInstanceCreation @@ -115,8 +116,7 @@ import SCons.Util  import SCons.Subst  # we use these a lot, so try to optimize them -is_String = SCons.Util.is_String -is_List = SCons.Util.is_List +from SCons.Util import is_String, is_List  class _null(object):      pass @@ -211,7 +211,7 @@ def _object_contents(obj):  def _code_contents(code, docstring=None): -    """Return the signature contents of a code object. +    r"""Return the signature contents of a code object.      By providing direct access to the code object of the      function, Python makes this extremely easy.  Hooray! @@ -258,8 +258,7 @@ def _code_contents(code, docstring=None):      # function. Note that we have to call _object_contents on each      # constants because the code object of nested functions can      # show-up among the constants. - -    z = [_object_contents(cc) for cc in code.co_consts[1:]] +    z = [_object_contents(cc) for cc in code.co_consts if cc != docstring]      contents.extend(b',(')      contents.extend(bytearray(',', 'utf-8').join(z))      contents.extend(b')') @@ -535,7 +534,7 @@ class ActionBase(object):          result = self.get_presig(target, source, env)          if not isinstance(result,(bytes, bytearray)): -            result = bytearray("",'utf-8').join([ SCons.Util.to_bytes(r) for r in result ]) +            result = bytearray(result, 'utf-8')          else:              # Make a copy and put in bytearray, without this the contents returned by get_presig              # can be changed by the logic below, appending with each call and causing very @@ -768,16 +767,22 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):      it'll have to be tweaked to get the full desired functionality.      one special arg (so far?), 'error', to tell what to do with exceptions.      """ -    # allow std{in,out,err} to be "'devnull'" -    io = kw.get('stdin') -    if is_String(io) and io == 'devnull': -        kw['stdin'] = open(os.devnull) -    io = kw.get('stdout') -    if is_String(io) and io == 'devnull': -        kw['stdout'] = open(os.devnull, 'w') -    io = kw.get('stderr') -    if is_String(io) and io == 'devnull': -        kw['stderr'] = open(os.devnull, 'w') +    # allow std{in,out,err} to be "'devnull'".  This is like +    # subprocess.DEVNULL, which does not exist for Py2. Use the +    # subprocess one if possible. +    # Clean this up when Py2 support is dropped +    try: +        from subprocess import DEVNULL +    except ImportError: +        DEVNULL = None + +    for stream in 'stdin', 'stdout', 'stderr': +        io = kw.get(stream) +        if is_String(io) and io == 'devnull': +            if DEVNULL: +                kw[stream] = DEVNULL +            else: +                kw[stream] = open(os.devnull, "r+")      # Figure out what shell environment to use      ENV = kw.get('env', None) @@ -803,7 +808,7 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):      kw['env'] = new_env      try: -        return subprocess.Popen(cmd, **kw) +        pobj = subprocess.Popen(cmd, **kw)      except EnvironmentError as e:          if error == 'raise': raise          # return a dummy Popen instance that only returns error @@ -817,7 +822,14 @@ def _subproc(scons_env, cmd, error = 'ignore', **kw):                  def readline(self): return ''                  def __iter__(self): return iter(())              stdout = stderr = f() -        return dummyPopen(e) +        pobj = dummyPopen(e) +    finally: +        # clean up open file handles stored in parent's kw +        for k, v in kw.items(): +            if inspect.ismethod(getattr(v, 'close', None)): +                v.close() + +    return pobj  class CommandAction(_ActionAction): @@ -837,8 +849,8 @@ class CommandAction(_ActionAction):          _ActionAction.__init__(self, **kw)          if is_List(cmd):              if [c for c in cmd if is_List(c)]: -                raise TypeError("CommandAction should be given only " \ -                      "a single command") +                raise TypeError("CommandAction should be given only " +                                "a single command")          self.cmd_list = cmd      def __str__(self): @@ -1086,7 +1098,7 @@ class LazyAction(CommandGeneratorAction, CommandAction):      def get_parent_class(self, env):          c = env.get(self.var) -        if is_String(c) and not '\n' in c: +        if is_String(c) and '\n' not in c:              return CommandAction          return CommandGeneratorAction @@ -1289,7 +1301,7 @@ class ListAction(ActionBase):          return result      def get_varlist(self, target, source, env, executor=None): -        result = SCons.Util.OrderedDict() +        result = OrderedDict()          for act in self.list:              for var in act.get_varlist(target, source, env, executor):                  result[var] = True  | 
