util/environment.py: require string values in env mods (#49987)
This commit is contained in:
parent
b6722ce5c9
commit
84dcc654ec
@ -12,13 +12,15 @@
|
||||
import shlex
|
||||
import subprocess
|
||||
import sys
|
||||
from functools import wraps
|
||||
import warnings
|
||||
from typing import Any, Callable, Dict, Iterable, List, MutableMapping, Optional, Tuple, Union
|
||||
|
||||
from llnl.path import path_to_os_path, system_path_filter
|
||||
from llnl.util import tty
|
||||
from llnl.util.lang import dedupe
|
||||
|
||||
import spack.error
|
||||
|
||||
if sys.platform == "win32":
|
||||
SYSTEM_PATHS = [
|
||||
"C:\\",
|
||||
@ -61,28 +63,6 @@
|
||||
ModificationList = List[Union["NameModifier", "NameValueModifier"]]
|
||||
|
||||
|
||||
def system_env_normalize(func):
|
||||
"""Decorator wrapping calls to system env modifications,
|
||||
converting all env variable names to all upper case on Windows, no-op
|
||||
on other platforms before calling env modification method.
|
||||
|
||||
Windows, due to a DOS holdover, treats all env variable names case
|
||||
insensitively, however Spack's env modification class does not,
|
||||
meaning setting `Path` and `PATH` would be distinct env operations
|
||||
for Spack, but would cause a collision when actually performing the
|
||||
env modification operations on the env.
|
||||
Normalize all env names to all caps to prevent this collision from the
|
||||
Spack side."""
|
||||
|
||||
@wraps(func)
|
||||
def case_insensitive_modification(self, name: str, *args, **kwargs):
|
||||
if sys.platform == "win32":
|
||||
name = name.upper()
|
||||
return func(self, name, *args, **kwargs)
|
||||
|
||||
return case_insensitive_modification
|
||||
|
||||
|
||||
def is_system_path(path: Path) -> bool:
|
||||
"""Returns True if the argument is a system path, False otherwise."""
|
||||
return bool(path) and (os.path.normpath(path) in SYSTEM_DIRS)
|
||||
@ -251,7 +231,7 @@ class NameModifier:
|
||||
__slots__ = ("name", "separator", "trace")
|
||||
|
||||
def __init__(self, name: str, *, separator: str = os.pathsep, trace: Optional[Trace] = None):
|
||||
self.name = name
|
||||
self.name = name.upper() if sys.platform == "win32" else name
|
||||
self.separator = separator
|
||||
self.trace = trace
|
||||
|
||||
@ -271,9 +251,17 @@ class NameValueModifier:
|
||||
__slots__ = ("name", "value", "separator", "trace")
|
||||
|
||||
def __init__(
|
||||
self, name: str, value: Any, *, separator: str = os.pathsep, trace: Optional[Trace] = None
|
||||
self, name: str, value: str, *, separator: str = os.pathsep, trace: Optional[Trace] = None
|
||||
):
|
||||
self.name = name
|
||||
self.name = name.upper() if sys.platform == "win32" else name
|
||||
if not isinstance(value, str):
|
||||
warnings.warn(
|
||||
f"{self.__class__.__name__} {self.name}={value}: using a non-string value "
|
||||
f"{type(value).__name__} is deprecated and will be an error in Spack v1.0",
|
||||
spack.error.SpackAPIWarning,
|
||||
stacklevel=4,
|
||||
)
|
||||
value = str(value)
|
||||
self.value = value
|
||||
self.separator = separator
|
||||
self.trace = trace
|
||||
@ -309,17 +297,17 @@ def __init__(
|
||||
self.raw = raw
|
||||
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"SetEnv: {self.name}={str(self.value)}", level=3)
|
||||
env[self.name] = str(self.value)
|
||||
tty.debug(f"SetEnv: {self.name}={self.value}", level=3)
|
||||
env[self.name] = self.value
|
||||
|
||||
|
||||
class AppendFlagsEnv(NameValueModifier):
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"AppendFlagsEnv: {self.name}={str(self.value)}", level=3)
|
||||
tty.debug(f"AppendFlagsEnv: {self.name}={self.value}", level=3)
|
||||
if self.name in env and env[self.name]:
|
||||
env[self.name] += self.separator + str(self.value)
|
||||
env[self.name] += self.separator + self.value
|
||||
else:
|
||||
env[self.name] = str(self.value)
|
||||
env[self.name] = self.value
|
||||
|
||||
|
||||
class UnsetEnv(NameModifier):
|
||||
@ -331,7 +319,7 @@ def execute(self, env: MutableMapping[str, str]):
|
||||
|
||||
class RemoveFlagsEnv(NameValueModifier):
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"RemoveFlagsEnv: {self.name}-{str(self.value)}", level=3)
|
||||
tty.debug(f"RemoveFlagsEnv: {self.name}-{self.value}", level=3)
|
||||
environment_value = env.get(self.name, "")
|
||||
flags = environment_value.split(self.separator) if environment_value else []
|
||||
flags = [f for f in flags if f != self.value]
|
||||
@ -339,15 +327,24 @@ def execute(self, env: MutableMapping[str, str]):
|
||||
|
||||
|
||||
class SetPath(NameValueModifier):
|
||||
def __init__(
|
||||
self,
|
||||
name: str,
|
||||
value: List[str],
|
||||
*,
|
||||
separator: str = os.pathsep,
|
||||
trace: Optional[Trace] = None,
|
||||
):
|
||||
super().__init__(name, separator.join(value), separator=separator, trace=trace)
|
||||
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
string_path = self.separator.join(str(item) for item in self.value)
|
||||
tty.debug(f"SetPath: {self.name}={string_path}", level=3)
|
||||
env[self.name] = string_path
|
||||
tty.debug(f"SetPath: {self.name}={self.value}", level=3)
|
||||
env[self.name] = self.value
|
||||
|
||||
|
||||
class AppendPath(NameValueModifier):
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"AppendPath: {self.name}+{str(self.value)}", level=3)
|
||||
tty.debug(f"AppendPath: {self.name}+{self.value}", level=3)
|
||||
environment_value = env.get(self.name, "")
|
||||
directories = environment_value.split(self.separator) if environment_value else []
|
||||
directories.append(path_to_os_path(os.path.normpath(self.value)).pop())
|
||||
@ -356,7 +353,7 @@ def execute(self, env: MutableMapping[str, str]):
|
||||
|
||||
class PrependPath(NameValueModifier):
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"PrependPath: {self.name}+{str(self.value)}", level=3)
|
||||
tty.debug(f"PrependPath: {self.name}+{self.value}", level=3)
|
||||
environment_value = env.get(self.name, "")
|
||||
directories = environment_value.split(self.separator) if environment_value else []
|
||||
directories = [path_to_os_path(os.path.normpath(self.value)).pop()] + directories
|
||||
@ -365,7 +362,7 @@ def execute(self, env: MutableMapping[str, str]):
|
||||
|
||||
class RemoveFirstPath(NameValueModifier):
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"RemoveFirstPath: {self.name}-{str(self.value)}", level=3)
|
||||
tty.debug(f"RemoveFirstPath: {self.name}-{self.value}", level=3)
|
||||
environment_value = env.get(self.name, "")
|
||||
directories = environment_value.split(self.separator)
|
||||
directories = [path_to_os_path(os.path.normpath(x)).pop() for x in directories]
|
||||
@ -377,7 +374,7 @@ def execute(self, env: MutableMapping[str, str]):
|
||||
|
||||
class RemoveLastPath(NameValueModifier):
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"RemoveLastPath: {self.name}-{str(self.value)}", level=3)
|
||||
tty.debug(f"RemoveLastPath: {self.name}-{self.value}", level=3)
|
||||
environment_value = env.get(self.name, "")
|
||||
directories = environment_value.split(self.separator)[::-1]
|
||||
directories = [path_to_os_path(os.path.normpath(x)).pop() for x in directories]
|
||||
@ -389,7 +386,7 @@ def execute(self, env: MutableMapping[str, str]):
|
||||
|
||||
class RemovePath(NameValueModifier):
|
||||
def execute(self, env: MutableMapping[str, str]):
|
||||
tty.debug(f"RemovePath: {self.name}-{str(self.value)}", level=3)
|
||||
tty.debug(f"RemovePath: {self.name}-{self.value}", level=3)
|
||||
environment_value = env.get(self.name, "")
|
||||
directories = environment_value.split(self.separator)
|
||||
directories = [
|
||||
@ -473,8 +470,7 @@ def _trace(self) -> Optional[Trace]:
|
||||
|
||||
return Trace(filename=filename, lineno=lineno, context=current_context)
|
||||
|
||||
@system_env_normalize
|
||||
def set(self, name: str, value: str, *, force: bool = False, raw: bool = False):
|
||||
def set(self, name: str, value: str, *, force: bool = False, raw: bool = False) -> None:
|
||||
"""Stores a request to set an environment variable.
|
||||
|
||||
Args:
|
||||
@ -486,8 +482,7 @@ def set(self, name: str, value: str, *, force: bool = False, raw: bool = False):
|
||||
item = SetEnv(name, value, trace=self._trace(), force=force, raw=raw)
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def append_flags(self, name: str, value: str, sep: str = " "):
|
||||
def append_flags(self, name: str, value: str, sep: str = " ") -> None:
|
||||
"""Stores a request to append 'flags' to an environment variable.
|
||||
|
||||
Args:
|
||||
@ -498,8 +493,7 @@ def append_flags(self, name: str, value: str, sep: str = " "):
|
||||
item = AppendFlagsEnv(name, value, separator=sep, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def unset(self, name: str):
|
||||
def unset(self, name: str) -> None:
|
||||
"""Stores a request to unset an environment variable.
|
||||
|
||||
Args:
|
||||
@ -508,8 +502,7 @@ def unset(self, name: str):
|
||||
item = UnsetEnv(name, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def remove_flags(self, name: str, value: str, sep: str = " "):
|
||||
def remove_flags(self, name: str, value: str, sep: str = " ") -> None:
|
||||
"""Stores a request to remove flags from an environment variable
|
||||
|
||||
Args:
|
||||
@ -520,8 +513,7 @@ def remove_flags(self, name: str, value: str, sep: str = " "):
|
||||
item = RemoveFlagsEnv(name, value, separator=sep, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def set_path(self, name: str, elements: List[str], separator: str = os.pathsep):
|
||||
def set_path(self, name: str, elements: List[str], separator: str = os.pathsep) -> None:
|
||||
"""Stores a request to set an environment variable to a list of paths,
|
||||
separated by a character defined in input.
|
||||
|
||||
@ -533,8 +525,7 @@ def set_path(self, name: str, elements: List[str], separator: str = os.pathsep):
|
||||
item = SetPath(name, elements, separator=separator, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def append_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
def append_path(self, name: str, path: str, separator: str = os.pathsep) -> None:
|
||||
"""Stores a request to append a path to list of paths.
|
||||
|
||||
Args:
|
||||
@ -545,8 +536,7 @@ def append_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
item = AppendPath(name, path, separator=separator, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def prepend_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
def prepend_path(self, name: str, path: str, separator: str = os.pathsep) -> None:
|
||||
"""Stores a request to prepend a path to list of paths.
|
||||
|
||||
Args:
|
||||
@ -557,8 +547,7 @@ def prepend_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
item = PrependPath(name, path, separator=separator, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def remove_first_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
def remove_first_path(self, name: str, path: str, separator: str = os.pathsep) -> None:
|
||||
"""Stores a request to remove first instance of path from a list of paths.
|
||||
|
||||
Args:
|
||||
@ -569,8 +558,7 @@ def remove_first_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
item = RemoveFirstPath(name, path, separator=separator, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def remove_last_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
def remove_last_path(self, name: str, path: str, separator: str = os.pathsep) -> None:
|
||||
"""Stores a request to remove last instance of path from a list of paths.
|
||||
|
||||
Args:
|
||||
@ -581,8 +569,7 @@ def remove_last_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
item = RemoveLastPath(name, path, separator=separator, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def remove_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
def remove_path(self, name: str, path: str, separator: str = os.pathsep) -> None:
|
||||
"""Stores a request to remove a path from a list of paths.
|
||||
|
||||
Args:
|
||||
@ -593,8 +580,7 @@ def remove_path(self, name: str, path: str, separator: str = os.pathsep):
|
||||
item = RemovePath(name, path, separator=separator, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def deprioritize_system_paths(self, name: str, separator: str = os.pathsep):
|
||||
def deprioritize_system_paths(self, name: str, separator: str = os.pathsep) -> None:
|
||||
"""Stores a request to deprioritize system paths in a path list,
|
||||
otherwise preserving the order.
|
||||
|
||||
@ -605,8 +591,7 @@ def deprioritize_system_paths(self, name: str, separator: str = os.pathsep):
|
||||
item = DeprioritizeSystemPaths(name, separator=separator, trace=self._trace())
|
||||
self.env_modifications.append(item)
|
||||
|
||||
@system_env_normalize
|
||||
def prune_duplicate_paths(self, name: str, separator: str = os.pathsep):
|
||||
def prune_duplicate_paths(self, name: str, separator: str = os.pathsep) -> None:
|
||||
"""Stores a request to remove duplicates from a path list, otherwise
|
||||
preserving the order.
|
||||
|
||||
|
@ -92,7 +92,7 @@ def configure_args(self):
|
||||
def setup_run_environment(self, env):
|
||||
if self.spec.satisfies("+x"):
|
||||
dir = join_path(self.prefix.lib, "X11", "app-defaults")
|
||||
env.set_path("XFILESEARCHPATH", dir)
|
||||
env.prepend_path("XFILESEARCHPATH", dir)
|
||||
|
||||
def flag_handler(self, name, flags):
|
||||
if name == "cxxflags":
|
||||
|
Loading…
Reference in New Issue
Block a user