zephyr/doc/_scripts/gen_boards_catalog.py

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=[],
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.values():
# 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,
}