|
12 | 12 | ) |
13 | 13 |
|
14 | 14 |
|
| 15 | +# PyYaml by default dumps unquoted strings if they look unambiguous, and quoted strings otherwise. |
| 16 | +# Unquoted strings, for some reason, cause issues when they are used as projections in spack manifests. |
| 17 | +# PyYaml dumps '{name}/prX-Y' as a quoted str as it has '{' at the front and causes ambiguity (good for projections) |
| 18 | +# But 'ROOT_SPEC/prX-Y/VERSION-{hash:7}' is dumped as an unquoted str as it is unambiguous (bad for projections) |
| 19 | +# So we need to wrap projections in a custom class that forces PyYaml to dump them as quoted strings. |
| 20 | +class YamlExplicitQuotedString(str): |
| 21 | + pass |
| 22 | + |
| 23 | + |
| 24 | +def yaml_explicit_quoted_string_representer(dumper, data): |
| 25 | + """ |
| 26 | + Custom representer for YAML to ensure that some strings are quoted explicitly. |
| 27 | + This is necessary for strings that are used as projections in spack manifests. |
| 28 | + """ |
| 29 | + return dumper.represent_scalar("tag:yaml.org,2002:str", data, style="'") |
| 30 | + |
| 31 | + |
| 32 | +yaml.add_representer(YamlExplicitQuotedString, yaml_explicit_quoted_string_representer) |
| 33 | + |
| 34 | +### Actual methods begin here ### |
| 35 | + |
| 36 | + |
15 | 37 | def inject_prerelease_information( |
16 | 38 | manifest_path: str, |
17 | 39 | version: str, |
@@ -79,7 +101,8 @@ def add_namespace_to_other_projection_versions( |
79 | 101 | f"Updating projection '{projection_name}' from '{projection_value}' to '{new_projection_value}'" |
80 | 102 | ) |
81 | 103 |
|
82 | | - manifest["spack"]["modules"]["default"]["tcl"]["projections"][projection_name] = new_projection_value |
| 104 | + # Ensures that the new projection is a quoted string when dumped so spack does projected modules correctly, see top of file. |
| 105 | + manifest["spack"]["modules"]["default"]["tcl"]["projections"][projection_name] = YamlExplicitQuotedString(new_projection_value) |
83 | 106 |
|
84 | 107 | return manifest |
85 | 108 |
|
@@ -177,7 +200,10 @@ def main(): |
177 | 200 | args = parse_args(sys.argv[1:]) |
178 | 201 |
|
179 | 202 | injected_manifest: str = inject_prerelease_information( |
180 | | - args.manifest, args.version, args.keep_root_spec_intact, args.spack_packages_path |
| 203 | + args.manifest, |
| 204 | + args.version, |
| 205 | + args.keep_root_spec_intact, |
| 206 | + args.spack_packages_path, |
181 | 207 | ) |
182 | 208 |
|
183 | 209 | print(injected_manifest) |
|
0 commit comments