Skip to content

Commit f83837c

Browse files
Merge pull request #1321 from douglasjacobsen/package-injection
Allows software_spec's to be injected if not present in environments
2 parents e7aab6a + c038e16 commit f83837c

File tree

15 files changed

+611
-13
lines changed

15 files changed

+611
-13
lines changed

lib/ramble/ramble/experiment_set.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ def _prepare_experiment(
328328
app_inst.set_formatted_executables(context.formatted_executables)
329329

330330
if app_inst.package_manager is not None:
331+
app_inst.package_manager.define_missing_packages(self._workspace)
331332
app_inst.define_variable(
332333
self.keywords.env_path,
333334
os.path.join(

lib/ramble/ramble/language/shared_language.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,14 @@ def _execute_figure_of_merit(obj):
161161

162162
@shared_directive("compilers")
163163
def define_compiler(
164-
name, pkg_spec, compiler_spec=None, compiler=None, package_manager=None, when=None, **kwargs
164+
name,
165+
pkg_spec,
166+
compiler_spec=None,
167+
compiler=None,
168+
package_manager=None,
169+
inject_if_missing=False,
170+
when=None,
171+
**kwargs,
165172
):
166173
"""Defines the compiler that will be used with this object
167174
@@ -175,6 +182,8 @@ def define_compiler(
175182
compiler (str): Package name to use for compilation
176183
package_manager (str): Glob supported pattern to match package managers
177184
this compiler applies to
185+
inject_if_missing (bool): Whether the package should be defined if a
186+
matching package is not already defined
178187
when (list | None): List of when conditions to apply to directive
179188
"""
180189

@@ -195,7 +204,12 @@ def _execute_define_compiler(obj):
195204

196205
obj.compilers[name].append(
197206
SoftwareSpec(
198-
name, pkg_spec, compiler=compiler, compiler_spec=compiler_spec, when=when_list
207+
name,
208+
pkg_spec,
209+
compiler=compiler,
210+
compiler_spec=compiler_spec,
211+
inject_if_missing=inject_if_missing,
212+
when=when_list,
199213
)
200214
)
201215

@@ -204,7 +218,14 @@ def _execute_define_compiler(obj):
204218

205219
@shared_directive("software_specs")
206220
def software_spec(
207-
name, pkg_spec, compiler_spec=None, compiler=None, package_manager=None, when=None, **kwargs
221+
name,
222+
pkg_spec,
223+
compiler_spec=None,
224+
compiler=None,
225+
package_manager=None,
226+
inject_if_missing=False,
227+
when=None,
228+
**kwargs,
208229
):
209230
"""Defines a new software spec needed for this object.
210231
@@ -223,6 +244,8 @@ def software_spec(
223244
compiler (str): Package name to use as compiler for compiling this package
224245
package_manager (str): Glob supported pattern to match package managers
225246
this package applies to
247+
inject_if_missing (bool): Whether the package should be added to experiment
248+
environments automatically or not.
226249
when (list | None): List of when conditions to apply to directive
227250
"""
228251

@@ -244,7 +267,12 @@ def _execute_software_spec(obj):
244267
# Define the spec
245268
obj.software_specs[name].append(
246269
SoftwareSpec(
247-
name, pkg_spec, compiler=compiler, compiler_spec=compiler_spec, when=when_list
270+
name,
271+
pkg_spec,
272+
compiler=compiler,
273+
compiler_spec=compiler_spec,
274+
inject_if_missing=inject_if_missing,
275+
when=when_list,
248276
)
249277
)
250278

lib/ramble/ramble/software_environments.py

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from ramble.expander import Expander
1515
from ramble.namespace import namespace
1616
from ramble.util.logger import logger
17+
from ramble.util.spec_utils import SoftwareSpec
1718

1819
SUB_INDENT = 2
1920

@@ -55,6 +56,7 @@ def __init__(
5556
self.pkg_info = pkg_info
5657
self._package_type = "Base"
5758
self._used = False
59+
self.injected = False
5860

5961
def mark_used(self):
6062
"""Mark this package a used"""
@@ -107,7 +109,9 @@ def info(
107109
indentation = " " * indent
108110
color = rucolor.level_func(color_level)
109111

110-
out_str = color(f"{indentation}{self._package_type} package: {self.name}\n")
112+
injected_str = "" if not self.injected else " (injected by ramble)"
113+
114+
out_str = color(f"{indentation}{self._package_type} package: {self.name} {injected_str}\n")
111115
return out_str
112116

113117
def __str__(self):
@@ -466,14 +470,22 @@ def __eq__(self, other):
466470
Returns:
467471
(bool): True if environments are equivalent, False otherwise
468472
"""
469-
equal = self.name == other.name and len(self._packages) == len(other._packages)
470-
471-
if not equal:
473+
if not self.name == other.name:
472474
return False
473475

474-
for self_pkg, other_pkg in zip(self._packages, other._packages):
475-
if self_pkg != other_pkg:
476-
return False
476+
self_pkgs = {}
477+
other_pkgs = {}
478+
479+
for self_pkg in self._packages:
480+
if not self_pkg.injected:
481+
self_pkgs[self_pkg.name] = self_pkg
482+
483+
for other_pkg in other._packages:
484+
if not other_pkg.injected:
485+
other_pkgs[other_pkg.name] = other_pkg
486+
487+
if self_pkgs != other_pkgs:
488+
return False
477489

478490
return True
479491

@@ -853,6 +865,7 @@ def define_compiler_packages(self, environment: RenderedEnvironment, expander: E
853865

854866
if rendered_pkg.compiler:
855867
cur_compiler = rendered_pkg.compiler
868+
856869
if not added:
857870
raise RambleSoftwareEnvironmentError(
858871
f"Compiler {pkg.compiler} used, but not "
@@ -921,6 +934,45 @@ def package_specs_for_environment(self, environment: SoftwareEnvironment):
921934
for pkg in environment._packages:
922935
yield pkg.spec_str(all_packages=self._rendered_packages, compiler=False)
923936

937+
def add_spec_to_environment(
938+
self,
939+
environment: SoftwareEnvironment,
940+
spec: SoftwareSpec,
941+
expander: Expander,
942+
package_manager,
943+
):
944+
"""Add a spec to a given environment
945+
946+
Creates a new template / rendered package (if needed) from the input spec,
947+
and adds to the template and rendered environment as a package in the environment.
948+
949+
Args:
950+
environment (SoftwareEnvironment): Rendered environment to add package to
951+
spec (ramble.util.spec_utils.SoftwareSpec): Software spec to add to environment
952+
expander (ramble.expander.Expander): Experiment's expander object,
953+
to render package / environment with
954+
package_manager: Package manager from the experiment
955+
"""
956+
957+
pm_name = package_manager.spec_prefix
958+
959+
if spec.name not in self._package_templates:
960+
template_package = TemplatePackage(spec.name, spec.to_dict())
961+
962+
self._package_templates[spec.name] = template_package
963+
964+
template_package = self._package_templates[spec.name]
965+
966+
rendered_package = template_package.render_package(expander, package_manager)
967+
rendered_package.injected = True
968+
969+
if rendered_package.name not in self._rendered_packages:
970+
template_package.add_rendered_package(
971+
rendered_package, self._rendered_packages, pm_name
972+
)
973+
974+
environment.add_package(rendered_package)
975+
924976
def _check_environment(self, environment):
925977
"""Check an environment for common issues
926978

0 commit comments

Comments
 (0)