diff options
-rw-r--r-- | doc/scons.mod | 5 | ||||
-rw-r--r-- | doc/user/command-line.in | 122 | ||||
-rw-r--r-- | doc/user/command-line.sgml | 96 | ||||
-rw-r--r-- | src/CHANGES.txt | 3 | ||||
-rw-r--r-- | src/engine/SCons/Options/PathOption.py | 47 | ||||
-rw-r--r-- | src/engine/SCons/Options/PathOptionTests.py | 22 | ||||
-rw-r--r-- | test/Options/PathOption.py | 33 |
7 files changed, 314 insertions, 14 deletions
diff --git a/doc/scons.mod b/doc/scons.mod index 58a6576..897262d 100644 --- a/doc/scons.mod +++ b/doc/scons.mod @@ -159,6 +159,11 @@ <!ENTITY Options "<function>Options</function>"> <!ENTITY PackageOption "<function>PackageOption</function>"> <!ENTITY PathOption "<function>PathOption</function>"> +<!ENTITY PathOption_PathAccept "<function>PathOption.PathAccept</function>"> +<!ENTITY PathOption_PathExists "<function>PathOption.PathExists</function>"> +<!ENTITY PathOption_PathIsDir "<function>PathOption.PathIsDir</function>"> +<!ENTITY PathOption_PathIsDirCreate "<function>PathOption.PathIsDirCreate</function>"> +<!ENTITY PathOption_PathIsFile "<function>PathOption.PathIsFile</function>"> <!ENTITY Precious "<function>Precious</function>"> <!ENTITY Prepend "<function>Prepend</function>"> <!ENTITY Replace "<function>Replace</function>"> diff --git a/doc/user/command-line.in b/doc/user/command-line.in index 9d69b21..f23755f 100644 --- a/doc/user/command-line.in +++ b/doc/user/command-line.in @@ -1324,6 +1324,128 @@ <command>scons -Q CONFIG=__ROOT__/usr/local/etc/other_config foo.o</command> </scons_output> + <para> + + By default, &PathOption; checks to make sure + that the specified path exists and generates an error if it + doesn't: + + </para> + + <scons_output example="PathOption"> + <command>scons -Q CONFIG=__ROOT__/does/not/exist foo.o</command> + </scons_output> + + <para> + + &PathOption; provides a number of methods + that you can use to change this behavior. + If you want to ensure that any specified paths are, + in fact, files and not directories, + use the &PathOption_PathIsFile; method: + + </para> + + <scons_example name="PathIsFile"> + <file name="SConstruct" printme="1"> + opts = Options('custom.py') + opts.Add(PathOption('CONFIG', + 'Path to configuration file', + '__ROOT__/etc/my_config', + PathOption.PathIsFile)) + env = Environment(options = opts, + CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="__ROOT__/etc/my_config"> + /opt/location + </file> + </scons_example> + + <para> + + Conversely, to ensure that any specified paths are + directories and not files, + use the &PathOption_PathIsDir; method: + + </para> + + <scons_example name="PathIsDir"> + <file name="SConstruct" printme="1"> + opts = Options('custom.py') + opts.Add(PathOption('DBDIR', + 'Path to database directory', + '__ROOT__/var/my_dbdir', + PathOption.PathIsDir)) + env = Environment(options = opts, + CPPDEFINES={'DBDIR' : '"$DBDIR"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="__ROOT__/var/my_dbdir"> + /opt/location + </file> + </scons_example> + + <para> + + If you want to make sure that any specified paths + are directories, + and you would like the directory created + if it doesn't already exist, + use the &PathOption_PathIsDirCreate; method: + + </para> + + <scons_example name="PathIsDirCreate"> + <file name="SConstruct" printme="1"> + opts = Options('custom.py') + opts.Add(PathOption('DBDIR', + 'Path to database directory', + '__ROOT__/var/my_dbdir', + PathOption.PathIsDirCreate)) + env = Environment(options = opts, + CPPDEFINES={'DBDIR' : '"$DBDIR"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + <file name="__ROOT__/var/my_dbdir"> + /opt/location + </file> + </scons_example> + + <para> + + Lastly, if you don't care whether the path exists, + is a file, or a directory, + use the &PathOption_PathAccept; method + to accept any path that the user supplies: + + </para> + + <scons_example name="PathAccept"> + <file name="SConstruct" printme="1"> + opts = Options('custom.py') + opts.Add(PathOption('OUTPUT', + 'Path to output file or directory', + None, + PathOption.PathAccept)) + env = Environment(options = opts, + CPPDEFINES={'OUTPUT' : '"$OUTPUT"'}) + env.Program('foo.c') + </file> + <file name="foo.c"> + foo.c + </file> + </scons_example> + </section> <section> diff --git a/doc/user/command-line.sgml b/doc/user/command-line.sgml index c488f7f..70658e0 100644 --- a/doc/user/command-line.sgml +++ b/doc/user/command-line.sgml @@ -1286,6 +1286,102 @@ scons: `foo.o' is up to date. </screen> + <para> + + By default, &PathOption; checks to make sure + that the specified path exists and generates an error if it + doesn't: + + </para> + + <screen> + % <userinput>scons -Q CONFIG=/does/not/exist foo.o</userinput> + + scons: *** Path for option CONFIG does not exist: /does/not/exist + File "SConstruct", line 6, in ? + </screen> + + <para> + + &PathOption; provides a number of methods + that you can use to change this behavior. + If you want to ensure that any specified paths are, + in fact, files and not directories, + use the &PathOption_PathIsFile; method: + + </para> + + <programlisting> + opts = Options('custom.py') + opts.Add(PathOption('CONFIG', + 'Path to configuration file', + '/etc/my_config', + PathOption.PathIsFile)) + env = Environment(options = opts, + CPPDEFINES={'CONFIG_FILE' : '"$CONFIG"'}) + env.Program('foo.c') + </programlisting> + + <para> + + Conversely, to ensure that any specified paths are + directories and not files, + use the &PathOption_PathIsDir; method: + + </para> + + <programlisting> + opts = Options('custom.py') + opts.Add(PathOption('DBDIR', + 'Path to database directory', + '/var/my_dbdir', + PathOption.PathIsDir)) + env = Environment(options = opts, + CPPDEFINES={'DBDIR' : '"$DBDIR"'}) + env.Program('foo.c') + </programlisting> + + <para> + + If you want to make sure that any specified paths + are directories, + and you would like the directory created + if it doesn't already exist, + use the &PathOption_PathIsDirCreate; method: + + </para> + + <programlisting> + opts = Options('custom.py') + opts.Add(PathOption('DBDIR', + 'Path to database directory', + '/var/my_dbdir', + PathOption.PathIsDirCreate)) + env = Environment(options = opts, + CPPDEFINES={'DBDIR' : '"$DBDIR"'}) + env.Program('foo.c') + </programlisting> + + <para> + + Lastly, if you don't care whether the path exists, + is a file, or a directory, + use the &PathOption_PathAccept; method + to accept any path that the user supplies: + + </para> + + <programlisting> + opts = Options('custom.py') + opts.Add(PathOption('OUTPUT', + 'Path to output file or directory', + None, + PathOption.PathAccept)) + env = Environment(options = opts, + CPPDEFINES={'OUTPUT' : '"$OUTPUT"'}) + env.Program('foo.c') + </programlisting> + </section> <section> diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 20842b4..523ace9 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -357,6 +357,9 @@ RELEASE 0.97 - XXX which cleans up a lot of special-case code in various methods and caches additional values to speed up most configurations. + - Add a PathAccept validator to the list of new canned PathOption + validators. + From Levi Stephen: - Allow $JARCHDIR to be expanded to other construction variables. diff --git a/src/engine/SCons/Options/PathOption.py b/src/engine/SCons/Options/PathOption.py index f407864..683ede0 100644 --- a/src/engine/SCons/Options/PathOption.py +++ b/src/engine/SCons/Options/PathOption.py @@ -1,29 +1,44 @@ -"""engine.SCons.Options.PathOption +"""SCons.Options.PathOption -This file defines an option type for SCons implementing 'package -activation'. +This file defines an option type for SCons implementing path settings. -To be used whenever a 'package' may be enabled/disabled and the -package path may be specified. +To be used whenever a a user-specified path override should be allowed. + +Arguments to PathOption are: + option-name = name of this option on the command line (e.g. "prefix") + option-help = help string for option + option-dflt = default value for this option + validator = [optional] validator for option value. Predefined + validators are: + + PathAccept -- accepts any path setting; no validation + PathIsDir -- path must be an existing directory + PathIsDirCreate -- path must be a dir; will create + PathIsFile -- path must be a file + PathExists -- path must exist (any type) [default] + + The validator is a function that is called and which + should return True or False to indicate if the path + is valid. The arguments to the validator function + are: (key, val, env). The key is the name of the + option, the val is the path specified for the option, + and the env is the env to which the Otions have been + added. Usage example: Examples: - x11=no (disables X11 support) - x11=yes (will search for the package installation dir) - x11=/usr/local/X11 (will check this path for existance) - - To replace autoconf's --with-xxx=yyy + prefix=/usr/local opts = Options() opts = Options() opts.Add(PathOption('qtdir', 'where the root of Qt is installed', - qtdir)) + qtdir, PathIsDir)) opts.Add(PathOption('qt_includes', 'where the Qt includes are installed', - '$qtdir/includes')) + '$qtdir/includes', PathIsDirCreate)) opts.Add(PathOption('qt_libraries', 'where the Qt library is installed', '$qtdir/lib')) @@ -62,6 +77,10 @@ import SCons.Errors class _PathOptionClass: + def PathAccept(self, key, val, env): + """Accepts any path, no checking done.""" + pass + def PathIsDir(self, key, val, env): """Validator to check if Path is a directory.""" if not os.path.isdir(val): @@ -102,8 +121,8 @@ class _PathOptionClass: are returned with the correct converter and validator appended. The result is usable for input to opts.Add() . - A 'package list' option may either be 'all', 'none' or a list of - package names (seperated by space). + The 'default' option specifies the default path to use if the + user does not specify an override with this option. validator is a validator, see this file for examples """ diff --git a/src/engine/SCons/Options/PathOptionTests.py b/src/engine/SCons/Options/PathOptionTests.py index 9749ee7..22e79ae 100644 --- a/src/engine/SCons/Options/PathOptionTests.py +++ b/src/engine/SCons/Options/PathOptionTests.py @@ -159,6 +159,28 @@ class PathOptionTestCase(unittest.TestCase): except: raise "did not catch expected UserError" + def test_PathAccept(self): + """Test the PathAccept validator""" + opts = SCons.Options.Options() + opts.Add(SCons.Options.PathOption('test', + 'test option help', + '/default/path', + SCons.Options.PathOption.PathAccept)) + + test = TestCmd.TestCmd(workdir='') + test.subdir('dir') + test.write('file', "file\n") + + o = opts.options[0] + + o.validator('X', test.workpath('file'), {}) + + d = test.workpath('d') + o.validator('X', d, {}) + + dne = test.workpath('does_not_exist') + o.validator('X', dne, {}) + def test_validator(self): """Test the PathOption validator argument""" opts = SCons.Options.Options() diff --git a/test/Options/PathOption.py b/test/Options/PathOption.py index 4366730..55f95c5 100644 --- a/test/Options/PathOption.py +++ b/test/Options/PathOption.py @@ -119,6 +119,39 @@ non_existing_file = test.workpath('non_existing_file') test.write('SConstruct', """\ opts = Options(args=ARGUMENTS) opts.AddOptions( + PathOption('X', 'X variable', r'%s', validator=PathOption.PathAccept), + ) + +env = Environment(options=opts) + +print env['X'] + +Default(env.Alias('dummy', None)) +""" % default_subdir) + +test.run() +check([default_subdir]) + +test.run(arguments='"X=%s"' % existing_file) +check([existing_file]) + +test.run(arguments='"X=%s"' % non_existing_file) +check([non_existing_file]) + +test.run(arguments='"X=%s"' % existing_subdir) +check([existing_subdir]) + +test.run(arguments='"X=%s"' % non_existing_subdir) +check([non_existing_subdir]) + +test.must_not_exist(non_existing_file) +test.must_not_exist(non_existing_subdir) + + + +test.write('SConstruct', """\ +opts = Options(args=ARGUMENTS) +opts.AddOptions( PathOption('X', 'X variable', r'%s', validator=PathOption.PathIsFile), ) |