diff options
author | Xavier Delaruelle <xavier.delaruelle@cea.fr> | 2023-06-26 11:55:57 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-06-26 11:55:57 +0200 |
commit | 81647122645477ee42c40e0683de044a4e7722fc (patch) | |
tree | 847b7ab093a9d2e553e0389bfa7b8716f7fbda92 /lib | |
parent | ce0b9ea8cf184c9048cac1ae88f2d69f0e4520c7 (diff) | |
download | spack-81647122645477ee42c40e0683de044a4e7722fc.tar.gz spack-81647122645477ee42c40e0683de044a4e7722fc.tar.bz2 spack-81647122645477ee42c40e0683de044a4e7722fc.tar.xz spack-81647122645477ee42c40e0683de044a4e7722fc.zip |
Add raw attribute to env.set command (#38465)
Update `env.set` command and underlying `SetEnv` object to add the `raw`
boolean attribute. `raw` is optional and set to False by default. When
set to True, value format is skipped for object when generating
environment modifications.
With this change it is now possible to define environment variable
whose value contains variable reference syntax (like `{foo}` or `{}`)
that should be set as-is.
Fixes #29578
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/spack/modules/common.py | 17 | ||||
-rw-r--r-- | lib/spack/spack/test/modules/lmod.py | 9 | ||||
-rw-r--r-- | lib/spack/spack/test/modules/tcl.py | 9 | ||||
-rw-r--r-- | lib/spack/spack/util/environment.py | 16 |
4 files changed, 42 insertions, 9 deletions
diff --git a/lib/spack/spack/modules/common.py b/lib/spack/spack/modules/common.py index 6384069c42..08ef690953 100644 --- a/lib/spack/spack/modules/common.py +++ b/lib/spack/spack/modules/common.py @@ -671,6 +671,12 @@ class BaseContext(tengine.Context): # the configure option section return None + def modification_needs_formatting(self, modification): + """Returns True if environment modification entry needs to be formatted.""" + return ( + not isinstance(modification, (spack.util.environment.SetEnv)) or not modification.raw + ) + @tengine.context_property @memoized def environment_modifications(self): @@ -734,11 +740,12 @@ class BaseContext(tengine.Context): _check_tokens_are_valid(x.name, message=msg) # Transform them x.name = spec.format(x.name, transform=transform) - try: - # Not every command has a value - x.value = spec.format(x.value) - except AttributeError: - pass + if self.modification_needs_formatting(x): + try: + # Not every command has a value + x.value = spec.format(x.value) + except AttributeError: + pass x.name = str(x.name).replace("-", "_") return [(type(x).__name__, x) for x in env if x.name not in exclude] diff --git a/lib/spack/spack/test/modules/lmod.py b/lib/spack/spack/test/modules/lmod.py index 5cfb6896c3..20c7e30ce7 100644 --- a/lib/spack/spack/test/modules/lmod.py +++ b/lib/spack/spack/test/modules/lmod.py @@ -198,6 +198,15 @@ class TestLmod(object): assert len([x for x in content if 'setenv("MANPATH", "/path/to/man")' in x]) == 1 assert len([x for x in content if 'append_path("MANPATH", "", ":")' in x]) == 0 + @pytest.mark.regression("29578") + def test_setenv_raw_value(self, modulefile_content, module_configuration): + """Tests that we can set environment variable value without formatting it.""" + + module_configuration("autoload_direct") + content = modulefile_content("module-setenv-raw") + + assert len([x for x in content if 'setenv("FOO", "{{name}}, {name}, {{}}, {}")' in x]) == 1 + def test_help_message(self, modulefile_content, module_configuration): """Tests the generation of module help message.""" diff --git a/lib/spack/spack/test/modules/tcl.py b/lib/spack/spack/test/modules/tcl.py index 283fad2583..9dee83bf0d 100644 --- a/lib/spack/spack/test/modules/tcl.py +++ b/lib/spack/spack/test/modules/tcl.py @@ -182,6 +182,15 @@ class TestTcl(object): assert len([x for x in content if 'setenv MANPATH "/path/to/man"' in x]) == 1 assert len([x for x in content if 'append-path --delim ":" MANPATH ""' in x]) == 0 + @pytest.mark.regression("29578") + def test_setenv_raw_value(self, modulefile_content, module_configuration): + """Tests that we can set environment variable value without formatting it.""" + + module_configuration("autoload_direct") + content = modulefile_content("module-setenv-raw") + + assert len([x for x in content if 'setenv FOO "{{name}}, {name}, {{}}, {}"' in x]) == 1 + def test_help_message(self, modulefile_content, module_configuration): """Tests the generation of module help message.""" diff --git a/lib/spack/spack/util/environment.py b/lib/spack/spack/util/environment.py index ded31dcf39..bde7ce3780 100644 --- a/lib/spack/spack/util/environment.py +++ b/lib/spack/spack/util/environment.py @@ -351,13 +351,20 @@ class NameValueModifier: class SetEnv(NameValueModifier): - __slots__ = ("force",) + __slots__ = ("force", "raw") def __init__( - self, name: str, value: str, *, trace: Optional[Trace] = None, force: bool = False + self, + name: str, + value: str, + *, + trace: Optional[Trace] = None, + force: bool = False, + raw: bool = False, ): super().__init__(name, value, trace=trace) self.force = force + self.raw = raw def execute(self, env: MutableMapping[str, str]): tty.debug(f"SetEnv: {self.name}={str(self.value)}", level=3) @@ -501,15 +508,16 @@ class EnvironmentModifications: return Trace(filename=filename, lineno=lineno, context=current_context) @system_env_normalize - def set(self, name: str, value: str, *, force: bool = False): + def set(self, name: str, value: str, *, force: bool = False, raw: bool = False): """Stores a request to set an environment variable. Args: name: name of the environment variable value: value of the environment variable force: if True, audit will not consider this modification a warning + raw: if True, format of value string is skipped """ - item = SetEnv(name, value, trace=self._trace(), force=force) + item = SetEnv(name, value, trace=self._trace(), force=force, raw=raw) self.env_modifications.append(item) @system_env_normalize |