|
5 | 5 | import jinja2 |
6 | 6 | import yaml |
7 | 7 |
|
8 | | -from . import root_logger, schema, spack_util, mirror |
9 | | -from .etc import envvars |
| 8 | +from . import cache, root_logger, schema, spack_util, mirror |
| 9 | +from .etc.envvars import EnvVarSet |
10 | 10 |
|
11 | 11 |
|
12 | 12 | class Recipe: |
@@ -87,14 +87,6 @@ def __init__(self, args): |
87 | 87 | self._logger.error(f"modules.yaml:{self.with_modules}") |
88 | 88 | raise RuntimeError("conflicting modules configuration detected") |
89 | 89 |
|
90 | | - # optional packages.yaml file |
91 | | - packages_path = self.path / "packages.yaml" |
92 | | - self._logger.debug(f"opening {packages_path}") |
93 | | - self.packages = None |
94 | | - if packages_path.is_file(): |
95 | | - with packages_path.open() as fid: |
96 | | - self.packages = yaml.load(fid, Loader=yaml.Loader) |
97 | | - |
98 | 90 | self._logger.debug("creating packages") |
99 | 91 |
|
100 | 92 | # load recipe/packages.yaml -> recipe_packages (if it exists) |
@@ -169,8 +161,23 @@ def __init__(self, args): |
169 | 161 | schema.EnvironmentsValidator.validate(raw) |
170 | 162 | self.generate_environment_specs(raw) |
171 | 163 |
|
| 164 | + # check that the default view exists (if one has been set) |
| 165 | + self._default_view = self.config["default-view"] |
| 166 | + if self._default_view is not None: |
| 167 | + available_views = [view["name"] for env in self.environments.values() for view in env["views"]] |
| 168 | + # add the modules and spack views to the list of available views |
| 169 | + if self.with_modules: |
| 170 | + available_views.append("modules") |
| 171 | + available_views.append("spack") |
| 172 | + if self._default_view not in available_views: |
| 173 | + self._logger.error( |
| 174 | + f"The default-view {self._default_view} is not the name of a view in the environments.yaml " |
| 175 | + "definition (one of {[name for name in available_views]}" |
| 176 | + ) |
| 177 | + raise RuntimeError("Ivalid default-view in the recipe.") |
| 178 | + |
172 | 179 | # load the optional mirrors.yaml from system config, and add any additional |
173 | | - # mirrors specified on the command line. |
| 180 | + # mirrors specified on the command line. |
174 | 181 | self._logger.debug("Configuring mirrors.") |
175 | 182 | self.mirrors = mirror.Mirrors(self.system_config_path, pathlib.Path(args.cache) if args.cache else None) |
176 | 183 |
|
@@ -262,66 +269,28 @@ def with_modules(self) -> bool: |
262 | 269 | def find_spack_version(self, develop): |
263 | 270 | return "1.0" |
264 | 271 |
|
| 272 | + @property |
| 273 | + def default_view(self): |
| 274 | + return self._default_view |
| 275 | + |
265 | 276 | @property |
266 | 277 | def environment_view_meta(self): |
267 | 278 | # generate the view meta data that is presented in the squashfs image meta data |
268 | 279 | view_meta = {} |
269 | 280 | for _, env in self.environments.items(): |
270 | 281 | for view in env["views"]: |
271 | | - # recipe authors can substitute the name of the view, the mount |
272 | | - # and view path into environment variables using '$@key@' where |
273 | | - # key is one of view_name, mount and view_path. |
274 | | - substitutions = { |
275 | | - "view_name": str(view["name"]), |
276 | | - "mount": str(self.mount), |
277 | | - "view_path": str(view["config"]["root"]), |
278 | | - } |
279 | | - |
280 | | - def fill(s): |
281 | | - return re.sub( |
282 | | - r"\$@(\w+)@", |
283 | | - lambda m: substitutions.get(m.group(1), m.group(0)), |
284 | | - s, |
285 | | - ) |
286 | | - |
287 | | - ev_inputs = view["extra"]["env_vars"] |
288 | | - env = envvars.EnvVarSet() |
289 | | - |
290 | | - # TODO: one day this code will be revisited because we need to append_path |
291 | | - # or prepend_path to a variable that isn't in envvars.is_list_var |
292 | | - # On that day, extend the environments.yaml views:uenv:env_vars field |
293 | | - # to also accept a list of env var names to add to the blessed list of prefix paths |
294 | | - |
295 | | - for v in ev_inputs["set"]: |
296 | | - ((name, value),) = v.items() |
297 | | - if value is not None: |
298 | | - value = fill(value) |
299 | | - |
300 | | - # insist that the only 'set' operation on prefix variables is to unset/reset them |
301 | | - # this requires that users use append and prepend to build up the variables |
302 | | - if envvars.is_list_var(name) and value is not None: |
303 | | - raise RuntimeError(f"{name} in the {view['name']} view is a prefix variable.") |
304 | | - else: |
305 | | - if envvars.is_list_var(name): |
306 | | - env.set_list(name, [], envvars.EnvVarOp.SET) |
307 | | - else: |
308 | | - env.set_scalar(name, value) |
309 | | - for v in ev_inputs["prepend_path"]: |
310 | | - ((name, value),) = v.items() |
311 | | - if value is not None: |
312 | | - value = fill(value) |
313 | | - if not envvars.is_list_var(name): |
314 | | - raise RuntimeError(f"{name} in the {view['name']} view is not a known prefix path variable") |
315 | | - |
316 | | - env.set_list(name, [value], envvars.EnvVarOp.APPEND) |
317 | | - for v in ev_inputs["append_path"]: |
318 | | - ((name, value),) = v.items() |
319 | | - if value is not None: |
320 | | - value = fill(value) |
321 | | - if not envvars.is_list_var(name): |
322 | | - raise RuntimeError(f"{name} in the {view['name']} view is not a known prefix path variable") |
323 | | - |
324 | | - env.set_list(name, [value], envvars.EnvVarOp.PREPEND) |
| 282 | + try: |
| 283 | + # recipe authors can substitute the name of the view, the mount |
| 284 | + # and view path into environment variables using '$@key@' where |
| 285 | + # key is one of view_name, mount and view_path. |
| 286 | + substitutions = { |
| 287 | + "view_name": str(view["name"]), |
| 288 | + "mount": str(self.mount), |
| 289 | + "view_path": str(view["config"]["root"]), |
| 290 | + } |
| 291 | + env = EnvVarSet.from_envvars(view["extra"]["env_vars"], substitutions) |
| 292 | + except Exception as err: |
| 293 | + raise RuntimeError(f'In view "{view["name"]}": {err}') |
325 | 294 |
|
326 | 295 | view_meta[view["name"]] = { |
327 | 296 | "root": view["config"]["root"], |
@@ -398,6 +367,10 @@ def generate_environment_specs(self, raw): |
398 | 367 | # Which will compile the upstream MPI with nvfortran, as well as downstream dependendencies. |
399 | 368 | if config["prefer"] is None: |
400 | 369 | compiler = config["compiler"][0] |
| 370 | + # spack uses a different name for the intel oneapi compilers |
| 371 | + # than the package that installs them. |
| 372 | + if compiler == "intel-oneapi-compilers": |
| 373 | + compiler = "oneapi" |
401 | 374 | config["prefer"] = [ |
402 | 375 | f"%[when=%c] c={compiler} %[when=%cxx] cxx={compiler} %[when=%fortran] fortran={compiler}" |
403 | 376 | ] |
@@ -484,6 +457,15 @@ def generate_compiler_specs(self, raw): |
484 | 457 | llvm_amdgpu["exclude_from_cache"] = cache_exclude |
485 | 458 | compilers["llvm-amdgpu"] = llvm_amdgpu |
486 | 459 |
|
| 460 | + if raw["intel-oneapi-compilers"] is not None: |
| 461 | + oneapi = {} |
| 462 | + oneapi_version = raw["intel-oneapi-compilers"]["version"] |
| 463 | + oneapi["packages"] = False |
| 464 | + oneapi["specs"] = [f"intel-oneapi-compilers@{oneapi_version}"] |
| 465 | + |
| 466 | + oneapi["exclude_from_cache"] = cache_exclude |
| 467 | + compilers["intel-oneapi-compilers"] = oneapi |
| 468 | + |
487 | 469 | self.compilers = compilers |
488 | 470 |
|
489 | 471 | # The path of the default configuration for the target system/cluster |
|
0 commit comments