diff --git a/etc/spack/defaults/windows/config.yaml b/etc/spack/defaults/windows/config.yaml index 367bf831cf..53116391cc 100644 --- a/etc/spack/defaults/windows/config.yaml +++ b/etc/spack/defaults/windows/config.yaml @@ -3,3 +3,4 @@ config: concretizer: clingo build_stage:: - '$spack/.staging' + stage_name: '{name}-{version}-{hash:7}' diff --git a/lib/spack/spack/package_base.py b/lib/spack/spack/package_base.py index 470a41c460..98bf4d9c23 100644 --- a/lib/spack/spack/package_base.py +++ b/lib/spack/spack/package_base.py @@ -57,7 +57,7 @@ from spack.filesystem_view import YamlFilesystemView from spack.install_test import TestFailure, TestSuite from spack.installer import InstallError, PackageInstaller -from spack.stage import ResourceStage, Stage, StageComposite, stage_prefix +from spack.stage import ResourceStage, Stage, StageComposite, compute_stage_name from spack.util.executable import ProcessError, which from spack.util.package_hash import package_hash from spack.util.prefix import Prefix @@ -1022,8 +1022,7 @@ def _make_root_stage(self, fetcher): ) # Construct a path where the stage should build.. s = self.spec - stage_name = "{0}{1}-{2}-{3}".format(stage_prefix, s.name, s.version, s.dag_hash()) - + stage_name = compute_stage_name(s) stage = Stage( fetcher, mirror_paths=mirror_paths, diff --git a/lib/spack/spack/schema/config.py b/lib/spack/spack/schema/config.py index abe207cac0..106e45ce7a 100644 --- a/lib/spack/spack/schema/config.py +++ b/lib/spack/spack/schema/config.py @@ -61,6 +61,7 @@ "build_stage": { "oneOf": [{"type": "string"}, {"type": "array", "items": {"type": "string"}}] }, + "stage_name": {"type": "string"}, "test_stage": {"type": "string"}, "extensions": {"type": "array", "items": {"type": "string"}}, "template_dirs": {"type": "array", "items": {"type": "string"}}, diff --git a/lib/spack/spack/stage.py b/lib/spack/spack/stage.py index f6ed3c1ef4..97e05f365e 100644 --- a/lib/spack/spack/stage.py +++ b/lib/spack/spack/stage.py @@ -35,6 +35,7 @@ import spack.fetch_strategy as fs import spack.mirror import spack.paths +import spack.spec import spack.util.lock import spack.util.path as sup import spack.util.pattern as pattern @@ -49,6 +50,13 @@ stage_prefix = "spack-stage-" +def compute_stage_name(spec): + """Determine stage name given a spec""" + default_stage_structure = "spack-stage-{name}-{version}-{hash}" + stage_name_structure = spack.config.get("config:stage_name", default=default_stage_structure) + return spec.format(format_string=stage_name_structure) + + def create_stage_root(path: str) -> None: """Create the stage root directory and ensure appropriate access perms.""" assert os.path.isabs(path) and len(path.strip()) > 1 @@ -150,7 +158,10 @@ def _resolve_paths(candidates): # Ensure the path is unique per user. can_path = sup.canonicalize_path(path) - if user not in can_path: + # When multiple users share a stage root, we can avoid conflicts between + # them by adding a per-user subdirectory. + # Avoid doing this on Windows to keep stage absolute path as short as possible. + if user not in can_path and not sys.platform == "win32": can_path = os.path.join(can_path, user) paths.append(can_path) diff --git a/lib/spack/spack/test/stage.py b/lib/spack/spack/test/stage.py index 1cc1f20472..f790a66d0e 100644 --- a/lib/spack/spack/test/stage.py +++ b/lib/spack/spack/test/stage.py @@ -765,8 +765,11 @@ def test_resolve_paths(self): # resolved path without user appends user paths = [os.path.join(os.path.sep, "a", "b", "c")] + can_paths = [paths[0]] user = getpass.getuser() - can_paths = [os.path.join(paths[0], user)] + + if sys.platform != "win32": + can_paths = [os.path.join(paths[0], user)] assert spack.stage._resolve_paths(paths) == can_paths # resolved path with node including user does not append user @@ -789,7 +792,7 @@ def test_resolve_paths(self): res_paths[1] = can_tempdir res_paths[2] = os.path.join(can_tempdir, user) res_paths[3] = os.path.join(can_tempdir, "stage", user) - else: + elif sys.platform != "win32": res_paths[0] = os.path.join(res_paths[0], user) assert spack.stage._resolve_paths(paths) == res_paths