Skip to content

Commit 4ec9a65

Browse files
authored
Merge pull request #4217 from bdbaddog/add_api_to_check_for_invalid_options_issue_4187
Add ValidateOption() API
2 parents c7deb78 + 6f94c86 commit 4ec9a65

15 files changed

Lines changed: 280 additions & 12 deletions

CHANGES.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ NOTE: 4.3.0 now requires Python 3.6.0 and above. Python 3.5.x is no longer suppo
99

1010
RELEASE VERSION/DATE TO BE FILLED IN LATER
1111

12+
From William Deegan:
13+
- Added ValidateOptions() which will check that all command line options are in either
14+
those specified by SCons itself, or by AddOption() in SConstruct/SConscript. It should
15+
not be called until all AddOption() calls are completed. Resolves Issue #4187
16+
1217
From Dan Mezhiborsky:
1318
- Add newline to end of compilation db (compile_commands.json).
1419

RELEASE.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ Here is a summary of the changes since 4.4.0:
1616
NEW FUNCTIONALITY
1717
-----------------
1818

19-
- List new features (presumably why a checkpoint is being released)
19+
- Added ValidateOptions() which will check that all command line options are in either
20+
those specified by SCons itself, or by AddOption() in SConstruct/SConscript. It should
21+
not be called until all AddOption() calls are completed. Resolves Issue #4187
2022

2123
DEPRECATED FUNCTIONALITY
2224
------------------------

SCons/Script/Main.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,26 @@ def GetOption(name):
492492
def SetOption(name, value):
493493
return OptionsParser.values.set_option(name, value)
494494

495+
496+
def ValidateOptions(throw_exception=False) -> None:
497+
"""Validate options passed to SCons on the command line.
498+
499+
If you call this after you set all your command line options with AddOption(),
500+
it will verify that all command line options are valid.
501+
So if you added an option --xyz and you call SCons with --xyy you can cause
502+
SCons to issue an error message and exit by calling this function.
503+
504+
:param bool throw_exception: (Optional) Should this function raise an error if there's an invalid option on the command line, or issue a message and exit with error status.
505+
506+
:raises SConsBadOptionError: If throw_exception is True and there are invalid options on command line.
507+
508+
.. versionadded:: 4.4.1
509+
"""
510+
511+
OptionsParser.raise_exception_on_error = throw_exception
512+
OptionsParser.preserve_unknown_options = False
513+
OptionsParser.parse_args(OptionsParser.largs, OptionsParser.values)
514+
495515
def PrintHelp(file=None):
496516
OptionsParser.print_help(file=file)
497517

@@ -1364,6 +1384,7 @@ def _exec_main(parser, values):
13641384
else:
13651385
_main(parser)
13661386

1387+
13671388
def main():
13681389
global OptionsParser
13691390
global exit_status

SCons/Script/Main.xml

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,6 +740,7 @@ Multiple targets can be passed in to a single call to
740740
</para>
741741
</summary>
742742
</scons_function>
743+
743744
<scons_function name="SetOption">
744745
<arguments>
745746
(name, value)
@@ -943,6 +944,68 @@ Example:
943944
SetOption('max_drift', 0)
944945
</example_commands>
945946
</summary>
947+
948+
946949
</scons_function>
947950

951+
<scons_function name="ValidateOptions">
952+
<arguments signature="global">
953+
([throw_exception=False])
954+
</arguments>
955+
956+
<summary>
957+
<para>
958+
Check that all the options specified on the command line are either defined by SCons itself
959+
or defined by calls to &f-link-AddOption;.
960+
</para>
961+
<para>
962+
This function should only be called after the last &f-link-AddOption; call in your &SConscript;
963+
logic.
964+
</para>
965+
<para>
966+
Be aware that some tools call &f-link-AddOption;, if you are getting error messages for arguments
967+
that they add, you will need to ensure that you load those tools before you call &f-ValidateOptions;.
968+
</para>
969+
<para>
970+
If there are any command line options not defined, calling this function will cause SCons to issue an
971+
error message and then exit with an error exit
972+
status.</para>
973+
<para>If the optional <parameter>throw_exception</parameter> is <literal>True</literal>, &f-ValidateOptions; will raise a
974+
<exceptionname>SConsBadOptionError</exceptionname>
975+
exception. This would allow the calling
976+
&SConscript; logic can catch that exception and handle invalid options itself.
977+
</para>
978+
979+
<para>
980+
Example:
981+
</para>
982+
983+
<example_commands>
984+
try:
985+
ValidateOptions(throw_exception=True)
986+
except SConsBadOptionError as e:
987+
print("Parser is SConsOptionParser:%s" % (isinstance(e.parser, SConsOptionParser)))
988+
print("Message is :%s" % e.opt_str)
989+
Exit(3)
990+
</example_commands>
991+
992+
<para>
993+
This function is useful to force SCons to fail fast before you execute any expensive logic later in your
994+
build logic.
995+
For example if you specify build options via any flags, a simple typo could yield the incorrect build
996+
option throughout your entire build.
997+
</para>
998+
<example_commands>
999+
scons --compilers=mingw (the correct flag is --compiler)
1000+
</example_commands>
1001+
<para>
1002+
Could cause SCons to run configure steps with the incorrect compiler. Costing developer time trying to
1003+
track down why the configure logic failed with a compiler which should work.
1004+
</para>
1005+
1006+
1007+
1008+
</summary>
1009+
</scons_function>
1010+
9481011
</sconsdoc>

