Coverage for apio/utils/resource_util.py: 82%
32 statements
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-23 03:53 +0000
« prev ^ index » next coverage.py v7.16.1, created at 2026-09-23 03:53 +0000
1"""Utilities related to the Apio resource files."""
3from dataclasses import dataclass
4from jsonschema import validate
5from jsonschema.exceptions import ValidationError
6from apio.common.apio_console import fatal_error
7from apio.common import proto_util
8from apio.managers.apio_definitions import ApioDefinitions
9from apio.common.proto.apio_definitions_pb2 import (
10 BoardDefinition,
11 FpgaDefinition,
12 ProgrammerDefinition,
13)
16@dataclass(frozen=True)
17class ProjectResources:
18 """Contains the resources of the current project."""
20 board_id: str
21 board_definition: BoardDefinition
22 fpga_id: str
23 fpga_definition: FpgaDefinition
24 programmer_id: str
25 programmer_definition: ProgrammerDefinition
28# -- JSON schema for validating config.jsonc.
29CONFIG_SCHEMA = {
30 "type": "object",
31 "required": [
32 "remote-config-ttl-days",
33 "remote-config-retry-minutes",
34 "remote-config-url",
35 ],
36 "properties": {
37 "remote-config-ttl-days": {"type": "integer", "minimum": 1},
38 "remote-config-retry-minutes": {"type": "integer", "minimum": 0},
39 "remote-config-url": {"type": "string"},
40 },
41 "additionalProperties": False,
42}
45# -- JSON schema for validating packages.jsonc.
46PACKAGES_SCHEMA = {
47 "type": "object",
48 "patternProperties": {
49 "^[a-z0-9_-]+$": { # package names like "oss-cad-suite"
50 "type": "object",
51 "required": ["description", "env"],
52 "properties": {
53 "description": {"type": "string"},
54 "restricted-to-platforms": {
55 "type": "array",
56 "items": {"type": "string"},
57 },
58 "env": {
59 "type": "object",
60 "properties": {
61 "add-to-path": {
62 "type": "array",
63 "items": {"type": "string"},
64 },
65 "delete-env-vars": {
66 "type": "array",
67 "items": {"type": "string"},
68 },
69 "add-env-vars": {
70 "type": "object",
71 "additionalProperties": {"type": "string"},
72 },
73 "define-consts": {
74 "type": "object",
75 "additionalProperties": {"type": "string"},
76 },
77 },
78 "additionalProperties": False,
79 },
80 },
81 "additionalProperties": False,
82 }
83 },
84 "additionalProperties": False,
85}
88def validate_config(config: dict) -> None:
89 """Check the config resource from config.jsonc."""
90 try:
91 validate(instance=config, schema=CONFIG_SCHEMA)
92 except ValidationError as e:
93 fatal_error("Invalid config.", cause=e)
96def validate_packages(packages: dict) -> None:
97 """Check the packages resource from packages.jsonc."""
98 try:
99 validate(instance=packages, schema=PACKAGES_SCHEMA)
100 except ValidationError as e:
101 fatal_error("Invalid packages resource.", cause=e)
104def collect_project_resources(
105 board_id: str,
106 definitions: ApioDefinitions,
107) -> ProjectResources:
108 """Collect and validate the resources used by a project. Since the
109 resources may be custom resources defined by the user, we need to
110 have a user friendly error handling and reporting."""
112 # -- Get the board definition.
113 board_definition = definitions.boards.get(board_id, None)
114 if board_definition is None: 114 ↛ 115line 114 didn't jump to line 115 because the condition on line 114 was never true
115 fatal_error(f"Unknown board id '{board_id}'.")
117 # -- We assume below that these fields are required.
118 proto_util.check_is_required(board_definition, "fpga_id", "programmer.id")
120 # -- Get fpga id and definition.
121 fpga_id = board_definition.fpga_id
122 fpga_definition = definitions.fpgas[fpga_id]
124 # -- Get programmer id and info.
125 programmer_id = board_definition.programmer.id
126 programmer_definition = definitions.programmers[programmer_id]
128 # -- Create the project resources bundle.
129 project_resources = ProjectResources(
130 board_id,
131 board_definition,
132 fpga_id,
133 fpga_definition,
134 programmer_id,
135 programmer_definition,
136 )
138 # -- All done
139 return project_resources