diff options
Diffstat (limited to 'script/sconsign')
| -rw-r--r-- | script/sconsign | 299 | 
1 files changed, 198 insertions, 101 deletions
diff --git a/script/sconsign b/script/sconsign index 7391807..7c5dda5 100644 --- a/script/sconsign +++ b/script/sconsign @@ -2,7 +2,7 @@  #  # SCons - a Software Constructor  # -# 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 @@ -25,17 +25,17 @@  from __future__ import print_function -__revision__ = "src/script/sconsign.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog" +__revision__ = "src/script/sconsign.py 72ae09dc35ac2626f8ff711d8c4b30b6138e08e3 2019-08-08 14:50:06 bdeegan" -__version__ = "3.0.1" +__version__ = "3.1.1" -__build__ = "74b2c53bc42290e911b334a6b44f187da698a668" +__build__ = "72ae09dc35ac2626f8ff711d8c4b30b6138e08e3" -__buildsys__ = "hpmicrodog" +__buildsys__ = "octodog" -__date__ = "2017/11/14 13:16:53" +__date__ = "2019-08-08 14:50:06" -__developer__ = "bdbaddog" +__developer__ = "bdeegan"  import os  import sys @@ -49,48 +49,53 @@ import sys  # should also change other scripts that use this same header.  ############################################################################## -# Strip the script directory from sys.path() so on case-insensitive -# (WIN32) systems Python doesn't think that the "scons" script is the -# "SCons" package.  Replace it with our own library directories -# (version-specific first, in case they installed by hand there, -# followed by generic) so we pick up the right version of the build -# engine modules if they're in either directory. - +# compatibility check +if (3,0,0) < sys.version_info < (3,5,0) or sys.version_info < (2,7,0): +    msg = "scons: *** SCons version %s does not run under Python version %s.\n\ +Python 2.7 or >= 3.5 is required.\n" +    sys.stderr.write(msg % (__version__, sys.version.split()[0])) +    sys.exit(1) +# Strip the script directory from sys.path so on case-insensitive +# (WIN32) systems Python doesn't think that the "scons" script is the +# "SCons" package.  script_dir = os.path.dirname(os.path.realpath(__file__)) - -if script_dir in sys.path: -    sys.path.remove(script_dir) +script_path = os.path.realpath(os.path.dirname(__file__)) +if script_path in sys.path: +    sys.path.remove(script_path)  libs = []  if "SCONS_LIB_DIR" in os.environ:      libs.append(os.environ["SCONS_LIB_DIR"]) -# - running from source takes priority (since 2.3.2), excluding SCONS_LIB_DIR settings -script_path = os.path.abspath(os.path.dirname(__file__)) -source_path = os.path.join(script_path, '..', 'engine') -libs.append(source_path) +# running from source takes 2nd priority (since 2.3.2), following SCONS_LIB_DIR +source_path = os.path.join(script_path, os.pardir, 'engine') +if os.path.isdir(source_path): +    libs.append(source_path) +# add local-install locations  local_version = 'scons-local-' + __version__  local = 'scons-local'  if script_dir:      local_version = os.path.join(script_dir, local_version)      local = os.path.join(script_dir, local) -libs.append(os.path.abspath(local_version)) -libs.append(os.path.abspath(local)) +if os.path.isdir(local_version): +    libs.append(os.path.abspath(local_version)) +if os.path.isdir(local): +    libs.append(os.path.abspath(local))  scons_version = 'scons-%s' % __version__  # preferred order of scons lookup paths  prefs = [] +# if we can find package information, use it  try:      import pkg_resources  except ImportError:      pass  else: -    # when running from an egg add the egg's directory      try:          d = pkg_resources.get_distribution('scons')      except pkg_resources.DistributionNotFound: @@ -99,77 +104,76 @@ else:          prefs.append(d.location)  if sys.platform == 'win32': -    # sys.prefix is (likely) C:\Python*; -    # check only C:\Python*. +    # Use only sys.prefix on Windows      prefs.append(sys.prefix)      prefs.append(os.path.join(sys.prefix, 'Lib', 'site-packages'))  else:      # On other (POSIX) platforms, things are more complicated due to -    # the variety of path names and library locations.  Try to be smart -    # about it. +    # the variety of path names and library locations. +    # Build up some possibilities, then transform them into candidates +    temp = []      if script_dir == 'bin':          # script_dir is `pwd`/bin;          # check `pwd`/lib/scons*. -        prefs.append(os.getcwd()) +        temp.append(os.getcwd())      else: -        if script_dir == '.' or script_dir == '': +        if script_dir in ('.', ''):              script_dir = os.getcwd()          head, tail = os.path.split(script_dir)          if tail == "bin":              # script_dir is /foo/bin;              # check /foo/lib/scons*. -            prefs.append(head) +            temp.append(head)      head, tail = os.path.split(sys.prefix)      if tail == "usr":          # sys.prefix is /foo/usr;          # check /foo/usr/lib/scons* first,          # then /foo/usr/local/lib/scons*. -        prefs.append(sys.prefix) -        prefs.append(os.path.join(sys.prefix, "local")) +        temp.append(sys.prefix) +        temp.append(os.path.join(sys.prefix, "local"))      elif tail == "local":          h, t = os.path.split(head)          if t == "usr":              # sys.prefix is /foo/usr/local;              # check /foo/usr/local/lib/scons* first,              # then /foo/usr/lib/scons*. -            prefs.append(sys.prefix) -            prefs.append(head) +            temp.append(sys.prefix) +            temp.append(head)          else:              # sys.prefix is /foo/local;              # check only /foo/local/lib/scons*. -            prefs.append(sys.prefix) +            temp.append(sys.prefix)      else:          # sys.prefix is /foo (ends in neither /usr or /local);          # check only /foo/lib/scons*. -        prefs.append(sys.prefix) +        temp.append(sys.prefix) + +    # suffix these to add to our original prefs: +    prefs.extend([os.path.join(x, 'lib') for x in temp]) +    prefs.extend([os.path.join(x, 'lib', 'python' + sys.version[:3], +                               'site-packages') for x in temp]) -    temp = [os.path.join(x, 'lib') for x in prefs] -    temp.extend([os.path.join(x, -                                           'lib', -                                           'python' + sys.version[:3], -                                           'site-packages') for x in prefs]) -    prefs = temp      # Add the parent directory of the current python's library to the -    # preferences.  On SuSE-91/AMD64, for example, this is /usr/lib64, -    # not /usr/lib. +    # preferences.  This picks up differences between, e.g., lib and lib64, +    # and finds the base location in case of a non-copying virtualenv.      try:          libpath = os.__file__      except AttributeError:          pass      else:          # Split /usr/libfoo/python*/os.py to /usr/libfoo/python*. -        libpath, tail = os.path.split(libpath) +        libpath, _ = os.path.split(libpath)          # Split /usr/libfoo/python* to /usr/libfoo          libpath, tail = os.path.split(libpath)          # Check /usr/libfoo/scons*.          prefs.append(libpath)  # Look first for 'scons-__version__' in all of our preference libs, -# then for 'scons'. -libs.extend([os.path.join(x, scons_version) for x in prefs]) -libs.extend([os.path.join(x, 'scons') for x in prefs]) +# then for 'scons'.  Skip paths that do not exist. +libs.extend([os.path.join(x, scons_version) for x in prefs if os.path.isdir(x)]) +libs.extend([os.path.join(x, 'scons') for x in prefs if os.path.isdir(x)])  sys.path = libs + sys.path @@ -181,23 +185,23 @@ import SCons.compat  try:      import whichdb +      whichdb = whichdb.whichdb  except ImportError as e:      from dbm import whichdb  import time  import pickle -import imp  import SCons.SConsign +  def my_whichdb(filename):      if filename[-7:] == ".dblite":          return "SCons.dblite"      try: -        f = open(filename + ".dblite", "rb") -        f.close() -        return "SCons.dblite" +        with open(filename + ".dblite", "rb"): +            return "SCons.dblite"      except IOError:          pass      return _orig_whichdb(filename) @@ -212,6 +216,8 @@ whichdb = my_whichdb  #dbm.whichdb = my_whichdb  def my_import(mname): +    import imp +      if '.' in mname:          i = mname.rfind('.')          parent = my_import(mname[:i]) @@ -221,25 +227,41 @@ def my_import(mname):          fp, pathname, description = imp.find_module(mname)      return imp.load_module(mname, fp, pathname, description) +  class Flagger(object):      default_value = 1 +      def __setitem__(self, item, value):          self.__dict__[item] = value          self.default_value = 0 +      def __getitem__(self, item):          return self.__dict__.get(item, self.default_value) +  Do_Call = None  Print_Directories = []  Print_Entries = []  Print_Flags = Flagger()  Verbose = 0  Readable = 0 +Warns = 0 +  def default_mapper(entry, name): +    """ +    Stringify an entry that doesn't have an explicit mapping. + +    Args: +        entry:  entry +        name: field name + +    Returns: str + +    """      try: -        val = eval("entry."+name) -    except: +        val = eval("entry." + name) +    except AttributeError:          val = None      if sys.version_info.major >= 3 and isinstance(val, bytes):          # This is a dirty hack for py 2/3 compatibility. csig is a bytes object @@ -248,7 +270,18 @@ def default_mapper(entry, name):          val = val.decode()      return str(val) -def map_action(entry, name): + +def map_action(entry, _): +    """ +    Stringify an action entry and signature. + +    Args: +        entry: action entry +        second argument is not used + +    Returns: str + +    """      try:          bact = entry.bact          bactsig = entry.bactsig @@ -256,7 +289,18 @@ def map_action(entry, name):          return None      return '%s [%s]' % (bactsig, bact) -def map_timestamp(entry, name): + +def map_timestamp(entry, _): +    """ +    Stringify a timestamp entry. + +    Args: +        entry: timestamp entry +        second argument is not used + +    Returns: str + +    """      try:          timestamp = entry.timestamp      except AttributeError: @@ -266,19 +310,39 @@ def map_timestamp(entry, name):      else:          return str(timestamp) -def map_bkids(entry, name): + +def map_bkids(entry, _): +    """ +    Stringify an implicit entry. + +    Args: +        entry: +        second argument is not used + +    Returns: str + +    """      try:          bkids = entry.bsources + entry.bdepends + entry.bimplicit          bkidsigs = entry.bsourcesigs + entry.bdependsigs + entry.bimplicitsigs      except AttributeError:          return None -    result = [] -    for i in range(len(bkids)): -        result.append(nodeinfo_string(bkids[i], bkidsigs[i], "        ")) -    if result == []: + +    if len(bkids) != len(bkidsigs): +        global Warns +        Warns += 1 +        # add warning to result rather than direct print so it will line up +        msg = "Warning: missing information, {} ids but {} sigs" +        result = [msg.format(len(bkids), len(bkidsigs))] +    else: +        result = [] +    result += [nodeinfo_string(bkid, bkidsig, "        ") +               for bkid, bkidsig in zip(bkids, bkidsigs)] +    if not result:          return None      return "\n        ".join(result) +  map_field = {      'action'    : map_action,      'timestamp' : map_timestamp, @@ -289,6 +353,7 @@ map_name = {      'implicit'  : 'bkids',  } +  def field(name, entry, verbose=Verbose):      if not Print_Flags[name]:          return None @@ -299,6 +364,7 @@ def field(name, entry, verbose=Verbose):          val = name + ": " + val      return val +  def nodeinfo_raw(name, ninfo, prefix=""):      # This just formats the dictionary, which we would normally use str()      # to do, except that we want the keys sorted for deterministic output. @@ -314,6 +380,7 @@ def nodeinfo_raw(name, ninfo, prefix=""):          name = repr(name)      return name + ': {' + ', '.join(l) + '}' +  def nodeinfo_cooked(name, ninfo, prefix=""):      try:          field_list = ninfo.field_list @@ -321,15 +388,19 @@ def nodeinfo_cooked(name, ninfo, prefix=""):          field_list = []      if '\n' in name:          name = repr(name) -    outlist = [name+':'] + [_f for _f in [field(x, ninfo, Verbose) for x in field_list] if _f] +    outlist = [name + ':'] + [ +        f for f in [field(x, ninfo, Verbose) for x in field_list] if f +    ]      if Verbose:          sep = '\n    ' + prefix      else:          sep = ' '      return sep.join(outlist) +  nodeinfo_string = nodeinfo_cooked +  def printfield(name, entry, prefix=""):      outlist = field("implicit", entry, 0)      if outlist: @@ -343,13 +414,15 @@ def printfield(name, entry, prefix=""):          else:              print("        " + outact) +  def printentries(entries, location):      if Print_Entries:          for name in Print_Entries:              try:                  entry = entries[name]              except KeyError: -                sys.stderr.write("sconsign: no entry `%s' in `%s'\n" % (name, location)) +                err = "sconsign: no entry `%s' in `%s'\n" % (name, location) +                sys.stderr.write(err)              else:                  try:                      ninfo = entry.ninfo @@ -369,6 +442,7 @@ def printentries(entries, location):                  print(nodeinfo_string(name, entry.ninfo))              printfield(name, entry.binfo) +  class Do_SConsignDB(object):      def __init__(self, dbm_name, dbm):          self.dbm_name = dbm_name @@ -376,8 +450,8 @@ class Do_SConsignDB(object):      def __call__(self, fname):          # The *dbm modules stick their own file suffixes on the names -        # that are passed in.  This is causes us to jump through some -        # hoops here to be able to allow the user +        # that are passed in.  This causes us to jump through some +        # hoops here.          try:              # Try opening the specified file name.  Example:              #   SPECIFIED                  OPENED BY self.dbm.open() @@ -389,29 +463,35 @@ class Do_SConsignDB(object):              print_e = e              try:                  # That didn't work, so try opening the base name, -                # so that if the actually passed in 'sconsign.dblite' +                # so that if they actually passed in 'sconsign.dblite'                  # (for example), the dbm module will put the suffix back                  # on for us and open it anyway.                  db = self.dbm.open(os.path.splitext(fname)[0], "r")              except (IOError, OSError):                  # That didn't work either.  See if the file name -                # they specified just exists (independent of the dbm +                # they specified even exists (independent of the dbm                  # suffix-mangling).                  try: -                    open(fname, "r") +                    with open(fname, "rb"): +                        pass  # this is a touch only, we don't use it here.                  except (IOError, OSError) as e:                      # Nope, that file doesn't even exist, so report that                      # fact back.                      print_e = e -                sys.stderr.write("sconsign: %s\n" % (print_e)) +                sys.stderr.write("sconsign: %s\n" % print_e)                  return          except KeyboardInterrupt:              raise          except pickle.UnpicklingError: -            sys.stderr.write("sconsign: ignoring invalid `%s' file `%s'\n" % (self.dbm_name, fname)) +            sys.stderr.write("sconsign: ignoring invalid `%s' file `%s'\n" +                             % (self.dbm_name, fname))              return          except Exception as e: -            sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n" % (self.dbm_name, fname, e)) +            sys.stderr.write("sconsign: ignoring invalid `%s' file `%s': %s\n" +                             % (self.dbm_name, fname, e)) +            exc_type, _, _ = sys.exc_info() +            if exc_type.__name__ == "ValueError" and sys.version_info < (3,0,0): +                sys.stderr.write("Python 2 only supports pickle protocols 0-2.\n")              return          if Print_Directories: @@ -419,41 +499,50 @@ class Do_SConsignDB(object):                  try:                      val = db[dir]                  except KeyError: -                    sys.stderr.write("sconsign: no dir `%s' in `%s'\n" % (dir, args[0])) +                    err = "sconsign: no dir `%s' in `%s'\n" % (dir, args[0]) +                    sys.stderr.write(err)                  else:                      self.printentries(dir, val)          else:              for dir in sorted(db.keys()):                  self.printentries(dir, db[dir]) -    def printentries(self, dir, val): -        print('=== ' + dir + ':') +    @staticmethod +    def printentries(dir, val): +        try: +            print('=== ' + dir + ':') +        except TypeError: +            print('=== ' + dir.decode() + ':')          printentries(pickle.loads(val), dir) +  def Do_SConsignDir(name):      try: -        fp = open(name, 'rb') +        with open(name, 'rb') as fp: +            try: +                sconsign = SCons.SConsign.Dir(fp) +            except KeyboardInterrupt: +                raise +            except pickle.UnpicklingError: +                err = "sconsign: ignoring invalid .sconsign file `%s'\n" % (name) +                sys.stderr.write(err) +                return +            except Exception as e: +                err = "sconsign: ignoring invalid .sconsign file `%s': %s\n" % (name, e) +                sys.stderr.write(err) +                return +            printentries(sconsign.entries, args[0])      except (IOError, OSError) as e: -        sys.stderr.write("sconsign: %s\n" % (e)) -        return -    try: -        sconsign = SCons.SConsign.Dir(fp) -    except KeyboardInterrupt: -        raise -    except pickle.UnpicklingError: -        sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s'\n" % (name)) -        return -    except Exception as e: -        sys.stderr.write("sconsign: ignoring invalid .sconsign file `%s': %s\n" % (name, e)) +        sys.stderr.write("sconsign: %s\n" % e)          return -    printentries(sconsign.entries, args[0]) +  ##############################################################################  import getopt  helpstr = """\ -Usage: sconsign [OPTIONS] FILE [...] +Usage: sconsign [OPTIONS] [FILE ...]  Options:    -a, --act, --action         Print build action information.    -c, --csig                  Print content signature information. @@ -469,13 +558,17 @@ Options:    -v, --verbose               Verbose, describe each field.  """ -opts, args = getopt.getopt(sys.argv[1:], "acd:e:f:hirstv", -                            ['act', 'action', -                             'csig', 'dir=', 'entry=', -                             'format=', 'help', 'implicit', -                             'raw', 'readable', -                             'size', 'timestamp', 'verbose']) - +try: +    opts, args = getopt.getopt(sys.argv[1:], "acd:e:f:hirstv", +                               ['act', 'action', +                                'csig', 'dir=', 'entry=', +                                'format=', 'help', 'implicit', +                                'raw', 'readable', +                                'size', 'timestamp', 'verbose']) +except getopt.GetoptError as err: +    sys.stderr.write(str(err) + '\n') +    print(helpstr) +    sys.exit(2)  for o, a in opts:      if o in ('-a', '--act', '--action'): @@ -489,8 +582,7 @@ for o, a in opts:      elif o in ('-f', '--format'):          # Try to map the given DB format to a known module          # name, that we can then try to import... -        Module_Map = {'dblite'   : 'SCons.dblite', -                      'sconsign' : None} +        Module_Map = {'dblite': 'SCons.dblite', 'sconsign': None}          dbm_name = Module_Map.get(a, a)          if dbm_name:              try: @@ -498,12 +590,13 @@ for o, a in opts:                      dbm = my_import(dbm_name)                  else:                      import SCons.dblite +                      dbm = SCons.dblite                      # Ensure that we don't ignore corrupt DB files,                      # this was handled by calling my_import('SCons.dblite')                      # again in earlier versions...                      SCons.dblite.ignore_corrupt_dbfiles = 0 -            except: +            except ImportError:                  sys.stderr.write("sconsign: illegal file format `%s'\n" % a)                  print(helpstr)                  sys.exit(2) @@ -526,19 +619,21 @@ for o, a in opts:      elif o in ('-v', '--verbose'):          Verbose = 1 -  if Do_Call:      for a in args:          Do_Call(a)  else: +    if not args: +        args = [".sconsign.dblite"]      for a in args:          dbm_name = whichdb(a)          if dbm_name: -            Map_Module = {'SCons.dblite' : 'dblite'} +            Map_Module = {'SCons.dblite': 'dblite'}              if dbm_name != "SCons.dblite":                  dbm = my_import(dbm_name)              else:                  import SCons.dblite +                  dbm = SCons.dblite                  # Ensure that we don't ignore corrupt DB files,                  # this was handled by calling my_import('SCons.dblite') @@ -548,6 +643,8 @@ else:          else:              Do_SConsignDir(a) +    if Warns: +        print("NOTE: there were %d warnings, please check output" % Warns)  sys.exit(0)  # Local Variables:  | 
