diff options
Diffstat (limited to 'script')
-rwxr-xr-x[-rw-r--r--] | script/scons | 113 | ||||
-rw-r--r-- | script/scons-configure-cache | 143 | ||||
-rw-r--r-- | script/scons-time | 105 | ||||
-rw-r--r-- | script/scons.bat | 12 | ||||
-rw-r--r-- | script/sconsign | 299 |
5 files changed, 407 insertions, 265 deletions
diff --git a/script/scons b/script/scons index fe9d724..1d9595e 100644..100755 --- a/script/scons +++ b/script/scons @@ -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,22 +25,30 @@ from __future__ import print_function -__revision__ = "src/script/scons.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog" +__revision__ = "src/script/scons.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" + +# This is the entry point to the SCons program. +# The only job of this script is to work out where the guts of the program +# could be and import them, where the real work begins. +# SCons can be invoked several different ways +# - from an installed location +# - from a "local install" copy +# - from a source tree, which has a different dir struture than the other two +# Try to account for all those possibilities. import os import sys - ############################################################################## # BEGIN STANDARD SCons SCRIPT HEADER # @@ -50,57 +58,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 < 3.5 is not yet supported.\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 = [] - -# - running from egg check +# 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: @@ -109,18 +113,18 @@ 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 == '': script_dir = os.getcwd() @@ -128,42 +132,41 @@ else: 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: @@ -177,9 +180,9 @@ else: 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 @@ -191,9 +194,9 @@ if __name__ == "__main__": try: import SCons.Script except ImportError: - print("SCons import failed. Unable to find engine files in:") + sys.stderr.write("SCons import failed. Unable to find engine files in:\n") for path in libs: - print(" {}".format(path)) + sys.stderr.write(" {}\n".format(path)) raise # this does all the work, and calls sys.exit diff --git a/script/scons-configure-cache b/script/scons-configure-cache index cbb058d..8bce553 100644 --- a/script/scons-configure-cache +++ b/script/scons-configure-cache @@ -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 @@ -23,102 +23,139 @@ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +'''Show or convert the configuration of an SCons cache directory. + +A cache of derived files is stored by file signature. +The files are split into directories named by the first few +digits of the signature. The prefix length used for directory +names can be changed by this script. +''' + from __future__ import print_function +import argparse +import glob +import json +import os -__revision__ = "src/script/scons-configure-cache.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog" +__revision__ = "src/script/scons-configure-cache.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 argparse -import glob -import json -import os def rearrange_cache_entries(current_prefix_len, new_prefix_len): - print('Changing prefix length from', current_prefix_len, 'to', new_prefix_len) + '''Move cache files if prefix length changed. + + Move the existing cache files to new directories of the + appropriate name length and clean up the old directories. + ''' + print('Changing prefix length from', current_prefix_len, + 'to', new_prefix_len) dirs = set() old_dirs = set() for file in glob.iglob(os.path.join('*', '*')): name = os.path.basename(file) - dir = name[:current_prefix_len].upper() - if dir not in old_dirs: - print('Migrating', dir) - old_dirs.add(dir) - dir = name[:new_prefix_len].upper() - if dir not in dirs: - os.mkdir(dir) - dirs.add(dir) - os.rename(file, os.path.join(dir, name)) + dname = name[:current_prefix_len].upper() + if dname not in old_dirs: + print('Migrating', dname) + old_dirs.add(dname) + dname = name[:new_prefix_len].upper() + if dname not in dirs: + os.mkdir(dname) + dirs.add(dname) + os.rename(file, os.path.join(dname, name)) # Now delete the original directories - for dir in old_dirs: - os.rmdir(dir) + for dname in old_dirs: + os.rmdir(dname) + -# This dictionary should have one entry per entry in the cache config -# Each entry should have the following: +# The configuration dictionary should have one entry per entry in the +# cache config. The value of each entry should include the following: # implicit - (optional) This is to allow adding a new config entry and also # changing the behaviour of the system at the same time. This -# indicates the value the config entry would have had if it had been -# specified. +# indicates the value the config entry would have had if it had +# been specified. # default - The value the config entry should have if it wasn't previously # specified # command-line - parameters to pass to ArgumentParser.add_argument -# converter - (optional) Function to call if it's necessary to do some work +# converter - (optional) Function to call if conversion is required # if this configuration entry changes config_entries = { - 'prefix_len' : { - 'implicit' : 1, - 'default' : 2 , - 'command-line' : { - 'help' : 'Length of cache file name used as subdirectory prefix', - 'metavar' : '<number>', - 'type' : int - }, - 'converter' : rearrange_cache_entries + 'prefix_len': { + 'implicit': 1, + 'default': 2, + 'command-line': { + 'help': 'Length of cache file name used as subdirectory prefix', + 'metavar': '<number>', + 'type': int + }, + 'converter': rearrange_cache_entries } } + parser = argparse.ArgumentParser( - description = 'Modify the configuration of an scons cache directory', - epilog = ''' - Unless you specify an option, it will not be changed (if it is - already set in the cache config), or changed to an appropriate - default (it it is not set). - ''' - ) + description='Modify the configuration of an scons cache directory', + epilog=''' + Unspecified options will not be changed unless they are not + set at all, in which case they are set to an appropriate default. + ''') parser.add_argument('cache-dir', help='Path to scons cache directory') for param in config_entries: - parser.add_argument('--' + param.replace('_', '-'), + parser.add_argument('--' + param.replace('_', '-'), **config_entries[param]['command-line']) -parser.add_argument('--version', action='version', version='%(prog)s 1.0') +parser.add_argument('--version', + action='version', + version='%(prog)s 1.0') +parser.add_argument('--show', + action="store_true", + help="show current configuration") # Get the command line as a dict without any of the unspecified entries. args = dict([x for x in vars(parser.parse_args()).items() if x[1]]) # It seems somewhat strange to me, but positional arguments don't get the - # in the name changed to _, whereas optional arguments do... -os.chdir(args['cache-dir']) +cache = args['cache-dir'] +if not os.path.isdir(cache): + raise RuntimeError("There is no cache directory named %s" % cache) +os.chdir(cache) del args['cache-dir'] if not os.path.exists('config'): + # old config dirs did not have a 'config' file. Try to update. # Validate the only files in the directory are directories 0-9, a-f - expected = [ '{:X}'.format(x) for x in range(0, 16) ] + expected = ['{:X}'.format(x) for x in range(0, 16)] if not set(os.listdir('.')).issubset(expected): - raise RuntimeError("This doesn't look like a version 1 cache directory") + raise RuntimeError( + "%s does not look like a valid version 1 cache directory" % cache) config = dict() else: with open('config') as conf: config = json.load(conf) -# Find any keys that aren't currently set but should be +if args.get('show', None): + print("Current configuration in '%s':" % cache) + print(json.dumps(config, sort_keys=True, + indent=4, separators=(',', ': '))) + # in case of the show argument, emit some stats as well + file_count = 0 + for _, _, files in os.walk('.'): + file_count += len(files) + if file_count: # skip config file if it exists + file_count -= 1 + print("Cache contains %s files" % file_count) + del args['show'] + +# Find any keys that are not currently set but should be for key in config_entries: if key not in config: if 'implicit' in config_entries[key]: @@ -128,10 +165,10 @@ for key in config_entries: if key not in args: args[key] = config_entries[key]['default'] -#Now we go through each entry in args to see if it changes an existing config -#setting. +# Now go through each entry in args to see if it changes an existing config +# setting. for key in args: - if args[key] != config[key]: + if args[key] != config[key]: if 'converter' in config_entries[key]: config_entries[key]['converter'](config[key], args[key]) config[key] = args[key] diff --git a/script/scons-time b/script/scons-time index 3fdb8f2..15e3700 100644 --- a/script/scons-time +++ b/script/scons-time @@ -9,7 +9,7 @@ # # -# 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 @@ -31,7 +31,7 @@ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. from __future__ import division, print_function -__revision__ = "src/script/scons-time.py 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog" +__revision__ = "src/script/scons-time.py 72ae09dc35ac2626f8ff711d8c4b30b6138e08e3 2019-08-08 14:50:06 bdeegan" import getopt import glob @@ -41,29 +41,15 @@ import shutil import sys import tempfile import time - -def make_temp_file(**kw): - try: - result = tempfile.mktemp(**kw) - result = os.path.realpath(result) - except TypeError: - try: - save_template = tempfile.template - prefix = kw['prefix'] - del kw['prefix'] - tempfile.template = prefix - result = tempfile.mktemp(**kw) - finally: - tempfile.template = save_template - return result +import subprocess def HACK_for_exec(cmd, *args): - ''' + """ For some reason, Python won't allow an exec() within a function that also declares an internal function (including lambda functions). This function is a hack that calls exec() in a function with no internal functions. - ''' + """ if not args: exec(cmd) elif len(args) == 1: exec(cmd, args[0]) else: exec(cmd, args[0], args[1]) @@ -121,7 +107,7 @@ class Line(object): # in the line's index number. We might want to represent # this some way rather than just drawing the line straight # between the two points on either side. - if not y is None: + if y is not None: print(fmt % (x, y)) print('e') @@ -147,7 +133,7 @@ class Gnuplotter(Plotter): return line.plot_string() def vertical_bar(self, x, type, label, comment): - if self.get_min_x() <= x and x <= self.get_max_x(): + if self.get_min_x() <= x <= self.get_max_x(): points = [(x, 0), (x, self.max_graph_value(self.get_max_y()))] self.line(points, type, label, comment) @@ -155,13 +141,13 @@ class Gnuplotter(Plotter): result = [] for line in self.lines: result.extend(line.get_x_values()) - return [r for r in result if not r is None] + return [r for r in result if r is not None] def get_all_y_values(self): result = [] for line in self.lines: result.extend(line.get_y_values()) - return [r for r in result if not r is None] + return [r for r in result if r is not None] def get_min_x(self): try: @@ -248,14 +234,16 @@ def unzip(fname): os.makedirs(dir) except: pass - open(name, 'wb').write(zf.read(name)) + with open(name, 'wb') as f: + f.write(zf.read(name)) def read_tree(dir): for dirpath, dirnames, filenames in os.walk(dir): for fn in filenames: fn = os.path.join(dirpath, fn) if os.path.isfile(fn): - open(fn, 'rb').read() + with open(fn, 'rb') as f: + f.read() def redirect_to_file(command, log): return '%s > %s 2>&1' % (command, log) @@ -264,7 +252,7 @@ def tee_to_file(command, log): return '%s 2>&1 | tee %s' % (command, log) - + class SConsTimer(object): """ Usage: scons-time SUBCOMMAND [ARGUMENTS] @@ -360,7 +348,7 @@ class SConsTimer(object): 'SCons' : 'Total SCons execution time', 'commands' : 'Total command execution time', } - + time_string_all = 'Total .* time' # @@ -456,14 +444,20 @@ class SConsTimer(object): def log_execute(self, command, log): command = self.subst(command, self.__dict__) - output = os.popen(command).read() + p = os.popen(command) + output = p.read() + p.close() + #TODO: convert to subrocess, os.popen is obsolete. This didn't work: + #process = subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) + #output = process.stdout.read() + #process.stdout.close() + #process.wait() if self.verbose: sys.stdout.write(output) # TODO: Figure out # Not sure we need to write binary here - open(log, 'w').write(output) - - # + with open(log, 'w') as f: + f.write(str(output)) def archive_splitext(self, path): """ @@ -628,13 +622,14 @@ class SConsTimer(object): search_string = self.time_string_all else: search_string = time_string - contents = open(file).read() + with open(file) as f: + contents = f.read() if not contents: sys.stderr.write('file %s has no contents!\n' % repr(file)) return None result = re.findall(r'%s: ([\d\.]*)' % search_string, contents)[-4:] result = [ float(r) for r in result ] - if not time_string is None: + if time_string is not None: try: result = result[0] except IndexError: @@ -673,7 +668,8 @@ class SConsTimer(object): search_string = self.memory_string_all else: search_string = memory_string - lines = open(file).readlines() + with open(file) as f: + lines = f.readlines() lines = [ l for l in lines if l.startswith(search_string) ][-4:] result = [ int(l.split()[-1]) for l in lines[-4:] ] if len(result) == 1: @@ -685,14 +681,14 @@ class SConsTimer(object): Returns the counts of the specified object_name. """ object_string = ' ' + object_name + '\n' - lines = open(file).readlines() + with open(file) as f: + lines = f.readlines() line = [ l for l in lines if l.endswith(object_string) ][0] result = [ int(field) for field in line.split()[:4] ] if index is not None: result = result[index] return result - # command_alias = {} @@ -814,7 +810,9 @@ class SConsTimer(object): self.title = a if self.config_file: - exec(open(self.config_file, 'r').read(), self.__dict__) + with open(self.config_file, 'r') as f: + config = f.read() + exec(config, self.__dict__) if self.chdir: os.chdir(self.chdir) @@ -923,7 +921,7 @@ class SConsTimer(object): elif o in ('-p', '--prefix'): self.prefix = a elif o in ('--stage',): - if not a in self.stages: + if a not in self.stages: sys.stderr.write('%s: mem: Unrecognized stage "%s".\n' % (self.name, a)) sys.exit(1) stage = a @@ -933,7 +931,9 @@ class SConsTimer(object): self.title = a if self.config_file: - HACK_for_exec(open(self.config_file, 'r').read(), self.__dict__) + with open(self.config_file, 'r') as f: + config = f.read() + HACK_for_exec(config, self.__dict__) if self.chdir: os.chdir(self.chdir) @@ -1035,7 +1035,7 @@ class SConsTimer(object): elif o in ('-p', '--prefix'): self.prefix = a elif o in ('--stage',): - if not a in self.stages: + if a not in self.stages: sys.stderr.write('%s: obj: Unrecognized stage "%s".\n' % (self.name, a)) sys.stderr.write('%s Type "%s help obj" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) @@ -1053,7 +1053,9 @@ class SConsTimer(object): object_name = args.pop(0) if self.config_file: - HACK_for_exec(open(self.config_file, 'r').read(), self.__dict__) + with open(self.config_file, 'r') as f: + config = f.read() + HACK_for_exec(config, self.__dict__) if self.chdir: os.chdir(self.chdir) @@ -1191,7 +1193,9 @@ class SConsTimer(object): sys.exit(1) if self.config_file: - exec(open(self.config_file, 'r').read(), self.__dict__) + with open(self.config_file, 'r') as f: + config = f.read() + exec(config, self.__dict__) if args: self.archive_list = args @@ -1231,7 +1235,7 @@ class SConsTimer(object): return os.path.join(dir, 'src', 'engine') def prep_aegis_run(self, commands, removals): - self.aegis_tmpdir = make_temp_file(prefix = self.name + '-aegis-') + self.aegis_tmpdir = tempfile.mkdtemp(prefix=self.name + '-aegis-') removals.append((shutil.rmtree, 'rm -rf %%s', self.aegis_tmpdir)) self.aegis_parent_project = os.path.splitext(self.aegis_project)[0] @@ -1239,21 +1243,19 @@ class SConsTimer(object): self.scons_lib_dir = self.scons_lib_dir_path(self.aegis_tmpdir) commands.extend([ - 'mkdir %(aegis_tmpdir)s', (lambda: os.chdir(self.aegis_tmpdir), 'cd %(aegis_tmpdir)s'), '%(aegis)s -cp -ind -p %(aegis_parent_project)s .', '%(aegis)s -cp -ind -p %(aegis_project)s -delta %(run_number)s .', ]) def prep_subversion_run(self, commands, removals): - self.svn_tmpdir = make_temp_file(prefix = self.name + '-svn-') + self.svn_tmpdir = tempfile.mkdtemp(prefix=self.name + '-svn-') removals.append((shutil.rmtree, 'rm -rf %%s', self.svn_tmpdir)) self.scons = self.scons_path(self.svn_tmpdir) self.scons_lib_dir = self.scons_lib_dir_path(self.svn_tmpdir) commands.extend([ - 'mkdir %(svn_tmpdir)s', '%(svn)s co %(svn_co_flag)s -r %(run_number)s %(subversion_url)s %(svn_tmpdir)s', ]) @@ -1300,11 +1302,9 @@ class SConsTimer(object): if self.targets2 is None: self.targets2 = self.targets - self.tmpdir = make_temp_file(prefix = self.name + '-') + self.tmpdir = tempfile.mkdtemp(prefix=self.name + '-') commands.extend([ - 'mkdir %(tmpdir)s', - (os.chdir, 'cd %%s', self.tmpdir), ]) @@ -1357,7 +1357,6 @@ class SConsTimer(object): if not os.environ.get('PRESERVE'): commands.extend(removals) - commands.append((shutil.rmtree, 'rm -rf %%s', self.tmpdir)) self.run_command_list(commands, self.__dict__) @@ -1424,14 +1423,16 @@ class SConsTimer(object): elif o in ('--title',): self.title = a elif o in ('--which',): - if not a in list(self.time_strings.keys()): + if a not in list(self.time_strings.keys()): sys.stderr.write('%s: time: Unrecognized timer "%s".\n' % (self.name, a)) sys.stderr.write('%s Type "%s help time" for help.\n' % (self.name_spaces, self.name)) sys.exit(1) which = a if self.config_file: - HACK_for_exec(open(self.config_file, 'r').read(), self.__dict__) + with open(self.config_file, 'r') as f: + config = f.read() + HACK_for_exec(config, self.__dict__) if self.chdir: os.chdir(self.chdir) diff --git a/script/scons.bat b/script/scons.bat index 4d0e6e6..a5b1b6e 100644 --- a/script/scons.bat +++ b/script/scons.bat @@ -1,11 +1,11 @@ -@REM Copyright (c) 2001 - 2017 The SCons Foundation
-@REM src/script/scons.bat 74b2c53bc42290e911b334a6b44f187da698a668 2017/11/14 13:16:53 bdbaddog
+@REM Copyright (c) 2001 - 2019 The SCons Foundation
+@REM src/script/scons.bat 72ae09dc35ac2626f8ff711d8c4b30b6138e08e3 2019-08-08 14:50:06 bdeegan
@echo off
set SCONS_ERRORLEVEL=
if "%OS%" == "Windows_NT" goto WinNT
@REM for 9x/Me you better not have more than 9 args
-python -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-3.0.1'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons-3.0.1'), join(sys.prefix, 'scons')] + sys.path; import SCons.Script; SCons.Script.main()" %1 %2 %3 %4 %5 %6 %7 %8 %9
+python -c "from os.path import join; import sys; sys.path = [ join(sys.prefix, 'Lib', 'site-packages', 'scons-3.1.1'), join(sys.prefix, 'Lib', 'site-packages', 'scons'), join(sys.prefix, 'scons-3.1.1'), join(sys.prefix, 'scons')] + sys.path; import SCons.Script; SCons.Script.main()" %1 %2 %3 %4 %5 %6 %7 %8 %9
@REM no way to set exit status of this script for 9x/Me
goto endscons
@@ -16,10 +16,14 @@ goto endscons :WinNT
setlocal
@REM ensure the script will be executed with the Python it was installed for
-set path=%~dp0;%~dp0..;%path%
+pushd %~dp0..
+set path=%~dp0;%CD%;%path%
+popd
@REM try the script named as the .bat file in current dir, then in Scripts subdir
set scriptname=%~dp0%~n0.py
if not exist "%scriptname%" set scriptname=%~dp0Scripts\%~n0.py
+@REM Handle when running from wheel where the script has no .py extension
+if not exist "%scriptname%" set scriptname=%~dp0%~n0
python "%scriptname%" %*
endlocal & set SCONS_ERRORLEVEL=%ERRORLEVEL%
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: |