source: rtems-central/rtemsqual/applconfig.py @ fa46b668

Last change on this file since fa46b668 was fa46b668, checked in by Sebastian Huber <sebastian.huber@…>, on 05/06/20 at 09:40:24

Move license and copyright registration of items

This avoids a future cyclic dependency between the items and content
modules.

  • Property mode set to 100644
File size: 9.1 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,
71                      option_type: str) -> 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_set(lines: List[str], constraint: Dict[str, Any]) -> None:
108    if "set" in constraint:
109        value_set = constraint["set"]
110        lines.append("")
111        lines.append(f"* It shall be an element of {value_set}.")
112
113
114def _generate_item_custom(lines: List[str], constraint: Dict[str,
115                                                             Any]) -> None:
116    for custom in constraint.get("custom", []):
117        lines.append("")
118        custom = custom.replace("The value of this configuration option", "It")
119        custom = custom.strip().split("\n")
120        lines.append(f"* {custom[0]}")
121        lines.extend([f"  {x}" if x else "" for x in custom[1:]])
122
123
124def _resolve_constraint_links(content: SphinxContent, item: Item,
125                              constraint: Dict[str, Any]) -> None:
126    if "links" in constraint:
127        if "custom" not in constraint:
128            constraint["custom"] = []
129        for link in reversed(constraint["links"]):
130            other = item.map(link)
131            content.register_license_and_copyrights_of_item(other)
132            constraint["custom"].append(other["text"])
133
134
135def _generate_constraint(content: SphinxContent, item: Item) -> None:
136    constraint = item["appl-config-option-constraint"]
137    count = len(constraint)
138    lines = []  # type: List[str]
139    _resolve_constraint_links(content, item, constraint)
140    if count == 1:
141        if "min" in constraint:
142            _generate_min_max(lines, constraint["min"], "greater")
143        elif "max" in constraint:
144            _generate_min_max(lines, constraint["max"], "less")
145        elif "set" in constraint:
146            _generate_set(lines, constraint["set"])
147        elif "custom" in constraint:
148            if len(constraint["custom"]) == 1:
149                lines.extend(constraint["custom"][0].strip().split("\n"))
150            else:
151                _start_constraint_list(lines)
152                _generate_item_custom(lines, constraint)
153    elif count == 2 and "min" in constraint and "max" in constraint:
154        minimum = constraint["min"]
155        maximum = constraint["max"]
156        lines.append("The value of this configuration option shall be "
157                     f"greater than or equal to {minimum}")
158        lines.append(f"and less than or equal to {maximum}.")
159    else:
160        _start_constraint_list(lines)
161        _generate_item_min(lines, constraint)
162        _generate_item_max(lines, constraint)
163        _generate_item_set(lines, constraint)
164        _generate_item_custom(lines, constraint)
165    content.add_definition_item("VALUE CONSTRAINTS:", lines)
166
167
168def _generate_initializer_or_integer(content: SphinxContent, item: Item,
169                                     _option_type: str) -> None:
170    default_value = item["appl-config-option-default-value"]
171    if not isinstance(default_value, str) or " " not in default_value:
172        default_value = f"The default value is {default_value}."
173    content.add_definition_item("DEFAULT VALUE:", default_value)
174    _generate_constraint(content, item)
175
176
177_OPTION_GENERATORS = {
178    "feature": _generate_feature,
179    "feature-enable": _generate_feature,
180    "initializer": _generate_initializer_or_integer,
181    "integer": _generate_initializer_or_integer
182}
183
184
185def _generate_notes(content: SphinxContent, notes: Optional[str]) -> None:
186    if not notes:
187        notes = "None."
188    content.add_definition_item("NOTES:", notes)
189
190
191def _generate_file(group: Item, options: ItemMap, target: str) -> None:
192    content = SphinxContent()
193    content.register_license_and_copyrights_of_item(group)
194    content.add_header(group["appl-config-group-name"], level="=")
195    content.add(group["appl-config-group-description"])
196    for item in sorted(options.values(), key=lambda x: x.uid):
197        name = item["appl-config-option-name"]
198        content.register_license_and_copyrights_of_item(item)
199        content.add_index_entries([name] + item["appl-config-option-index"])
200        content.add_label(name)
201        content.add_header(name, level="-")
202        content.add_definition_item("CONSTANT:", f"``{name}``")
203        option_type = item["appl-config-option-type"]
204        content.add_definition_item("OPTION TYPE:", _OPTION_TYPES[option_type])
205        _OPTION_GENERATORS[option_type](content, item, option_type)
206        content.add_definition_item("DESCRIPTION:",
207                                    item["appl-config-option-description"])
208        _generate_notes(content, item["appl-config-option-notes"])
209    content.add_licence_and_copyrights()
210    content.write(target)
211
212
213def generate(config: dict, item_cache: ItemCache) -> None:
214    """
215    Generates application configuration documentation sources according to the
216    configuration.
217
218    :param config: A dictionary with configuration entries.
219    :param item_cache: The specification item cache containing the application
220                       configuration groups and options.
221    """
222    groups = {}  # type: ItemMap
223    for item in item_cache.top_level.values():
224        _gather_groups(item, groups)
225
226    for group_config in config["groups"]:
227        group = groups[group_config["uid"]]
228        options = {}  # type: ItemMap
229        _gather_options(group, options)
230        _generate_file(group, options, group_config["target"])
Note: See TracBrowser for help on using the repository browser.