source: rtems-central/rtemsqual/applconfig.py @ 735caf4

Last change on this file since 735caf4 was 735caf4, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 1, 2020 at 6:28:24 AM

applconfig: Support null notes

  • Property mode set to 100644
File size: 9.3 KB
Line 
1# SPDX-License-Identifier: BSD-2-Clause
2""" Functions for application configuration documentation generation. """
3
4# Copyright (C) 2019, 2020 embedded brains GmbH (http://www.embedded-brains.de)
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14#
15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25# POSSIBILITY OF SUCH DAMAGE.
26
27from typing import Any, Dict, List, Optional
28
29from rtemsqual.content import SphinxContent
30from rtemsqual.items import Item, ItemCache
31
32ItemMap = Dict[str, Item]
33
34
35def _gather_groups(item: Item, groups: ItemMap) -> None:
36    for child in item.children:
37        _gather_groups(child, groups)
38    if item["type"] == "interface" and item[
39            "interface-type"] == "appl-config-group":
40        groups[item.uid] = item
41
42
43def _gather_options(item: Item, options: ItemMap) -> None:
44    for child in item.children:
45        _gather_options(child, options)
46    if item["type"] == "interface" and item[
47            "interface-type"] == "appl-config-option":
48        options[item.uid] = item
49
50
51_FEATURE = "This configuration option is a boolean feature define."
52
53_OPTION_TYPES = {
54    "feature": _FEATURE,
55    "feature-enable": _FEATURE,
56    "integer": "This configuration option is an integer define.",
57    "initializer": "This configuration option is an initializer define."
58}
59
60_OPTION_DEFAULT_CONFIG = {
61    "feature":
62    lambda item: item["appl-config-option-default"],
63    "feature-enable":
64    lambda item:
65    """If this configuration option is undefined, then the described feature is not
66enabled."""
67}
68
69
70def _generate_feature(content: SphinxContent, item: Item, option_type: str,
71                      _item_cache: ItemCache) -> None:
72    content.add_definition_item("DEFAULT CONFIGURATION:",
73                                _OPTION_DEFAULT_CONFIG[option_type](item))
74
75
76def _generate_min_max(lines: List[str], value: str, word: str) -> None:
77    lines.append("The value of this configuration option shall be "
78                 f"{word} than or equal to {value}.")
79
80
81def _generate_set(lines: List[str], values: List[Any]) -> None:
82    value_set = "{" + ", ".join([str(x) for x in values]) + "}"
83    lines.append("The value of this configuration option shall be")
84    lines.append(f"an element of {value_set}.")
85
86
87def _start_constraint_list(lines: List[str]) -> None:
88    lines.append("The value of this configuration option shall "
89                 "satisfy all of the following")
90    lines.append("constraints:")
91
92
93def _generate_item_min(lines: List[str], constraint: Dict[str, Any]) -> None:
94    if "min" in constraint:
95        value = constraint["min"]
96        lines.append("")
97        lines.append(f"* It shall be greater than or equal to {value}.")
98
99
100def _generate_item_max(lines: List[str], constraint: Dict[str, Any]) -> None:
101    if "max" in constraint:
102        value = constraint["max"]
103        lines.append("")
104        lines.append(f"* It shall be less than or equal to {value}.")
105
106
107def _generate_item_custom(lines: List[str], constraint: Dict[str,
108                                                             Any]) -> None:
109    for custom in constraint.get("custom", []):
110        lines.append("")
111        custom = custom.replace("The value of this configuration option", "It")
112        custom = custom.strip().split("\n")
113        lines.append(f"* {custom[0]}")
114        lines.extend([f"  {x}" if x else "" for x in custom[1:]])
115
116
117def _resolve_constraint_links(content: SphinxContent, constraint: Dict[str,
118                                                                       Any],
119                              item_cache: ItemCache) -> None:
120    if "links" in constraint:
121        if "custom" not in constraint:
122            constraint["custom"] = []
123        for link in reversed(constraint["links"]):
124            item = item_cache[link]
125            item.register_license_and_copyrights(content)
126            constraint["custom"].append(item["text"])
127
128
129def _generate_constraint(content: SphinxContent, item: Item,
130                         item_cache: ItemCache) -> None:
131    constraint = item["appl-config-option-constraint"]
132    count = len(constraint)
133    lines = []  # type: List[str]
134    _resolve_constraint_links(content, constraint, item_cache)
135    if count == 1:
136        if "min" in constraint:
137            _generate_min_max(lines, constraint["min"], "greater")
138        elif "max" in constraint:
139            _generate_min_max(lines, constraint["max"], "less")
140        elif "set" in constraint:
141            _generate_set(lines, constraint["set"])
142        elif "custom" in constraint:
143            if len(constraint["custom"]) == 1:
144                lines.extend(constraint["custom"][0].strip().split("\n"))
145            else:
146                _start_constraint_list(lines)
147                _generate_item_custom(lines, constraint)
148        else:
149            raise ValueError
150    elif count == 2 and "min" in constraint and "max" in constraint:
151        minimum = constraint["min"]
152        maximum = constraint["max"]
153        lines.append("The value of this configuration option shall be "
154                     f"greater than or equal to {minimum}")
155        lines.append(f"and less than or equal to {maximum}.")
156    else:
157        _start_constraint_list(lines)
158        _generate_item_min(lines, constraint)
159        _generate_item_max(lines, constraint)
160        _generate_item_custom(lines, constraint)
161    content.add_definition_item("VALUE CONSTRAINTS:", lines)
162
163
164def _generate_initializer_or_integer(content: SphinxContent, item: Item,
165                                     _option_type: str,
166                                     item_cache: ItemCache) -> None:
167    default_value = item["appl-config-option-default-value"]
168    if not isinstance(default_value, str) or " " not in default_value:
169        default_value = f"The default value is {default_value}."
170    content.add_definition_item("DEFAULT VALUE:", default_value)
171    _generate_constraint(content, item, item_cache)
172
173
174_OPTION_GENERATORS = {
175    "feature": _generate_feature,
176    "feature-enable": _generate_feature,
177    "initializer": _generate_initializer_or_integer,
178    "integer": _generate_initializer_or_integer
179}
180
181
182def _generate_notes(content: SphinxContent, notes: Optional[str]) -> None:
183    if not notes:
184        notes = "None."
185    content.add_definition_item("NOTES:", notes)
186
187
188def _generate_content(group: Item, options: ItemMap,
189                      item_cache: ItemCache) -> SphinxContent:
190    content = SphinxContent()
191    group.register_license_and_copyrights(content)
192    content.add_header(group["appl-config-group-name"], level="=")
193    content.add_blank_line()
194    content.add_lines(group["appl-config-group-description"])
195    for item in sorted(options.values(), key=lambda x: x.uid):
196        name = item["appl-config-option-name"]
197        item.register_license_and_copyrights(content)
198        content.add_index_entries([name] + item["appl-config-option-index"])
199        content.add_blank_line()
200        content.add_label(name)
201        content.add_blank_line()
202        content.add_header(name, level="-")
203        content.add_definition_item("CONSTANT:", f"``{name}``")
204        option_type = item["appl-config-option-type"]
205        content.add_definition_item("OPTION TYPE:", _OPTION_TYPES[option_type])
206        _OPTION_GENERATORS[option_type](content, item, option_type, item_cache)
207        content.add_definition_item("DESCRIPTION:",
208                                    item["appl-config-option-description"])
209        _generate_notes(content, item["appl-config-option-notes"])
210    content.add_licence_and_copyrights()
211    return content
212
213
214def generate(config: dict, item_cache: ItemCache) -> None:
215    """
216    Generates application configuration documentation sources according to the
217    configuration.
218
219    :param config: A dictionary with configuration entries.
220    :param item_cache: The specification item cache containing the application
221                       configuration groups and options.
222    """
223    groups = {}  # type: ItemMap
224    for item in item_cache.top_level.values():
225        _gather_groups(item, groups)
226
227    for group_config in config["groups"]:
228        group = groups[group_config["uid"]]
229        options = {}  # type: ItemMap
230        _gather_options(group, options)
231        content = _generate_content(group, options, item_cache)
232        content.write(group_config["target"])
Note: See TracBrowser for help on using the repository browser.