SCons/Script/SConsOptions.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -289,14 +289,36 @@ def format_help(self, formatter):
289289
return result
290290

291291

292+
class SConsBadOptionError(optparse.BadOptionError):
293+
"""Exception used to indicate that invalid command line options were specified
294+
295+
:ivar str opt_str: The offending option specified on command line which is not recognized
296+
:ivar OptionParser parser: The active argument parser
297+
298+
"""
299+
300+
def __init__(self, opt_str, parser=None):
301+
self.opt_str = opt_str
302+
self.parser = parser
303+
304+
def __str__(self):
305+
return _("no such option: %s") % self.opt_str
306+
307+
292308
class SConsOptionParser(optparse.OptionParser):
293309
preserve_unknown_options = False
310+
raise_exception_on_error = False
294311

295312
def error(self, msg):
296-
# overridden OptionValueError exception handler
297-
self.print_usage(sys.stderr)
298-
sys.stderr.write("SCons Error: %s\n" % msg)
299-
sys.exit(2)
313+
"""
314+
overridden OptionValueError exception handler
315+
"""
316+
if self.raise_exception_on_error:
317+
raise SConsBadOptionError(msg, self)
318+
else:
319+
self.print_usage(sys.stderr)
320+
sys.stderr.write("SCons Error: %s\n" % msg)
321+
sys.exit(2)
300322

301323
def _process_long_opt(self, rargs, values):
302324
""" SCons-specific processing of long options.

SCons/Script/SConscript.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,7 @@ def GetOption(self, name):
528528
name = self.subst(name)
529529
return SCons.Script.Main.GetOption(name)
530530

531+
531532
def Help(self, text, append=False):
532533
text = self.subst(text, raw=1)
533534
SCons.Script.HelpFunction(text, append=append)

SCons/Script/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
PrintHelp = Main.PrintHelp
108108
GetOption = Main.GetOption
109109
SetOption = Main.SetOption
110+
ValidateOptions = Main.ValidateOptions
110111
Progress = Main.Progress
111112
GetBuildFailures = Main.GetBuildFailures
112113

SCons/__init__.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
__version__="4.4.0"
1+
__version__="4.4.1"
22
__copyright__="Copyright (c) 2001 - 2022 The SCons Foundation"
33
__developer__="bdbaddog"
4-
__date__="Sat, 30 Jul 2022 14:11:34 -0700"
4+
__date__="Mon, 15 Aug 2022 11:59:33 -0700"
55
__buildsys__="M1Dog2021"
6-
__revision__="fc8d0ec215ee6cba8bc158ad40c099be0b598297"
7-
__build__="fc8d0ec215ee6cba8bc158ad40c099be0b598297"
6+
__revision__="18745cfc5e75df8028682183097202f926e22134"
7+
__build__="18745cfc5e75df8028682183097202f926e22134"
88
# make sure compatibility is always in place
99
import SCons.compat # noqa

bin/update_doc_files.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/bash
2+
3+
python bin/docs-update-generated.py
4+
python bin/docs-validate.py
5+
python bin/docs-create-example-outputs.py
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<screen xmlns="http://www.scons.org/dbxsd/v1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">% <userinput>scons -Q</userinput>
2-
cc -o f4.o -c f4.c
3-
cc -o f2.o -c f2.c
42
cc -o f3.o -c f3.c
3+
cc -o f4.o -c f4.c
54
cc -o f1.o -c f1.c
5+
cc -o f2.o -c f2.c
66
cc -o f5.o -c f5.c
77
cc -o prog f1.o f2.o f3.o f4.o f5.o
88
</screen>

0 commit comments

Comments
 (0)