From b61917920644e58ab48cad87dabc19f9db6f0a64 Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Wed, 18 Jun 2003 05:44:54 +0000 Subject: Options fixes. (Charles Crain) --- src/CHANGES.txt | 54 ++++++++++++++++++++++++++++++- src/engine/SCons/Options.py | 47 ++++++++++++--------------- src/engine/SCons/OptionsTests.py | 69 ++++++++++++++++++++++++++++++++++++---- test/Options.py | 10 +++--- 4 files changed, 141 insertions(+), 39 deletions(-) diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 1222d44..c37f3ab 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -10,35 +10,87 @@ RELEASE 0.15 - XXX + From Chad Austin: + + - Fix the _concat() documentation, and add a test for it. + + - Portability fixes for non-GNU versions of lex and yacc. + From Matt Balvin: - Fix handling of library prefixes when the subdirectory matches the prefix. + From Timothee Bessett: + + - Add an M4 Builder. + From Charles Crain: - Use '.lnk' as the suffix on the temporary file for linking long command lines (necessary for the Phar Lap linkloc linker). + - Save non-string Options values as their actual type. + + - Save Options string values that contain a single quote correctly. + + - Save any Options values that are changed from the default + Environment values, not just ones changed on the command line or in + an Options file. + + - Make closing the Options file descriptor exception-safe. + From Steven Knight: - SCons now enforces (with an error) that construction variables must have the same form as valid Python identifiers. - Fix man page bugs: remove duplicate AddPostAction() description; - document no_import_lib. + document no_import_lib; mention that CPPFLAGS does not contain + $_CPPINCFLAGS; mention that F77FLAGS does not contain $_F77INCFLAGS; + mention that LINKFLAGS and SHLINKFLAGS contains neither $_LIBFLAGS + nor $_LIBDIRFLAGS. - Eliminate a dependency on the distutils.fancy_getopt module by copying and pasting its wrap_text() function directly. + - Make the Script.Options() subclass match the underlying base class + implementation. + From Steve Leblanc: - Don't update the .sconsign files when run with -n. + From Gary Oberbrunner: + + - Add support for the Intel C Compiler (icl.exe). + + From Anthony Roach + + - Fix Import('*'). + + From David Snopek + + - Fix use of SConf in paths with white space in them. + + - Add CheckFunc and CheckType functionality to SConf. + + - Fix use of SConf with Builders that return a list of nodes. + From David Snopek and Christoph Wiedemann - Fix use of the SConf subsystem with SConscriptChdir(). + From Greg Spencer + + - Check for the existence of MS Visual Studio on disk before using it, + to avoid getting fooled by leftover junk in the registry. + + - Add support for MSVC++ .NET. + + - Add support for MS Visual Studio project files (DSP, DSW, + SLN and VCPROJ files). + RELEASE 0.14 - Wed, 21 May 2003 05:16:32 -0500 diff --git a/src/engine/SCons/Options.py b/src/engine/SCons/Options.py index 953f1a4..cbe642a 100644 --- a/src/engine/SCons/Options.py +++ b/src/engine/SCons/Options.py @@ -80,7 +80,6 @@ class Options: option.default = default option.validater = validater option.converter = converter - option.should_save = 0 self.options.append(option) @@ -108,18 +107,6 @@ class Options: if args is None: args = self.args values.update(args) - - # Update should save state. - # This will mark options that have either been set on - # the command line or in a loaded option file. - # KeyError occurs when an option has default of None - # and has not been set. - for option in self.options: - try: - if values[option.key] != option.default: - option.should_save = 1 - except KeyError: - pass # put the variables in the environment: # (don't copy over variables that are not declared @@ -132,7 +119,7 @@ class Options: # Call the convert functions: for option in self.options: - if option.converter: + if option.converter and values.has_key(option.key): value = env.subst('${%s}'%option.key) try: env[option.key] = option.converter(value) @@ -144,8 +131,6 @@ class Options: for option in self.options: if option.validater: option.validater(option.key, env.subst('${%s}'%option.key), env) - - def Save(self, filename, env): """ @@ -161,17 +146,25 @@ class Options: try: fh = open(filename, 'w') - # Make an assignment in the file for each option within the environment - # that was assigned a value other than the default. - for option in self.options: - try: - value = env[option.key] - if option.should_save: - fh.write('%s = \'%s\'\n' % (option.key, value)) - except KeyError: - pass - - fh.close() + try: + # Make an assignment in the file for each option within the environment + # that was assigned a value other than the default. + for option in self.options: + try: + value = env[option.key] + try: + eval(repr(value)) + except: + # Convert stuff that has a repr() that + # cannot be evaluated into a string + value = SCons.Util.to_String(value) + if env.subst('${%s}' % option.key) != \ + env.subst(SCons.Util.to_String(option.default)): + fh.write('%s = %s\n' % (option.key, repr(value))) + except KeyError: + pass + finally: + fh.close() except IOError, x: raise SCons.Errors.UserError, 'Error writing options to file: %s\n%s' % (filename, x) diff --git a/src/engine/SCons/OptionsTests.py b/src/engine/SCons/OptionsTests.py index ce8bee7..90ff153 100644 --- a/src/engine/SCons/OptionsTests.py +++ b/src/engine/SCons/OptionsTests.py @@ -26,6 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import unittest import TestSCons import SCons.Options +import SCons.Util import sys import string @@ -34,17 +35,19 @@ class Environment: def __init__(self): self.dict = {} def subst(self, x): - return self.dict[x[2:-1]] + return SCons.Util.scons_subst(x, self) def __setitem__(self, key, value): self.dict[key] = value def __getitem__(self, key): return self.dict[key] def has_key(self, key): return self.dict.has_key(key) + def Dictionary(self): + return self.dict def check(key, value, env): - assert value == 6 * 9, "key %s = %s" % (key, value) + assert int(value) == 6 * 9, "key %s = %s" % (key, repr(value)) # Check saved option file by executing and comparing against # the expected dictionary @@ -52,7 +55,7 @@ def checkSave(file, expected): gdict = {} ldict = {} execfile(file, gdict, ldict) - assert expected == ldict + assert expected == ldict, "%s\n...not equal to...\n%s" % (expected, ldict) class OptionsTestCase(unittest.TestCase): def test_Add(self): @@ -72,7 +75,6 @@ class OptionsTestCase(unittest.TestCase): assert o.default == None assert o.validater == None assert o.converter == None - assert o.should_save == 0 o = opts.options[1] assert o.key == 'ANSWER' @@ -200,6 +202,22 @@ class OptionsTestCase(unittest.TestCase): opts.Update(env, {'ANSWER':'42'}) assert env['ANSWER'] == 54 + # Test against a former bug. If we supply a converter, + # but no default, the value should *not* appear in the + # Environment if no value is specified in the options file + # or args. + test = TestSCons.TestSCons() + file = test.workpath('custom.py') + opts = SCons.Options.Options(file) + + opts.Add('ANSWER', + help='THE answer to THE question', + converter=str) + + env = Environment() + opts.Update(env, {}) + assert not env.has_key('ANSWER') + def test_args(self): """Test updating an Environment with arguments overridden""" @@ -270,13 +288,52 @@ class OptionsTestCase(unittest.TestCase): 21, None, None) + opts.Add('OPT_VAL_2', + default='foo') + opts.Add('OPT_VAL_3', + default=1) env = Environment() - opts.Update(env, {}) + opts.Update(env, {'OPT_VAL_3' : 2}) assert env['OPT_VAL'] == 21 + assert env['OPT_VAL_2'] == 'foo' + assert env['OPT_VAL_3'] == 2 + env['OPT_VAL_2'] = 'bar' opts.Save(cache_file, env) - checkSave(cache_file, {}) + checkSave(cache_file, { 'OPT_VAL_2' : 'bar', + 'OPT_VAL_3' : 2 }) + + # Test against some old bugs + class Foo: + def __init__(self, x): + self.x = x + def __str__(self): + return self.x + + test = TestSCons.TestSCons() + cache_file = test.workpath('cached.options') + opts = SCons.Options.Options() + + opts.Add('THIS_USED_TO_BREAK', + 'An option to test', + "Default") + opts.Add('THIS_ALSO_BROKE', + 'An option to test', + "Default2") + + opts.Add('THIS_SHOULD_WORK', + 'An option to test', + Foo('bar')) + + env = Environment() + opts.Update(env, { 'THIS_USED_TO_BREAK' : "Single'Quotes'In'String", + 'THIS_ALSO_BROKE' : "\\Escape\nSequences\t", + 'THIS_SHOULD_WORK' : Foo('baz') }) + opts.Save(cache_file, env) + checkSave(cache_file, { 'THIS_USED_TO_BREAK' : "Single'Quotes'In'String", + 'THIS_ALSO_BROKE' : "\\Escape\nSequences\t", + 'THIS_SHOULD_WORK' : 'baz' }) def test_GenerateHelpText(self): opts = SCons.Options.Options() diff --git a/test/Options.py b/test/Options.py index b142db9..0e21aa9 100644 --- a/test/Options.py +++ b/test/Options.py @@ -198,23 +198,23 @@ def checkSave(file, expected): gdict = {} ldict = {} execfile(file, gdict, ldict) - assert expected == ldict + assert expected == ldict, "%s\n...not equal to...\n%s" % (expected, ldict) # First test with no command line options # This should just leave the custom.py settings test.run() check(['1','0']) -checkSave('options.saved', { 'RELEASE_BUILD':'1', 'DEBUG_BUILD':'0'}) +checkSave('options.saved', { 'RELEASE_BUILD':1, 'DEBUG_BUILD':0}) # Override with command line arguments test.run(arguments='"DEBUG_BUILD=3"') check(['1','3']) -checkSave('options.saved', {'RELEASE_BUILD':'1', 'DEBUG_BUILD':'3'}) +checkSave('options.saved', {'RELEASE_BUILD':1, 'DEBUG_BUILD':3}) # Now make sure that saved options are overridding the custom.py test.run() check(['1','3']) -checkSave('options.saved', {'DEBUG_BUILD':'3', 'RELEASE_BUILD':'1'}) +checkSave('options.saved', {'DEBUG_BUILD':3, 'RELEASE_BUILD':1}) # Load no options from file(s) # Used to test for correct output in save option file @@ -256,7 +256,7 @@ checkSave('options.saved', {}) # Now specify same option non-default and make sure only it is written out test.run(arguments='"DEBUG_BUILD=0"') check(['0','0']) -checkSave('options.saved',{'DEBUG_BUILD':'0'}) +checkSave('options.saved',{'DEBUG_BUILD':0}) test.write('SConstruct', """ opts = Options('custom.py') -- cgit v0.12