diff --git a/manager/manager_cmds/distribution.py b/manager/manager_cmds/distribution.py index 58443a43..e80545d3 100644 --- a/manager/manager_cmds/distribution.py +++ b/manager/manager_cmds/distribution.py @@ -2,6 +2,7 @@ import fnmatch import glob import os +import re import shutil import tempfile from pathlib import Path @@ -169,7 +170,10 @@ def canonicalize_path(spath): def valid_env_scopes(env): - scopes = spack.config.CONFIG.matching_scopes(f"^env:{env.name}|^include:") + env_name = getattr(env, "name", None) + escaped_env_name = re.escape(env_name) + pattern = f"^(env:{escaped_env_name}|include:)" + scopes = spack.config.CONFIG.matching_scopes(pattern) return [s.name for s in scopes] diff --git a/tests/test_distribution.py b/tests/test_distribution.py index 0ce9c380..7afd66b9 100644 --- a/tests/test_distribution.py +++ b/tests/test_distribution.py @@ -258,6 +258,23 @@ def test_get_valid_env_scopes(tmpdir): assert len(scope_names) == 2 +def test_get_valid_env_scopes_escape_chars(tmpdir): + """ + Regression test: valid_env_scopes should match an environment scope even + when env.name contains regex-special characters. + """ + env_dir = os.path.join(tmpdir.strpath, "escape_char+_-=/*!~", "environment") + manifest = os.path.join(env_dir, "spack.yaml") + + create_spack_manifest(manifest) + + env = spack.environment.environment_from_name_or_dir(os.path.dirname(manifest)) + with env: + scope_names = distribution.valid_env_scopes(env) + + assert f"env:{env.name}" in scope_names + + class MockArgs: def __init__(self, source=False, binary=False): self.source_only = source