Coverage for src/debputy/plugins/debputy/manifest_root_rules.py: 82%
64 statements
« prev ^ index » next coverage.py v7.8.2, created at 2025-09-07 09:27 +0000
« prev ^ index » next coverage.py v7.8.2, created at 2025-09-07 09:27 +0000
1from typing import List, Any, Dict, Tuple, TYPE_CHECKING, cast
3from debputy._manifest_constants import (
4 ManifestVersion,
5 MK_MANIFEST_VERSION,
6 MK_INSTALLATIONS,
7 SUPPORTED_MANIFEST_VERSIONS,
8 MK_MANIFEST_DEFINITIONS,
9 MK_PACKAGES,
10 MK_MANIFEST_VARIABLES,
11 MK_MANIFEST_REMOVE_DURING_CLEAN,
12)
13from debputy.exceptions import DebputySubstitutionError
14from debputy.installations import InstallRule
15from debputy.manifest_parser.base_types import FileSystemMatchRule
16from debputy.manifest_parser.exceptions import ManifestParseException
17from debputy.manifest_parser.parser_data import ParserContextData
18from debputy.manifest_parser.tagging_types import DebputyParsedContent
19from debputy.manifest_parser.util import AttributePath
20from debputy.plugin.api.impl import DebputyPluginInitializerProvider
21from debputy.plugin.api.parser_tables import (
22 OPARSER_MANIFEST_ROOT,
23 OPARSER_MANIFEST_DEFINITIONS,
24 OPARSER_PACKAGES,
25)
26from debputy.plugin.api.spec import (
27 not_integrations,
28 INTEGRATION_MODE_DH_DEBPUTY_RRR,
29 INTEGRATION_MODE_FULL,
30 only_integrations,
31)
32from debputy.plugins.debputy.build_system_rules import register_build_system_rules
33from debputy.substitution import VariableNameState, SUBST_VAR_RE
35if TYPE_CHECKING:
36 from debputy.highlevel_manifest_parser import YAMLManifestParser
39def register_manifest_root_rules(api: DebputyPluginInitializerProvider) -> None:
40 # Registration order matters. Notably, definitions must come before anything that can
41 # use definitions (variables), which is why it is second only to the manifest version.
42 api.pluggable_manifest_rule(
43 OPARSER_MANIFEST_ROOT,
44 MK_MANIFEST_VERSION,
45 ManifestVersionFormat,
46 _handle_version,
47 source_format=ManifestVersion,
48 )
49 api.pluggable_object_parser(
50 OPARSER_MANIFEST_ROOT,
51 MK_MANIFEST_DEFINITIONS,
52 object_parser_key=OPARSER_MANIFEST_DEFINITIONS,
53 on_end_parse_step=lambda _a, _b, _c, mp: mp._ensure_package_states_is_initialized(),
54 )
55 api.pluggable_manifest_rule(
56 OPARSER_MANIFEST_DEFINITIONS,
57 MK_MANIFEST_VARIABLES,
58 ManifestVariablesParsedFormat,
59 _handle_manifest_variables,
60 source_format=Dict[str, str],
61 )
62 api.pluggable_manifest_rule(
63 OPARSER_MANIFEST_ROOT,
64 MK_INSTALLATIONS,
65 List[InstallRule],
66 _handle_installation_rules,
67 expected_debputy_integration_mode=not_integrations(
68 INTEGRATION_MODE_DH_DEBPUTY_RRR
69 ),
70 )
71 api.pluggable_manifest_rule(
72 OPARSER_MANIFEST_ROOT,
73 MK_MANIFEST_REMOVE_DURING_CLEAN,
74 List[RemoveDuringCleanParsedFormat],
75 _handle_remove_during_clean,
76 expected_debputy_integration_mode=only_integrations(
77 INTEGRATION_MODE_FULL,
78 ),
79 source_format=List[FileSystemMatchRule],
80 )
81 api.pluggable_object_parser(
82 OPARSER_MANIFEST_ROOT,
83 MK_PACKAGES,
84 object_parser_key=OPARSER_PACKAGES,
85 on_end_parse_step=lambda _a, _b, _c, mp: mp._ensure_package_states_is_initialized(),
86 nested_in_package_context=True,
87 )
88 register_build_system_rules(api)
91class ManifestVersionFormat(DebputyParsedContent):
92 manifest_version: ManifestVersion
95class ListOfInstallRulesFormat(DebputyParsedContent):
96 elements: List[InstallRule]
99class DictFormat(DebputyParsedContent):
100 mapping: Dict[str, Any]
103class ManifestVariablesParsedFormat(DebputyParsedContent):
104 variables: Dict[str, str]
107class RemoveDuringCleanParsedFormat(DebputyParsedContent):
108 pattern: FileSystemMatchRule
111def _handle_version(
112 _name: str,
113 parsed_data: ManifestVersionFormat,
114 _attribute_path: AttributePath,
115 _parser_context: ParserContextData,
116) -> str:
117 manifest_version = parsed_data["manifest_version"]
118 if manifest_version not in SUPPORTED_MANIFEST_VERSIONS: 118 ↛ 119line 118 didn't jump to line 119 because the condition on line 118 was never true
119 raise ManifestParseException(
120 "Unsupported manifest-version. This implementation supports the following versions:"
121 f' {", ".join(repr(v) for v in SUPPORTED_MANIFEST_VERSIONS)}"'
122 )
123 return manifest_version
126def _handle_manifest_variables(
127 _name: str,
128 parsed_data: ManifestVariablesParsedFormat,
129 variables_path: AttributePath,
130 parser_context: ParserContextData,
131) -> None:
132 variables = parsed_data.get("variables", {})
133 resolved_vars: Dict[str, Tuple[str, AttributePath]] = {}
134 manifest_parser: "YAMLManifestParser" = cast("YAMLManifestParser", parser_context)
135 substitution = manifest_parser.substitution
136 for key, value_raw in variables.items():
137 key_path = variables_path[key]
138 if not SUBST_VAR_RE.match("{{" + key + "}}"): 138 ↛ 139line 138 didn't jump to line 139 because the condition on line 138 was never true
139 raise ManifestParseException(
140 f"The variable at {key_path.path_key_lc} has an invalid name and therefore cannot"
141 " be used."
142 )
143 if substitution.variable_state(key) != VariableNameState.UNDEFINED:
144 raise ManifestParseException(
145 f'The variable "{key}" is already reserved/defined. Error triggered by'
146 f" {key_path.path_key_lc}."
147 )
148 try:
149 value = substitution.substitute(value_raw, key_path.path)
150 except DebputySubstitutionError:
151 if not resolved_vars:
152 raise
153 # See if flushing the variables work
154 substitution = manifest_parser.add_extra_substitution_variables(
155 **resolved_vars
156 )
157 resolved_vars = {}
158 value = substitution.substitute(value_raw, key_path.path)
159 resolved_vars[key] = (value, key_path)
160 substitution = manifest_parser.add_extra_substitution_variables(**resolved_vars)
163def _handle_installation_rules(
164 _name: str,
165 parsed_data: List[InstallRule],
166 _attribute_path: AttributePath,
167 _parser_context: ParserContextData,
168) -> List[InstallRule]:
169 return parsed_data
172def _handle_remove_during_clean(
173 _name: str,
174 parsed_data: List[RemoveDuringCleanParsedFormat],
175 _attribute_path: AttributePath,
176 _parser_context: ParserContextData,
177) -> List[FileSystemMatchRule]:
178 return [x["pattern"] for x in parsed_data]
181def _handle_opaque_dict(
182 _name: str,
183 parsed_data: DictFormat,
184 _attribute_path: AttributePath,
185 _parser_context: ParserContextData,
186) -> Dict[str, Any]:
187 return parsed_data["mapping"]