Skip to content

Commit

Permalink
Add ability to save "local" help only
Browse files Browse the repository at this point in the history
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 SCons#2356
Fixes SCons#3686

Signed-off-by: Mats Wichmann <mats@linux.com>
  • Loading branch information
mwichmann committed Aug 1, 2023
1 parent a7998e7 commit 137e02f
Show file tree
Hide file tree
Showing 7 changed files with 209 additions and 99 deletions.
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 @@ -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
Expand Down Expand Up @@ -528,10 +528,25 @@ def GetOption(self, name):
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:
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
31 changes: 18 additions & 13 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,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:
Expand Down
56 changes: 23 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 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,
Expand All @@ -135,8 +117,16 @@ 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> will clobber
any help output associated with &f-link-AddOption; calls.
To preserve the help output from &AddOption;,
add the <literal>append=True</literal> keyword argument.
This also preserves the 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 137e02f

Please sign in to comment.