Options fixes. (Charles Crain)
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 18 Jun 2003 05:44:54 +0000 (05:44 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 18 Jun 2003 05:44:54 +0000 (05:44 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@717 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Options.py
src/engine/SCons/OptionsTests.py
test/Options.py

index 1222d4415c03ddfac04af95c8f876d9fa8efc7f6..c37f3ab2600ee2b00edfec9aeda9e49bc7a5ae94 100644 (file)
 
 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
index 953f1a44e6af1402df0329e79f3e2d449f10b2bb..cbe642acffbcaa12fe2fc3603fd2ca616fe23a01 100644 (file)
@@ -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)
index ce8bee7696302eec7ce0aa3cd70930954b6e04ab..90ff153849ac1bed5359e1ad671f84aa6831c32d 100644 (file)
@@ -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()
index b142db9926124d78cd95b6db9d87a272538fa0eb..0e21aa93cff656b72a82117f361049a02d765e0a 100644 (file)
@@ -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')