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

1"""Utilities related to the Apio resource files.""" 

2 

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) 

14 

15 

16@dataclass(frozen=True) 

17class ProjectResources: 

18 """Contains the resources of the current project.""" 

19 

20 board_id: str 

21 board_definition: BoardDefinition 

22 fpga_id: str 

23 fpga_definition: FpgaDefinition 

24 programmer_id: str 

25 programmer_definition: ProgrammerDefinition 

26 

27 

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} 

43 

44 

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} 

86 

87 

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) 

94 

95 

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) 

102 

103 

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.""" 

111 

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}'.") 

116 

117 # -- We assume below that these fields are required. 

118 proto_util.check_is_required(board_definition, "fpga_id", "programmer.id") 

119 

120 # -- Get fpga id and definition. 

121 fpga_id = board_definition.fpga_id 

122 fpga_definition = definitions.fpgas[fpga_id] 

123 

124 # -- Get programmer id and info. 

125 programmer_id = board_definition.programmer.id 

126 programmer_definition = definitions.programmers[programmer_id] 

127 

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 ) 

137 

138 # -- All done 

139 return project_resources