Skip to content

Commit

Permalink
Merge pull request #4388 from mwichmann/feature/local-help
Browse files Browse the repository at this point in the history
Add ability to save "local" help only
  • Loading branch information
bdbaddog authored Aug 26, 2023
2 parents ef0cb9f + 7e8853f commit f4d343d
Show file tree
Hide file tree
Showing 9 changed files with 216 additions and 96 deletions.
4 changes: 4 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,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: 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)".
- A little more code "modernization", done via "pypgrade" tool set
to "3.6 and above" setting.
- Finish the change to make calling SConscript() with a nonexistent
Expand Down
4 changes: 4 additions & 0 deletions RELEASE.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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:
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)".
- Calling SConscript() with a nonexistent file is now an error.
Previously this succeeded - prior to SCons 3.0, silently; since 3.0, with
a warning. Developers can still instruct such an SConscript() call not
Expand Down
9 changes: 5 additions & 4 deletions SCons/Script/Main.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
61 changes: 56 additions & 5 deletions SCons/Script/SConsOptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,8 +271,7 @@ def _check_nargs_optional(self):


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
Expand All @@ -288,7 +287,8 @@ def format_help(self, formatter):
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


Expand Down Expand Up @@ -474,7 +474,6 @@ def add_local_option(self, *args, **kw):
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
Expand All @@ -489,6 +488,40 @@ def add_local_option(self, *args, **kw):

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:
Expand All @@ -504,7 +537,7 @@ def format_heading(self, heading):
"""
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.
Expand Down Expand Up @@ -577,6 +610,24 @@ def format_option(self, option):
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.
Expand Down
21 changes: 18 additions & 3 deletions SCons/Script/SConscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,10 +520,25 @@ def GetOption(self, name):
name = self.subst(name)
return SCons.Script.Main.GetOption(name)


def Help(self, text, append: bool=False) -> None:
def Help(self, text, append: bool = False, keep_local: bool = False) -> None:
"""Update the help text.
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:
Expand Down
39 changes: 26 additions & 13 deletions SCons/Script/SConscript.xml
Original file line number Diff line number Diff line change
Expand Up @@ -238,29 +238,42 @@ file is found.

<scons_function name="Help">
<arguments>
(text, append=False)
(text, append=False, local_only=False)
</arguments>
<summary>
<para>
Specifies a local help message to be printed if the
<option>-h</option>
argument is given to
&scons;.
Subsequent calls to
&f-Help;
append <parameter>text</parameter> to the previously
defined local help text.
Adds <parameter>text</parameter> to the help message shown when
&scons; is called with the
<option>-h</option> or <option>--help</option>
argument.
</para>
<para>
For the first call to &f-Help; only,
On the first call to &f-Help;,
if <parameter>append</parameter> is <constant>False</constant>
(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 <parameter>append</parameter> is <constant>True</constant>,
<parameter>text</parameter> is appended to
the existing help text.
If <parameter>local_only</parameter> is also <constant>True</constant>
(the default is <constant>False</constant>),
the project-local help from &f-AddOption; calls is preserved
in the help message but the &scons; command help is not.
</para>
<para>
Subsequent calls to
&f-Help; ignore the keyword arguments
<parameter>append</parameter> and
<parameter>local_only</parameter>
and always append to the existing help text.
</para>
<para>
<emphasis>Changed in 4.6.0</emphasis>: added <parameter>local_only</parameter>.
</para>

</summary>
</scons_function>

Expand Down
25 changes: 15 additions & 10 deletions SCons/Script/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@
BuildTask = Main.BuildTask
CleanTask = Main.CleanTask
QuestionTask = Main.QuestionTask
#PrintHelp = Main.PrintHelp
#SConscriptSettableOptions = Main.SConscriptSettableOptions

AddOption = Main.AddOption
Expand Down Expand Up @@ -248,26 +247,32 @@ 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 = True
_warn_missing_sconscript_deprecated = False # TODO: now unused
Expand Down
58 changes: 25 additions & 33 deletions doc/user/output.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
<?xml version='1.0'?>
<!--
SPDX-License-Identifier: MIT
Copyright The SCons Foundation
-->

<!DOCTYPE sconsdoc [
<!ENTITY % scons SYSTEM "../scons.mod">
%scons;
Expand All @@ -19,31 +25,6 @@
xsi:schemaLocation="http://www.scons.org/dbxsd/v1.0 http://www.scons.org/dbxsd/v1.0/scons.xsd">
<title>Controlling Build Output</title>

<!--
__COPYRIGHT__
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
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.
-->

<para>

A key aspect of creating a usable build configuration
Expand All @@ -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:

</para>
Expand All @@ -83,7 +64,7 @@ Type: 'scons program' to build the production program,

<para>

Optionally, one can specify the append flag:
Optionally, you can specify the <parameter>append</parameter> flag:

</para>

Expand All @@ -107,7 +88,7 @@ Type: 'scons program' to build the production program,
<para>

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>-h</option> option:

Expand All @@ -120,11 +101,12 @@ Type: 'scons program' to build the production program,
<para>

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 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
will determine the order in which the &Help; functions are called,
Expand All @@ -135,8 +117,18 @@ Type: 'scons program' to build the production program,

<para>

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 <literal>Help("text")</literal> 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 <literal>append=True</literal> keyword argument
when calling <literal>Help</literal>.
This also preserves the option help for the &scons; command itself.
To preserve only the &AddOption; help,
also add the <literal>local_only=True</literal> 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).

</para>

Expand Down
Loading

0 comments on commit f4d343d

Please sign in to comment.