Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build system: add list of features for documentation and sanity checking #20366

Merged
merged 5 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ all: welcome
@exit 1

doc:
@./dist/tools/features_yaml2mx/features_yaml2mx.py \
features.yaml \
--output-md doc/doxygen/src/feature_list.md
"$(MAKE)" -BC doc/doxygen

doc-man:
Expand All @@ -33,6 +36,11 @@ distclean: docclean pkg-clean
print-versions:
@./dist/tools/ci/print_toolchain_versions.sh

generate-features:
@./dist/tools/features_yaml2mx/features_yaml2mx.py \
features.yaml \
--output-makefile makefiles/features_existing.inc.mk

include makefiles/boards.inc.mk
include makefiles/app_dirs.inc.mk

Expand All @@ -53,7 +61,7 @@ welcome:
@echo " https://forum.riot-os.org"
@echo ""
@echo "Available targets for the RIOT base directory include:"
@echo " generate-{board,driver,example,module,pkg,test}"
@echo " generate-{board,driver,example,module,pkg,test,features}"
@echo " info-{applications,boards,emulated-boards} info-applications-supported-boards"
@echo " print-versions"
@echo " clean distclean pkg-clean"
Expand Down
1 change: 0 additions & 1 deletion boards/esp32-olimex-evb/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ config BOARD_ESP32_OLIMEX_EVB
select HAS_PERIPH_SDMMC
select HAS_PERIPH_SPI
select HAS_PERIPH_CAN
select HAS_PERIPH_IR

select HAVE_MTD_SDMMC_DEFAULT

Expand Down
1 change: 0 additions & 1 deletion boards/esp32-olimex-evb/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,5 @@ FEATURES_CONFLICT_MSG += "SD/MMC and SPI cannot be used at the same time on this
# unique features of the board
FEATURES_PROVIDED += esp_eth # Ethernet MAC (EMAC)
FEATURES_PROVIDED += periph_can # CAN peripheral interface
FEATURES_PROVIDED += periph_ir # IR peripheral interface

FEATURES_PROVIDED += arduino_pins
11 changes: 11 additions & 0 deletions dist/tools/ci/check_features_existing_inc_mk_is_up_to_date.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/sh
# This tools checks if the makefiles/features_existing.inc.mk is up to date
hash_feature_list_pre="$(sha256sum "$(dirname "$0")/../../../makefiles/features_existing.inc.mk")"
make --silent -C "$(dirname "$0")"/../../.. generate-features || exit 1
hash_feature_list_post="$(sha256sum "$(dirname "$0")/../../../makefiles/features_existing.inc.mk")"
if [ "$hash_feature_list_pre" != "$hash_feature_list_post" ]; then
echo "Forgot to run make generate-features after updating features.yaml!"
exit 1
fi

exit 0
1 change: 1 addition & 0 deletions dist/tools/ci/static_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
# directory for more details.
#

. "$(dirname "${0}")"/github_annotate.sh

Check warning on line 13 in dist/tools/ci/static_tests.sh

View workflow job for this annotation

GitHub Actions / static-tests

Not following: ./github_annotate.sh was not specified as input (see shellcheck -x). [SC1091]

declare -A DEPS

Expand Down Expand Up @@ -114,6 +114,7 @@
run ./dist/tools/whitespacecheck/check.sh "${BASE_BRANCH}"
DIFFFILTER="MR" ERROR_EXIT_CODE=0 run ./dist/tools/licenses/check.sh
DIFFFILTER="AC" run ./dist/tools/licenses/check.sh
run ./dist/tools/ci/check_features_existing_inc_mk_is_up_to_date.sh
run ./dist/tools/doccheck/check.sh
run ./dist/tools/externc/check.sh
# broken configuration produces many false positives
Expand Down
12 changes: 12 additions & 0 deletions dist/tools/features_yaml2mx/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Tool to export features described in a YAML to formats usable by our build system
=================================================================================

The python script in this folder converts features specified in a YAML file to
a Makefile for use to check provided and requested features against, as well
as a markdown file for consumption by Doxygen to document the features.

The YAML file containing the features is `features.yaml` in the root of the
repo. Its syntax is documented in a comment on top of said file.

This script should be invoked by running `make generate-features` in the root
of the repository.
161 changes: 161 additions & 0 deletions dist/tools/features_yaml2mx/features_yaml2mx.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
#!/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)
16 changes: 16 additions & 0 deletions dist/tools/features_yaml2mx/schema.cddl
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
root = group-toplevel

group-toplevel = group .within { "groups" => any }
group-nested = group .within { "title" => tstr, any => any }

group = {
? "title" => tstr,
? "help" => tstr,
? "features" => [ + feature ],
? "groups" => [ + group-nested ],
}

feature = {
"name" => tstr,
? "help" => tstr,
}
1 change: 1 addition & 0 deletions doc/doxygen/riot.doxyfile
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,7 @@ INPUT = ../../doc.txt \
src/build-in-docker.md \
../../tests/README.md \
src/build-system-basics.md \
src/feature_list.md \
src/kconfig/kconfig.md \
src/using-cpp.md \
src/using-rust.md \
Expand Down
1 change: 1 addition & 0 deletions doc/doxygen/src/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/feature_list.md
Loading
Loading