diff --git a/build/lib/help/parse.py b/build/lib/help/parse.py index 1f6c8cc94..dca5bc333 100644 --- a/build/lib/help/parse.py +++ b/build/lib/help/parse.py @@ -223,16 +223,35 @@ def _allow_list_inherit(xml_allow, inherit_map, name): """The list an allow list inherits, or the list itself when it inherits none. An option that allows what another option allows describes the values once and inherits them, the way the configuration - inherits the values themselves, since the same list written out twice is two lists to keep in step.""" + inherits the values themselves, since the same list written out twice is two lists to keep in step. + + A list documented under a command is inherited by naming the command as well. An option that a command documents differently + is documented once per command, so the option name alone does not say which of those lists is meant, and an option that only + the commands document has no list of its own for the name to find.""" inherit = xml_node_attribute(xml_allow, "inherit") if inherit is None: return xml_allow - check(inherit in inherit_map, "%s inherits the allow list of option '%s', which does not describe one" % (name, inherit)) + inherit_cmd = xml_node_attribute(xml_allow, "command") - return inherit_map[inherit] + check( + (inherit_cmd, inherit) in inherit_map, + "%s inherits the allow list of option '%s'%s, which does not describe one" + % (name, inherit, "" if inherit_cmd is None else " for command '%s'" % inherit_cmd), + ) + + return inherit_map[(inherit_cmd, inherit)] + + +#################################################################################################################################### +def _allow_list_inherit_add(inherit_map, key, description): + """Record the list documented in help text so an option that allows the same values can inherit it.""" + + for _, xml_allow in _allow_list_find(description): + if len(xml_node_child_list(xml_allow, "allow-item")) > 0: + inherit_map[key] = xml_allow #################################################################################################################################### @@ -324,9 +343,11 @@ def _allow_list(bld_hlp, bld_cfg): inherit_map = {} for opt_hlp in bld_hlp.opt_list: - for _, xml_allow in _allow_list_find(opt_hlp.description): - if len(xml_node_child_list(xml_allow, "allow-item")) > 0: - inherit_map[opt_hlp.name] = xml_allow + _allow_list_inherit_add(inherit_map, (None, opt_hlp.name), opt_hlp.description) + + for cmd_hlp in bld_hlp.cmd_list: + for opt_hlp in cmd_hlp.opt_list or []: + _allow_list_inherit_add(inherit_map, (cmd_hlp.name, opt_hlp.name), opt_hlp.description) for opt in bld_cfg.opt_list: opt_hlp = _find(bld_hlp.opt_list, opt.name) diff --git a/test/src/module/build/help/parse_test.py b/test/src/module/build/help/parse_test.py index 816d8ee05..9740ad137 100644 --- a/test/src/module/build/help/parse_test.py +++ b/test/src/module/build/help/parse_test.py @@ -52,6 +52,7 @@ option: - latest - oldest command: + backup: {} restore: {} type: @@ -75,8 +76,10 @@ option: """ # Help for everything the configuration declares. Buffer size is documented in a configuration section, force and stanza on the -# command line, and set and type only by the command that takes them. File buffer size allows what buffer size allows, so it -# inherits the list rather than describing it again. Process has no help at all, since no user can give it. +# command line, and set and type only by the commands that take them. File buffer size allows what buffer size allows, so it +# inherits the list rather than describing it again, and restore inherits the list backup describes for set the same way, naming +# the command since an option documented by more than one has a list per command. Process has no help at all, since no user can +# give it. HELP = """ Configuration description. @@ -162,7 +165,9 @@ HELP = """ Set summary. -

Set description. Allowed values are .

+

Set description.

+ +
@@ -182,6 +187,19 @@ HELP = """

Backup description.

+ + + + @@ -265,7 +283,7 @@ def test_help_parse(): # An option a command documents differently is under the command rather than in the option list assert_equal([opt.name for opt in cmd.opt_list], ["set", "type"]) - assert_is_none(_find(bld_hlp.cmd_list, "backup").opt_list) + assert_is_none(_find(bld_hlp.cmd_list, "help").opt_list) # Options are sorted and are found wherever they were documented assert_equal([opt.name for opt in bld_hlp.opt_list], ["buffer-size", "buffer-size-file", "force", "stanza"]) @@ -342,10 +360,6 @@ def test_help_parse_allow_list(): # command documents is rendered from what the option allows, or from what the command allows when it allows something else. cmd_hlp = _find(bld_hlp.cmd_list, "restore") - assert_in( - "

Set description. Allowed values are latest and oldest.

", - _render(_find(cmd_hlp.opt_list, "set").description), - ) assert_in( "

Type description. Allowed values are full, diff, and incr.

", _render(_find(cmd_hlp.opt_list, "type").description), @@ -354,12 +368,29 @@ def test_help_parse_allow_list(): # An option that allows what another option allows renders the list it inherits rather than one of its own assert_in(buffer_size_list, _render(_find(bld_hlp.opt_list, "buffer-size-file").description)) + # An option that more than one command documents renders the list the named command describes, in both places + set_list = ( + "

The following sets are supported:

" + "latest - The latest." + "oldest - The oldest." + ) + + assert_in(set_list, _render(_find(_find(bld_hlp.cmd_list, "backup").opt_list, "set").description)) + assert_in(set_list, _render(_find(cmd_hlp.opt_list, "set").description)) + # A list inherited from an option that describes none assert_equal( _error(HELP.replace('', '')), "option 'buffer-size-file' inherits the allow list of option 'stanza', which does not describe one", ) + # A list inherited from a command that describes none + assert_equal( + _error(HELP.replace('command="backup"', 'command="help"')), + "option 'set' for command 'restore' inherits the allow list of option 'set' for command 'help', which does not describe" + " one", + ) + # A value that is documented but not allowed assert_equal( _error(HELP.replace('', '')), @@ -387,7 +418,7 @@ def test_help_parse_allow_list(): # An allow list that is not documented at all, since a value a user cannot read about is a value they cannot use assert_equal( _error(HELP.replace("Allowed values are .", "")), - "option 'set' for command 'restore' must document its allow list", + "option 'type' for command 'restore' must document its allow list", ) @@ -404,7 +435,7 @@ def test_help_parse_error(): # An option with no help of its own must be documented by every command that takes it assert_equal( _error(HELP.replace('