Browse Source
Assists on converting boards from hwmv1 to hwmv2. Signed-off-by: Gerard Marull-Paretas <gerard@teslabs.com>pull/69687/head
2 changed files with 205 additions and 0 deletions
@ -0,0 +1,204 @@ |
|||||||
|
#!/usr/bin/env python |
||||||
|
""" |
||||||
|
Utility script to assist in the migration of a board from hardware model v1 |
||||||
|
(HWMv1) to hardware model v2 (HWMv2). |
||||||
|
|
||||||
|
.. warning:: |
||||||
|
This script is not a complete migration tool. It is meant to assist in the |
||||||
|
migration process, but it does not handle all cases. |
||||||
|
|
||||||
|
This script requires the following arguments: |
||||||
|
|
||||||
|
- ``-b|--board``: The name of the board to migrate. |
||||||
|
- ``-g|--group``: The group the board belongs to. This is used to group a set of |
||||||
|
boards in the same folder. In HWMv2, the boards are no longer organized by |
||||||
|
architecture. |
||||||
|
- ``-v|--vendor``: The vendor name. |
||||||
|
- ``-s|--soc``: The SoC name. |
||||||
|
|
||||||
|
In some cases, the new board name will differ from the old board name. For |
||||||
|
example, the old board name may have the SoC name as a suffix, while in HWMv2, |
||||||
|
this is no longer needed. In such cases, ``-n|--new-board`` needs to be |
||||||
|
provided. |
||||||
|
|
||||||
|
For boards with variants, ``--variants`` needs to be provided. |
||||||
|
|
||||||
|
For out-of-tree boards, provide ``--board-root`` pointing to the custom board |
||||||
|
root. |
||||||
|
|
||||||
|
Copyright (c) 2023 Nordic Semiconductor ASA |
||||||
|
SPDX-License-Identifier: Apache-2.0 |
||||||
|
""" |
||||||
|
|
||||||
|
import argparse |
||||||
|
from pathlib import Path |
||||||
|
import re |
||||||
|
import sys |
||||||
|
|
||||||
|
import ruamel.yaml |
||||||
|
|
||||||
|
|
||||||
|
ZEPHYR_BASE = Path(__file__).parents[2] |
||||||
|
|
||||||
|
|
||||||
|
def board_v1_to_v2(board_root, board, new_board, group, vendor, soc, variants): |
||||||
|
try: |
||||||
|
board_path = next(board_root.glob(f"boards/*/{board}")) |
||||||
|
except StopIteration: |
||||||
|
sys.exit(f"Board not found: {board}") |
||||||
|
|
||||||
|
new_board_path = board_root / "boards" / "v2" / group / new_board |
||||||
|
if new_board_path.exists(): |
||||||
|
print("New board already exists, updating board with additional SoC") |
||||||
|
if not soc: |
||||||
|
sys.exit("No SoC provided") |
||||||
|
|
||||||
|
new_board_path.mkdir(parents=True, exist_ok=True) |
||||||
|
|
||||||
|
print("Moving files to the new board folder...") |
||||||
|
for f in board_path.iterdir(): |
||||||
|
f_new = new_board_path / f.name |
||||||
|
if f_new.exists(): |
||||||
|
print(f"Skipping existing file: {f_new}") |
||||||
|
continue |
||||||
|
f.rename(f_new) |
||||||
|
|
||||||
|
print("Creating or updating board.yaml...") |
||||||
|
board_settings_file = new_board_path / "board.yml" |
||||||
|
if not board_settings_file.exists(): |
||||||
|
board_settings = { |
||||||
|
"board": { |
||||||
|
"name": new_board, |
||||||
|
"vendor": vendor, |
||||||
|
"socs": [] |
||||||
|
} |
||||||
|
} |
||||||
|
else: |
||||||
|
with open(board_settings_file) as f: |
||||||
|
board_settings = ruamel.yaml.safe_load(f) # pylint: disable=assignment-from-no-return |
||||||
|
|
||||||
|
soc = {"name": soc} |
||||||
|
if variants: |
||||||
|
soc["variants"] = [{"name": variant} for variant in variants] |
||||||
|
|
||||||
|
board_settings["board"]["socs"].append(soc) |
||||||
|
|
||||||
|
yaml = ruamel.yaml.YAML() |
||||||
|
yaml.indent(sequence=4, offset=2) |
||||||
|
with open(board_settings_file, "w") as f: |
||||||
|
yaml.dump(board_settings, f) |
||||||
|
|
||||||
|
print(f"Updating {board}_defconfig...") |
||||||
|
board_defconfig_file = new_board_path / f"{board}_defconfig" |
||||||
|
with open(board_defconfig_file) as f: |
||||||
|
board_soc_settings = [] |
||||||
|
board_defconfig = "" |
||||||
|
|
||||||
|
dropped_line = False |
||||||
|
for line in f.readlines(): |
||||||
|
m = re.match(r"^CONFIG_BOARD_.*$", line) |
||||||
|
if m: |
||||||
|
dropped_line = True |
||||||
|
continue |
||||||
|
|
||||||
|
m = re.match(r"^CONFIG_(SOC_[A-Z0-9_]+).*$", line) |
||||||
|
if m: |
||||||
|
board_soc_settings.append(m.group(1)) |
||||||
|
dropped_line = True |
||||||
|
continue |
||||||
|
|
||||||
|
if dropped_line and re.match(r"^$", line): |
||||||
|
continue |
||||||
|
|
||||||
|
dropped_line = False |
||||||
|
board_defconfig += line |
||||||
|
|
||||||
|
with open(board_defconfig_file, "w") as f: |
||||||
|
f.write(board_defconfig) |
||||||
|
|
||||||
|
print("Updating Kconfig.defconfig...") |
||||||
|
board_kconfig_defconfig_file = new_board_path / "Kconfig.defconfig" |
||||||
|
with open(board_kconfig_defconfig_file) as f: |
||||||
|
board_kconfig_defconfig = "" |
||||||
|
has_kconfig_defconfig_entries = False |
||||||
|
|
||||||
|
in_board = False |
||||||
|
for line in f.readlines(): |
||||||
|
# drop "config BOARD" entry from Kconfig.defconfig |
||||||
|
m = re.match(r"^config BOARD$", line) |
||||||
|
if m: |
||||||
|
in_board = True |
||||||
|
continue |
||||||
|
|
||||||
|
if in_board and re.match(r"^\s+.*$", line): |
||||||
|
continue |
||||||
|
|
||||||
|
in_board = False |
||||||
|
|
||||||
|
m = re.match(r"^config .*$", line) |
||||||
|
if m: |
||||||
|
has_kconfig_defconfig_entries = True |
||||||
|
|
||||||
|
m = re.match(rf"^(.*)BOARD_{board.upper()}(.*)$", line) |
||||||
|
if m: |
||||||
|
board_kconfig_defconfig += ( |
||||||
|
m.group(1) + "BOARD_" + new_board.upper() + m.group(2) + "\n" |
||||||
|
) |
||||||
|
continue |
||||||
|
|
||||||
|
board_kconfig_defconfig += line |
||||||
|
|
||||||
|
if has_kconfig_defconfig_entries: |
||||||
|
with open(board_kconfig_defconfig_file, "w") as f: |
||||||
|
f.write(board_kconfig_defconfig) |
||||||
|
else: |
||||||
|
print("Removing empty Kconfig.defconfig after update...") |
||||||
|
board_kconfig_defconfig_file.unlink() |
||||||
|
|
||||||
|
print(f"Creating or updating Kconfig.{new_board}...") |
||||||
|
new_board_kconfig_file = new_board_path / f"Kconfig.{new_board}" |
||||||
|
selects = "\n\t" + "\n\t".join(["select " + setting for setting in board_soc_settings]) |
||||||
|
if not new_board_kconfig_file.exists(): |
||||||
|
with open(new_board_kconfig_file, "w") as f: |
||||||
|
f.write( |
||||||
|
f"config BOARD_{new_board.upper()}{selects}" |
||||||
|
) |
||||||
|
else: |
||||||
|
with open(new_board_kconfig_file, "a") as f: |
||||||
|
f.write(selects) |
||||||
|
|
||||||
|
print("Removing old Kconfig.board...") |
||||||
|
board_kconfig_file = new_board_path / "Kconfig.board" |
||||||
|
board_kconfig_file.unlink() |
||||||
|
|
||||||
|
print("Conversion done!") |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
parser = argparse.ArgumentParser(allow_abbrev=False) |
||||||
|
|
||||||
|
parser.add_argument( |
||||||
|
"--board-root", |
||||||
|
type=Path, |
||||||
|
default=ZEPHYR_BASE, |
||||||
|
help="Board root", |
||||||
|
) |
||||||
|
|
||||||
|
parser.add_argument("-b", "--board", type=str, required=True, help="Board name") |
||||||
|
parser.add_argument("-n", "--new-board", type=str, help="New board name") |
||||||
|
parser.add_argument("-g", "--group", type=str, required=True, help="Board group") |
||||||
|
parser.add_argument("-v", "--vendor", type=str, required=True, help="Vendor name") |
||||||
|
parser.add_argument("-s", "--soc", type=str, required=True, help="Board SoC") |
||||||
|
parser.add_argument("--variants", nargs="+", default=[], help="Board variants") |
||||||
|
|
||||||
|
args = parser.parse_args() |
||||||
|
|
||||||
|
board_v1_to_v2( |
||||||
|
args.board_root, |
||||||
|
args.board, |
||||||
|
args.new_board or args.board, |
||||||
|
args.group, |
||||||
|
args.vendor, |
||||||
|
args.soc, |
||||||
|
args.variants, |
||||||
|
) |
Loading…
Reference in new issue