mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
ce5bae3edb
Add a python script that allows having a single YAML file as source of truth for what features are available, and also add documentation such as help texts and grouping to them. This utility converts such a YAML file to a Makefile with the contents ``` FEATURES_EXISTING := \ feature_a \ feature_b \ ... \ features_z \ # ``` This allows the Makefile based build system to easily check if all provided features and all requested features do actually exist. In addition, this also converts the YAML file to a markdown file that documents the features. This file is then intended to be used by Doxygen to document the provided features. Co-authored-by: mguetschow <mikolai.guetschow@tu-dresden.de> Co-authored-by: chrysn <chrysn@fsfe.org>
162 lines
5.4 KiB
Python
Executable File
162 lines
5.4 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Command line utility generate trivial Makefile listing all existing features in
|
|
RIOT and a matching documentation in Markdown format from single YAML file.
|
|
"""
|
|
import argparse
|
|
import yaml
|
|
|
|
|
|
def collect_features(parsed):
|
|
"""
|
|
Collect all features from a parsed YAML file
|
|
|
|
:param parsed: Parsed YAML file
|
|
:type parsed: dict
|
|
:return: list of features in no particular, possible unstable, order
|
|
:rtype: list
|
|
"""
|
|
result = []
|
|
for group in parsed.get("groups", []):
|
|
result += collect_features(group)
|
|
for feature in parsed.get("features", []):
|
|
result.append(feature["name"])
|
|
return result
|
|
|
|
|
|
def write_makefile(outfile, yaml_path, parsed):
|
|
"""
|
|
Extract the list of features from the given parsed YAML file and writes
|
|
them into file at the given path in Makefile syntax, e.g.
|
|
|
|
FEATURES_EXISTING := \
|
|
feat_a \
|
|
feat_b \
|
|
feat_c \
|
|
#
|
|
|
|
:param outfile: path to the Makefile to write the features to
|
|
:type outfile: str
|
|
:param yaml_path: Path to the source YAML file
|
|
:type yaml_path: str
|
|
:param parsed: the parsed YAML file
|
|
:type parsed: dict
|
|
"""
|
|
outfile.write(f"""\
|
|
# WARNING: This has been auto-generated from {yaml_path}.
|
|
# Do not edit this by hand, but update {yaml_path} instead.
|
|
# Finally, run `make generate-features` in the root of the RIOT repo.
|
|
""")
|
|
outfile.write("FEATURES_EXISTING := \\\n")
|
|
for feature in sorted(collect_features(parsed)):
|
|
outfile.write(f" {feature} \\\n")
|
|
outfile.write(" #\n")
|
|
outfile.flush()
|
|
|
|
|
|
def write_md_section(outfile, group, level):
|
|
"""
|
|
Write a section documenting certain features to the given file in markdown
|
|
format.
|
|
|
|
:param outfile: The file to write the section to
|
|
:type outfile: file
|
|
:param group: The group content (e.g. a subtree from the parsed YAML)
|
|
:type group: dict
|
|
:param level: The current section level (e.g. 1=section, 2=subsection)
|
|
:type level: int
|
|
"""
|
|
title = group.get("title")
|
|
outfile.write("#" * level + f" {title}" if title else "" + "\n")
|
|
if "help" in group:
|
|
outfile.write("\n")
|
|
outfile.write(group["help"])
|
|
outfile.write("\n")
|
|
|
|
if "features" in group:
|
|
outfile.write("\n")
|
|
outfile.write("""\
|
|
| Feature | Description |
|
|
|:--------------------------------- |:----------------------------------------------------------------------------- |
|
|
""")
|
|
|
|
for feature in group["features"]:
|
|
name = f"`{feature['name']}`"
|
|
description = feature['help'].strip().replace("\n", " ")
|
|
outfile.write(f"| {name:<33} | {description:<77} |\n")
|
|
|
|
for group in group.get('groups', []):
|
|
outfile.write("\n")
|
|
write_md_section(outfile, group, level + 1)
|
|
|
|
|
|
def write_mdfile(outfile, yaml_path, parsed):
|
|
"""
|
|
Write the given contents from the parsed YAML file as markdown
|
|
documentation to the given file
|
|
|
|
:param outfile: The file to write the documentation to
|
|
:type outfile: file
|
|
:param yaml_path: Path to the source YAML file
|
|
:type yaml_path: str
|
|
:param parsed: The parsed YAML file contents
|
|
:type parsed: dict
|
|
"""
|
|
outfile.write(f"""\
|
|
# List of Features (Features as Build System Enties)
|
|
<!--
|
|
WARNING: This has been auto-generated from {yaml_path}.
|
|
Do not edit this by hand, but update {yaml_path} instead.
|
|
Finally, run `make generate-features` in the root of the RIOT repo.
|
|
-->
|
|
|
|
[TOC]
|
|
|
|
""")
|
|
write_md_section(outfile, parsed, 0)
|
|
|
|
|
|
def convert_features(yaml_file, mk_file, md_file):
|
|
"""
|
|
Convert the YAML file identified by the given path to a Makefile and
|
|
to a markdown file, if their paths are given.
|
|
|
|
:param yaml_file: Path to the YAML file to read
|
|
:type yaml_file: str
|
|
:param mk_file: Path to the Makefile to write the features to or None
|
|
for not writing the Makefile
|
|
:type mk_file: str or None
|
|
:param md_file: Path to the markdown file to write the doc to or None
|
|
for not writing the doc
|
|
:type md_file: str or None
|
|
"""
|
|
with open(yaml_file, 'rb') as file:
|
|
parsed = yaml.safe_load(file)
|
|
|
|
if mk_file is not None:
|
|
with open(mk_file, 'w', encoding="utf-8") as file:
|
|
write_makefile(file, yaml_file, parsed)
|
|
|
|
if md_file is not None:
|
|
with open(md_file, 'w', encoding="utf-8") as file:
|
|
write_mdfile(file, yaml_file, parsed)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
parser = argparse.ArgumentParser(
|
|
description='Generate documentation for features in markdown ' +
|
|
'format and a Makefile listing existing features'
|
|
)
|
|
parser.add_argument('INPUT', type=str, default=None,
|
|
help="Input file in YAML format")
|
|
parser.add_argument('--output-md', type=str, default=None,
|
|
help="Output file to write the markdown " +
|
|
"documentation to (default: no documentation")
|
|
parser.add_argument('--output-makefile', type=str, default=None,
|
|
help="Output file to write the makefile to " +
|
|
"(default: no makefile generated)")
|
|
|
|
args = parser.parse_args()
|
|
|
|
convert_features(args.INPUT, args.output_makefile, args.output_md)
|