From 1bdca141aaffd784827f62657c95e61f39fe1eb3 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Sun, 30 Jul 2023 07:48:57 -0600 Subject: Add ability to save "local" help only An additional keyword argument, "local_only", is now recorgnized by Help(). If true, and "append" is True, then only project-defined help messages are saved into the help text. That is, save help added by calls to AddOption, but not SCons' own help, which is added a different way. Fixes #2356 Fixes #3686 Signed-off-by: Mats Wichmann --- CHANGES.txt | 4 ++ RELEASE.txt | 4 ++ SCons/Script/Main.py | 9 +++-- SCons/Script/SConsOptions.py | 61 ++++++++++++++++++++++++++--- SCons/Script/SConscript.py | 21 ++++++++-- SCons/Script/SConscript.xml | 39 ++++++++++++------- SCons/Script/__init__.py | 31 ++++++++------- doc/user/output.xml | 56 +++++++++++---------------- test/Help.py | 91 ++++++++++++++++++++++++++++++-------------- 9 files changed, 217 insertions(+), 99 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index db96df0..d2c074d 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -131,6 +131,10 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER - More tweaking of test framework overview (which is duplicated onto the website, but not in the regular documentation section). - Extend range of recognized Java versions to 20. + - The Help() function now takes an additional keyword argument + keep_local, which if combined with the append argument direct + help from only AddOption ("project local") calls to be kept in the + help message, not SCons' own option help. From Jonathon Reinhart: - Fix another instance of `int main()` in CheckLib() causing failures diff --git a/RELEASE.txt b/RELEASE.txt index f72a2a6..22be0f5 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -60,6 +60,10 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY architecture combination. For example, when using VS2022 on arm64, the arm64 native tools are only installed for the 14.3x toolsets. - Extend range of recognized Java versions to 20. +- The Help() function now takes an additional keyword argument keep_local. + On first call to Help(), if both append and keep_local are True, + the help from project AddOption calls is kept in the help message, + but not SCons' own option help. FIXES ----- diff --git a/SCons/Script/Main.py b/SCons/Script/Main.py index 361b4b2..5ccb197 100644 --- a/SCons/Script/Main.py +++ b/SCons/Script/Main.py @@ -564,10 +564,11 @@ def ValidateOptions(throw_exception: bool=False) -> None: OptionsParser.preserve_unknown_options = False OptionsParser.parse_args(OptionsParser.largs, OptionsParser.values) -def PrintHelp(file=None) -> None: - OptionsParser.print_help(file=file) - - +def PrintHelp(file=None, local_only: bool = False) -> None: + if local_only: + OptionsParser.print_local_option_help(file=file) + else: + OptionsParser.print_help(file=file) # utility functions diff --git a/SCons/Script/SConsOptions.py b/SCons/Script/SConsOptions.py index d2893ba..e799716 100644 --- a/SCons/Script/SConsOptions.py +++ b/SCons/Script/SConsOptions.py @@ -271,8 +271,7 @@ class SConsOption(optparse.Option): class SConsOptionGroup(optparse.OptionGroup): - """ - A subclass for SCons-specific option groups. + """A subclass for SCons-specific option groups. The only difference between this and the base class is that we print the group's help text flush left, underneath their own title but @@ -288,7 +287,8 @@ class SConsOptionGroup(optparse.OptionGroup): formatter.dedent() result = formatter.format_heading(self.title) formatter.indent() - result = result + optparse.OptionContainer.format_help(self, formatter) + # bypass OptionGroup format_help and call up to its parent + result += optparse.OptionContainer.format_help(self, formatter) return result @@ -474,7 +474,6 @@ class SConsOptionParser(optparse.OptionParser): self.local_option_group = group result = group.add_option(*args, **kw) - if result: # The option was added successfully. We now have to add the # default value to our object that holds the default values @@ -489,6 +488,40 @@ class SConsOptionParser(optparse.OptionParser): return result + def format_local_option_help(self, formatter=None, file=None): + """Return the help for the project-level ("local") options. + + .. versionadded:: 4.6.0 + """ + if formatter is None: + formatter = self.formatter + try: + group = self.local_option_group + except AttributeError: + return "" + + formatter.store_local_option_strings(self, group) + for opt in group.option_list: + strings = formatter.format_option_strings(opt) + formatter.option_strings[opt] = strings + + # defeat our own cleverness, which starts out by dedenting + formatter.indent() + local_help = group.format_help(formatter) + formatter.dedent() + return local_help + + def print_local_option_help(self, file=None): + """Print help for just project-defined options. + + Writes to *file* (default stdout). + + .. versionadded:: 4.6.0 + """ + if file is None: + file = sys.stdout + file.write(self.format_local_option_help()) + class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): def format_usage(self, usage) -> str: @@ -504,7 +537,7 @@ class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): """ if heading == 'Options': heading = "SCons Options" - return optparse.IndentedHelpFormatter.format_heading(self, heading) + return super().format_heading(heading) def format_option(self, option): """ Customized option formatter. @@ -577,6 +610,24 @@ class SConsIndentedHelpFormatter(optparse.IndentedHelpFormatter): result.append("\n") return "".join(result) + def store_local_option_strings(self, parser, group): + """Local-only version of store_option_strings. + + We need to replicate this so the formatter will be set up + properly if we didn't go through the "normal" store_option_strings + + .. versionadded:: 4.6.0 + """ + self.indent() + max_len = 0 + for opt in group.option_list: + strings = self.format_option_strings(opt) + self.option_strings[opt] = strings + max_len = max(max_len, len(strings) + self.current_indent) + self.dedent() + self.help_position = min(max_len + 2, self.max_help_position) + self.help_width = max(self.width - self.help_position, 11) + def Parser(version): """Returns a parser object initialized with the standard SCons options. diff --git a/SCons/Script/SConscript.py b/SCons/Script/SConscript.py index c0b556c..66ce5b6 100644 --- a/SCons/Script/SConscript.py +++ b/SCons/Script/SConscript.py @@ -145,7 +145,7 @@ def Return(*vars, **kw): stack_bottom = '% Stack boTTom %' # hard to define a variable w/this name :) -def handle_missing_SConscript(f, must_exist=None): +def handle_missing_SConscript(f: str, must_exist=None) -> None: """Take appropriate action on missing file in SConscript() call. Print a warning or raise an exception on missing file, unless @@ -528,10 +528,25 @@ class SConsEnvironment(SCons.Environment.Base): name = self.subst(name) return SCons.Script.Main.GetOption(name) + def Help(self, text, append: bool = False, keep_local: bool = False) -> None: + """Update the help text. - def Help(self, text, append: bool=False) -> None: + The previous help text has *text* appended to it, except on the + first call. On first call, the values of *append* and *keep_local* + are considered to determine what is appended to. + + Arguments: + text: string to add to the help text. + append: on first call, if true, keep the existing help text + (default False). + keep_local: on first call, if true and *append* is also true, + keep only the help text from AddOption calls. + + .. versionchanged:: 4.6.0 + The *keep_local* parameter was added. + """ text = self.subst(text, raw=1) - SCons.Script.HelpFunction(text, append=append) + SCons.Script.HelpFunction(text, append=append, keep_local=keep_local) def Import(self, *vars): try: diff --git a/SCons/Script/SConscript.xml b/SCons/Script/SConscript.xml index 7a4bc29..b984f7d 100644 --- a/SCons/Script/SConscript.xml +++ b/SCons/Script/SConscript.xml @@ -238,29 +238,42 @@ file is found. -(text, append=False) +(text, append=False, local_only=False) -Specifies a local help message to be printed if the - -argument is given to -&scons;. -Subsequent calls to -&f-Help; -append text to the previously -defined local help text. +Adds text to the help message shown when +&scons; is called with the + or +argument. -For the first call to &f-Help; only, +On the first call to &f-Help;, if append is False -(the default) -any local help message generated through -&f-link-AddOption; calls is replaced. +(the default), any existing help text is discarded. +The default help text is the help for the &scons; +command itself plus help collected from any +project-local &f-link-AddOption; calls. +This is the help printed if &f-Help; has never been called. If append is True, text is appended to the existing help text. +If local_only is also True +(the default is False), +the project-local help from &f-AddOption; calls is preserved +in the help message but the &scons; command help is not. + + +Subsequent calls to +&f-Help; ignore the keyword arguments +append and +local_only +and always append to the existing help text. + +Changed in 4.6.0: added local_only. + + diff --git a/SCons/Script/__init__.py b/SCons/Script/__init__.py index e398ecf..6811e57 100644 --- a/SCons/Script/__init__.py +++ b/SCons/Script/__init__.py @@ -100,7 +100,6 @@ main = Main.main BuildTask = Main.BuildTask CleanTask = Main.CleanTask QuestionTask = Main.QuestionTask -#PrintHelp = Main.PrintHelp #SConscriptSettableOptions = Main.SConscriptSettableOptions AddOption = Main.AddOption @@ -248,31 +247,37 @@ def _Set_Default_Targets(env, tlist) -> None: BUILD_TARGETS._add_Default(nodes) _build_plus_default._add_Default(nodes) -# + help_text = None -def HelpFunction(text, append: bool=False) -> None: + +def HelpFunction(text, append: bool = False, keep_local: bool = False) -> None: + """The implementaion of the the ``Help`` method. + + See :meth:`~SCons.Script.SConscript.Help`. + + .. versionchanged:: 4.6.0 + The *keep_local* parameter was added. + """ global help_text if help_text is None: if append: - s = StringIO() - PrintHelp(s) - help_text = s.getvalue() - s.close() + with StringIO() as s: + PrintHelp(s, local_only=keep_local) + help_text = s.getvalue() else: help_text = "" - help_text= help_text + text + help_text += text -# # Will be non-zero if we are reading an SConscript file. -sconscript_reading = 0 +sconscript_reading: int = 0 -_no_missing_sconscript = False -_warn_missing_sconscript_deprecated = True +_no_missing_sconscript: bool = False +_warn_missing_sconscript_deprecated: bool = True -def set_missing_sconscript_error(flag: int=1): +def set_missing_sconscript_error(flag: bool = True) -> bool: """Set behavior on missing file in SConscript() call. Returns: diff --git a/doc/user/output.xml b/doc/user/output.xml index cf6571c..3831088 100644 --- a/doc/user/output.xml +++ b/doc/user/output.xml @@ -1,4 +1,10 @@ + + %scons; @@ -19,31 +25,6 @@ xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd"> Controlling Build Output - - A key aspect of creating a usable build configuration @@ -67,7 +48,7 @@ users some help that describes the specific targets, build options, etc., that can be used for your build. - &SCons; provides the &Help; function + &SCons; provides the &f-link-Help; function to allow you to specify this help text: @@ -83,7 +64,7 @@ Type: 'scons program' to build the production program, - Optionally, one can specify the append flag: + Optionally, you can specify the append flag: @@ -107,7 +88,7 @@ Type: 'scons program' to build the production program, When the &SConstruct; or &SConscript; files - contain such a call to the &Help; function, + contain a call to the &Help; function, the specified help text will be displayed in response to the &SCons; option: @@ -120,11 +101,12 @@ Type: 'scons program' to build the production program, The &SConscript; files may contain - multiple calls to the &Help; function, + multiple calls to the &f-link-Help; function, in which case the specified text(s) will be concatenated when displayed. - This allows you to split up the - help text across multiple &SConscript; files. + This allows you to define bits of help text together with + the corresponding feature, even if speread + across multiple &SConscript; files. In this situation, the order in which the &SConscript; files are called will determine the order in which the &Help; functions are called, @@ -135,8 +117,16 @@ Type: 'scons program' to build the production program, - When used with &AddOption; Help("text", append=False) will clobber any help output associated with AddOption(). - To preserve the help output from AddOption(), set append=True. + Calling Help("text") will clobber + any help output associated with &f-link-AddOption; calls. + To preserve the help output from &AddOption;, + add the append=True keyword argument. + This also preserves the help for the &scons; command itself. + To preserve only the &AddOption; help, + also add the local_only=True keyword argument. + (This only matters the first time you call &Append;, + on any subsequent calls the text you passed is added + to the existing help text). diff --git a/test/Help.py b/test/Help.py index 95f57ad..a090d42 100644 --- a/test/Help.py +++ b/test/Help.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # -# __COPYRIGHT__ +# MIT License +# +# Copyright The SCons Foundation # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -20,9 +22,6 @@ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# - -__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" import TestSCons @@ -85,47 +84,46 @@ test.run(arguments = '-h', stdout = expect) # Bug #2831 - append flag to Help doesn't wipe out addoptions and variables used together test.write('SConstruct', r""" -AddOption('--debugging', - dest='debugging', - action='store_true', - default=False, - metavar='BDEBUGGING', - help='Compile with debugging symbols') +AddOption( + '--debugging', + dest='debugging', + action='store_true', + default=False, + metavar='BDEBUGGING', + help='Compile with debugging symbols', +) vars = Variables() -vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', - ['python'])) - +vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', ['python'])) +DefaultEnvironment(tools=[]) env = Environment() - -Help(vars.GenerateHelpText(env),append=True) +Help(vars.GenerateHelpText(env), append=True) """) expect = ".*--debugging.*Compile with debugging symbols.*buildmod: List of modules to build.*" - test.run(arguments = '-h', stdout = expect, match=TestSCons.match_re_dotall) - # Bug 2831 # This test checks to verify that append=False doesn't include anything # but the expected help for the specified Variable() test.write('SConstruct', r""" - -AddOption('--debugging', - dest='debugging', - action='store_true', - default=False, - metavar='BDEBUGGING', - help='Compile with debugging symbols') +AddOption( + '--debugging', + dest='debugging', + action='store_true', + default=False, + metavar='BDEBUGGING', + help='Compile with debugging symbols', +) vars = Variables() -vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', - ['python'])) +vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', ['python'])) +DefaultEnvironment(tools=[]) env = Environment() -Help(vars.GenerateHelpText(env),append=False) +Help(vars.GenerateHelpText(env), append=False) """) expect = """\ @@ -141,8 +139,45 @@ buildmod: List of modules to build Use scons -H for help about SCons built-in command-line options. """ -test.run(arguments = '-h', stdout = expect) +test.run(arguments='-h', stdout=expect) + +# Enhancement: keep_local flag saves the AddOption help, +# but not SCons' own help. +test.write('SConstruct', r""" +AddOption( + '--debugging', + dest='debugging', + action='store_true', + default=False, + metavar='BDEBUGGING', + help='Compile with debugging symbols', +) + +vars = Variables() +vars.Add(ListVariable('buildmod', 'List of modules to build', 'none', ['python'])) + +DefaultEnvironment(tools=[]) +env = Environment() + +Help(vars.GenerateHelpText(env), append=True, keep_local=True) +""") + +expect = """\ +scons: Reading SConscript files ... +scons: done reading SConscript files. +Local Options: + --debugging Compile with debugging symbols + +buildmod: List of modules to build + (all|none|comma-separated list of names) + allowed names: python + default: none + actual: None + +Use scons -H for help about SCons built-in command-line options. +""" +test.run(arguments='-h', stdout=expect) test.pass_test() -- cgit v0.12 From 70b64467bf91b6a1ea1224f43de4d4f416d94799 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Tue, 1 Aug 2023 15:24:16 -0600 Subject: Further tweak user guide Help description [skip appveyor] Signed-off-by: Mats Wichmann --- doc/user/output.xml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/doc/user/output.xml b/doc/user/output.xml index 3831088..7a63540 100644 --- a/doc/user/output.xml +++ b/doc/user/output.xml @@ -104,8 +104,8 @@ Type: 'scons program' to build the production program, multiple calls to the &f-link-Help; function, in which case the specified text(s) will be concatenated when displayed. - This allows you to define bits of help text together with - the corresponding feature, even if speread + This allows you to define fragments of help text together with + the corresponding feature, even if spread across multiple &SConscript; files. In this situation, the order in which the &SConscript; files are called @@ -117,11 +117,13 @@ Type: 'scons program' to build the production program, - Calling Help("text") will clobber - any help output associated with &f-link-AddOption; calls. - To preserve the help output from &AddOption;, - add the append=True keyword argument. - This also preserves the help for the &scons; command itself. + Calling Help("text") overwrites + the help text that otherwise would be collected from any + command-line options defined in &f-link-AddOption; calls. + To preserve the &AddOption; help text, + add the append=True keyword argument + when calling Help. + This also preserves the option help for the &scons; command itself. To preserve only the &AddOption; help, also add the local_only=True keyword argument. (This only matters the first time you call &Append;, -- cgit v0.12 From 99e97832fc1fbb92a2d53eccb8404c711c64bdd2 Mon Sep 17 00:00:00 2001 From: Mats Wichmann Date: Wed, 9 Aug 2023 07:55:26 -0600 Subject: Update Help note in CHANGES, RELEASE [skip ci] Signed-off-by: Mats Wichmann --- CHANGES.txt | 6 +++--- RELEASE.txt | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/CHANGES.txt b/CHANGES.txt index d2c074d..a17c799 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -132,9 +132,9 @@ RELEASE VERSION/DATE TO BE FILLED IN LATER the website, but not in the regular documentation section). - Extend range of recognized Java versions to 20. - The Help() function now takes an additional keyword argument - keep_local, which if combined with the append argument direct - help from only AddOption ("project local") calls to be kept in the - help message, not SCons' own option help. + keep_local: when starting to build a help message, you can now + retain help from AddOption calls, but omit help for SCons' own + command-line options with "Help(newtext, append=True, local_only=True)". From Jonathon Reinhart: - Fix another instance of `int main()` in CheckLib() causing failures diff --git a/RELEASE.txt b/RELEASE.txt index 22be0f5..60c361e 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -60,10 +60,10 @@ CHANGED/ENHANCED EXISTING FUNCTIONALITY architecture combination. For example, when using VS2022 on arm64, the arm64 native tools are only installed for the 14.3x toolsets. - Extend range of recognized Java versions to 20. -- The Help() function now takes an additional keyword argument keep_local. - On first call to Help(), if both append and keep_local are True, - the help from project AddOption calls is kept in the help message, - but not SCons' own option help. + The Help() function now takes an additional keyword argument keep_local: + when starting to build a help message, you can now retain help from AddOption + calls (options added for the project_, but omit help for SCons' own cmdline + options with "Help(newtext, append=True, local_only=True)". FIXES ----- -- cgit v0.12