zephyr/doc/_scripts/gen_boards_catalog.py
Benjamin Cabé c9b71045f8 doc: extensions: boards: Better handle unknown/other vendors
Boards under a folder that doesn't directly match a vendor prefix
incorrectly end up being categorized as "zephyr" since that's the only
prefix that is eventually found when navigating up the folder hierarchy.

This commits treats boards in the "others" and "native" folders as
special cases and associates them to an "Unknown/Other" category.

Signed-off-by: Benjamin Cabé <benjamin@zephyrproject.org>
2024-10-23 16:50:30 +02:00

130 lines
4.2 KiB
Python

# Copyright (c) 2024 The Linux Foundation
# SPDX-License-Identifier: Apache-2.0
import logging
from collections import namedtuple
from pathlib import Path
import list_boards, list_hardware
import yaml
import zephyr_module
from gen_devicetree_rest import VndLookup
ZEPHYR_BASE = Path(__file__).parents[2]
logger = logging.getLogger(__name__)
def guess_file_from_patterns(directory, patterns, name, extensions):
for pattern in patterns:
for ext in extensions:
matching_file = next(directory.glob(pattern.format(name=name, ext=ext)), None)
if matching_file:
return matching_file
return None
def guess_image(board_or_shield):
img_exts = ["jpg", "jpeg", "webp", "png"]
patterns = [
"**/{name}.{ext}",
"**/*{name}*.{ext}",
"**/*.{ext}",
]
img_file = guess_file_from_patterns(
board_or_shield.dir, patterns, board_or_shield.name, img_exts
)
return (img_file.relative_to(ZEPHYR_BASE)).as_posix() if img_file else None
def guess_doc_page(board_or_shield):
patterns = [
"doc/index.{ext}",
"**/{name}.{ext}",
"**/*{name}*.{ext}",
"**/*.{ext}",
]
doc_file = guess_file_from_patterns(
board_or_shield.dir, patterns, board_or_shield.name, ["rst"]
)
return doc_file
def get_catalog():
vnd_lookup = VndLookup(ZEPHYR_BASE / "dts/bindings/vendor-prefixes.txt", [])
module_settings = {
"arch_root": [ZEPHYR_BASE],
"board_root": [ZEPHYR_BASE],
"soc_root": [ZEPHYR_BASE],
}
for module in zephyr_module.parse_modules(ZEPHYR_BASE):
for key in module_settings:
root = module.meta.get("build", {}).get("settings", {}).get(key)
if root is not None:
module_settings[key].append(Path(module.project) / root)
Args = namedtuple("args", ["arch_roots", "board_roots", "soc_roots", "board_dir", "board"])
args_find_boards = Args(
arch_roots=module_settings["arch_root"],
board_roots=module_settings["board_root"],
soc_roots=module_settings["soc_root"],
board_dir=ZEPHYR_BASE / "boards",
board=None,
)
boards = list_boards.find_v2_boards(args_find_boards)
systems = list_hardware.find_v2_systems(args_find_boards)
board_catalog = {}
for board in boards:
# We could use board.vendor but it is often incorrect. Instead, deduce vendor from
# containing folder. There are a few exceptions, like the "native" and "others" folders
# which we know are not actual vendors so treat them as such.
for folder in board.dir.parents:
if folder.name in ["native", "others"]:
vendor = "others"
break
elif vnd_lookup.vnd2vendor.get(folder.name):
vendor = folder.name
break
# Grab all the twister files for this board and use them to figure out all the archs it
# supports.
archs = set()
pattern = f"{board.name}*.yaml"
for twister_file in board.dir.glob(pattern):
try:
with open(twister_file, "r") as f:
board_data = yaml.safe_load(f)
archs.add(board_data.get("arch"))
except Exception as e:
logger.error(f"Error parsing twister file {twister_file}: {e}")
socs = {soc.name for soc in board.socs}
full_name = board.full_name or board.name
doc_page = guess_doc_page(board)
board_catalog[board.name] = {
"name": board.name,
"full_name": full_name,
"doc_page": doc_page.relative_to(ZEPHYR_BASE).as_posix() if doc_page else None,
"vendor": vendor,
"archs": list(archs),
"socs": list(socs),
"image": guess_image(board),
}
socs_hierarchy = {}
for soc in systems.get_socs():
family = soc.family or "<no family>"
series = soc.series or "<no series>"
socs_hierarchy.setdefault(family, {}).setdefault(series, []).append(soc.name)
return {
"boards": board_catalog,
"vendors": {**vnd_lookup.vnd2vendor, "others": "Other/Unknown"},
"socs": socs_hierarchy,
}