Compare commits

...

9 Commits

Author SHA1 Message Date
Wouter Deconinck
4bc67e8e84 util-linux: provide uuid when new variant +uuid 2024-07-06 14:07:05 -05:00
dependabot[bot]
aeaa922eef build(deps): bump actions/upload-artifact from 4.3.3 to 4.3.4 (#45069)
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.3.3 to 4.3.4.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](65462800fd...0b2256b8c0)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-06 08:20:30 +02:00
Hadrien G
a6d5a34be3 Remove myself from maintainer lists (#45071) 2024-07-06 08:17:31 +02:00
Todd Gamblin
ba79542f3c spack gc: remove debug print statement (#45067)
Signed-off-by: Todd Gamblin <tgamblin@llnl.gov>
2024-07-05 22:36:45 +02:00
Auriane R
dc10c8a1ed [py-transformers] Add newer versions (#45022)
* Add newer versions for py-transformers

* Add dependencies needed for py-transformers latest version

* Enforce dependencies requirements for py-transformers newer versions
2024-07-05 14:52:24 +02:00
Auriane R
5ab814505e py-flash-attn: add v2.5.6 -> main (#44894)
* Add latest releases of py-flash-attn

* Add main branch for flash attention

* Add additional requirements
2024-07-05 06:19:01 -06:00
Harmen Stoppels
1d8bdcfc04 config: fix class hierarchy (#45044)
1. Avoid that `self.path` is of type `Optional[str]`
2. Simplify immutable config with a property.
2024-07-05 12:41:13 +02:00
Massimiliano Culpo
95cf341b50 Inject dependencies in repo classes (#45053) 2024-07-05 12:00:41 +02:00
Benjamin Fovet
a134485b1b remove trailing dot in gmsh 4.13.0 shasum (#45054) 2024-07-05 10:18:11 +02:00
41 changed files with 548 additions and 342 deletions

View File

@@ -87,7 +87,7 @@ jobs:
fi fi
- name: Upload Dockerfile - name: Upload Dockerfile
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b
with: with:
name: dockerfiles_${{ matrix.dockerfile[0] }} name: dockerfiles_${{ matrix.dockerfile[0] }}
path: dockerfiles path: dockerfiles
@@ -126,7 +126,7 @@ jobs:
needs: deploy-images needs: deploy-images
steps: steps:
- name: Merge Artifacts - name: Merge Artifacts
uses: actions/upload-artifact/merge@65462800fd760344b1a7b4382951275a0abb4808 uses: actions/upload-artifact/merge@0b2256b8c012f0828dc542b3febcab082c67f72b
with: with:
name: dockerfiles name: dockerfiles
pattern: dockerfiles_* pattern: dockerfiles_*

View File

@@ -60,7 +60,7 @@ packages:
szip: [libaec, libszip] szip: [libaec, libszip]
tbb: [intel-tbb] tbb: [intel-tbb]
unwind: [libunwind] unwind: [libunwind]
uuid: [util-linux-uuid, libuuid] uuid: [util-linux-uuid, util-linux+uuid, libuuid]
xxd: [xxd-standalone, vim] xxd: [xxd-standalone, vim]
yacc: [bison, byacc] yacc: [bison, byacc]
ziglang: [zig] ziglang: [zig]

View File

@@ -129,10 +129,10 @@ def _bootstrap_config_scopes() -> Sequence["spack.config.ConfigScope"]:
configuration_paths = (spack.config.CONFIGURATION_DEFAULTS_PATH, ("bootstrap", _config_path())) configuration_paths = (spack.config.CONFIGURATION_DEFAULTS_PATH, ("bootstrap", _config_path()))
for name, path in configuration_paths: for name, path in configuration_paths:
platform = spack.platforms.host().name platform = spack.platforms.host().name
platform_scope = spack.config.ConfigScope( platform_scope = spack.config.DirectoryConfigScope(
"/".join([name, platform]), os.path.join(path, platform) f"{name}/{platform}", os.path.join(path, platform)
) )
generic_scope = spack.config.ConfigScope(name, path) generic_scope = spack.config.DirectoryConfigScope(name, path)
config_scopes.extend([generic_scope, platform_scope]) config_scopes.extend([generic_scope, platform_scope])
msg = "[BOOTSTRAP CONFIG SCOPE] name={0}, path={1}" msg = "[BOOTSTRAP CONFIG SCOPE] name={0}, path={1}"
tty.debug(msg.format(generic_scope.name, generic_scope.path)) tty.debug(msg.format(generic_scope.name, generic_scope.path))

View File

@@ -34,6 +34,8 @@ def _misc_cache():
return spack.util.file_cache.FileCache(path) return spack.util.file_cache.FileCache(path)
FileCacheType = Union[spack.util.file_cache.FileCache, llnl.util.lang.Singleton]
#: Spack's cache for small data #: Spack's cache for small data
MISC_CACHE: Union[spack.util.file_cache.FileCache, llnl.util.lang.Singleton] = ( MISC_CACHE: Union[spack.util.file_cache.FileCache, llnl.util.lang.Singleton] = (
llnl.util.lang.Singleton(_misc_cache) llnl.util.lang.Singleton(_misc_cache)

View File

@@ -809,7 +809,8 @@ def ensure_expected_target_path(path):
cli_scopes = [ cli_scopes = [
os.path.relpath(s.path, concrete_env_dir) os.path.relpath(s.path, concrete_env_dir)
for s in cfg.scopes().values() for s in cfg.scopes().values()
if isinstance(s, cfg.ImmutableConfigScope) if not s.writable
and isinstance(s, (cfg.DirectoryConfigScope))
and s.path not in env_includes and s.path not in env_includes
and os.path.exists(s.path) and os.path.exists(s.path)
] ]

View File

@@ -165,7 +165,7 @@ def _reset(args):
if not ok_to_continue: if not ok_to_continue:
raise RuntimeError("Aborting") raise RuntimeError("Aborting")
for scope in spack.config.CONFIG.file_scopes: for scope in spack.config.CONFIG.writable_scopes:
# The default scope should stay untouched # The default scope should stay untouched
if scope.name == "defaults": if scope.name == "defaults":
continue continue

View File

@@ -264,7 +264,9 @@ def config_remove(args):
def _can_update_config_file(scope: spack.config.ConfigScope, cfg_file): def _can_update_config_file(scope: spack.config.ConfigScope, cfg_file):
if isinstance(scope, spack.config.SingleFileScope): if isinstance(scope, spack.config.SingleFileScope):
return fs.can_access(cfg_file) return fs.can_access(cfg_file)
return fs.can_write_to_dir(scope.path) and fs.can_access(cfg_file) elif isinstance(scope, spack.config.DirectoryConfigScope):
return fs.can_write_to_dir(scope.path) and fs.can_access(cfg_file)
return False
def _config_change_requires_scope(path, spec, scope, match_spec=None): def _config_change_requires_scope(path, spec, scope, match_spec=None):
@@ -362,14 +364,11 @@ def config_change(args):
def config_update(args): def config_update(args):
# Read the configuration files # Read the configuration files
spack.config.CONFIG.get_config(args.section, scope=args.scope) spack.config.CONFIG.get_config(args.section, scope=args.scope)
updates: List[spack.config.ConfigScope] = list( updates: List[spack.config.ConfigScope] = [
filter( x
lambda s: not isinstance( for x in spack.config.CONFIG.format_updates[args.section]
s, (spack.config.InternalConfigScope, spack.config.ImmutableConfigScope) if not isinstance(x, spack.config.InternalConfigScope) and x.writable
), ]
spack.config.CONFIG.format_updates[args.section],
)
)
cannot_overwrite, skip_system_scope = [], False cannot_overwrite, skip_system_scope = [], False
for scope in updates: for scope in updates:
@@ -447,7 +446,7 @@ def _can_revert_update(scope_dir, cfg_file, bkp_file):
def config_revert(args): def config_revert(args):
scopes = [args.scope] if args.scope else [x.name for x in spack.config.CONFIG.file_scopes] scopes = [args.scope] if args.scope else [x.name for x in spack.config.CONFIG.writable_scopes]
# Search for backup files in the configuration scopes # Search for backup files in the configuration scopes
Entry = collections.namedtuple("Entry", ["scope", "cfg", "bkp"]) Entry = collections.namedtuple("Entry", ["scope", "cfg", "bkp"])

View File

@@ -2,7 +2,6 @@
# Spack Project Developers. See the top-level COPYRIGHT file for details. # Spack Project Developers. See the top-level COPYRIGHT file for details.
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os import os
import re import re
import sys import sys
@@ -934,7 +933,7 @@ def get_repository(args, name):
# Figure out where the new package should live # Figure out where the new package should live
repo_path = args.repo repo_path = args.repo
if repo_path is not None: if repo_path is not None:
repo = spack.repo.Repo(repo_path) repo = spack.repo.from_path(repo_path)
if spec.namespace and spec.namespace != repo.namespace: if spec.namespace and spec.namespace != repo.namespace:
tty.die( tty.die(
"Can't create package with namespace {0} in repo with " "Can't create package with namespace {0} in repo with "

View File

@@ -123,7 +123,7 @@ def edit(parser, args):
spack.util.editor.editor(*paths) spack.util.editor.editor(*paths)
elif names: elif names:
if args.repo: if args.repo:
repo = spack.repo.Repo(args.repo) repo = spack.repo.from_path(args.repo)
elif args.namespace: elif args.namespace:
repo = spack.repo.PATH.get_repo(args.namespace) repo = spack.repo.PATH.get_repo(args.namespace)
else: else:

View File

@@ -56,7 +56,6 @@ def roots_from_environments(args, active_env):
# -e says "also preserve things needed by this particular env" # -e says "also preserve things needed by this particular env"
for env_name_or_dir in args.except_environment: for env_name_or_dir in args.except_environment:
print("HMM", env_name_or_dir)
if ev.exists(env_name_or_dir): if ev.exists(env_name_or_dir):
env = ev.read(env_name_or_dir) env = ev.read(env_name_or_dir)
elif ev.is_env_dir(env_name_or_dir): elif ev.is_env_dir(env_name_or_dir):

View File

@@ -91,7 +91,7 @@ def repo_add(args):
tty.die("Not a Spack repository: %s" % path) tty.die("Not a Spack repository: %s" % path)
# Make sure it's actually a spack repository by constructing it. # Make sure it's actually a spack repository by constructing it.
repo = spack.repo.Repo(canon_path) repo = spack.repo.from_path(canon_path)
# If that succeeds, finally add it to the configuration. # If that succeeds, finally add it to the configuration.
repos = spack.config.get("repos", scope=args.scope) repos = spack.config.get("repos", scope=args.scope)
@@ -124,7 +124,7 @@ def repo_remove(args):
# If it is a namespace, remove corresponding repo # If it is a namespace, remove corresponding repo
for path in repos: for path in repos:
try: try:
repo = spack.repo.Repo(path) repo = spack.repo.from_path(path)
if repo.namespace == namespace_or_path: if repo.namespace == namespace_or_path:
repos.remove(path) repos.remove(path)
spack.config.set("repos", repos, args.scope) spack.config.set("repos", repos, args.scope)
@@ -142,7 +142,7 @@ def repo_list(args):
repos = [] repos = []
for r in roots: for r in roots:
try: try:
repos.append(spack.repo.Repo(r)) repos.append(spack.repo.from_path(r))
except spack.repo.RepoError: except spack.repo.RepoError:
continue continue

View File

@@ -260,7 +260,7 @@ def _init_compiler_config(
def compiler_config_files(): def compiler_config_files():
config_files = list() config_files = list()
config = spack.config.CONFIG config = spack.config.CONFIG
for scope in config.file_scopes: for scope in config.writable_scopes:
name = scope.name name = scope.name
compiler_config = config.get("compilers", scope=name) compiler_config = config.get("compilers", scope=name)
if compiler_config: if compiler_config:

View File

@@ -35,7 +35,7 @@
import os import os
import re import re
import sys import sys
from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Type, Union from typing import Any, Callable, Dict, Generator, List, Optional, Tuple, Union
from llnl.util import filesystem, lang, tty from llnl.util import filesystem, lang, tty
@@ -117,21 +117,39 @@
class ConfigScope: class ConfigScope:
"""This class represents a configuration scope. def __init__(self, name: str) -> None:
self.name = name
self.writable = False
self.sections = syaml.syaml_dict()
A scope is one directory containing named configuration files. def get_section_filename(self, section: str) -> str:
Each file is a config "section" (e.g., mirrors, compilers, etc.). raise NotImplementedError
"""
def __init__(self, name, path) -> None: def get_section(self, section: str) -> Optional[YamlConfigDict]:
self.name = name # scope name. raise NotImplementedError
self.path = path # path to directory containing configs.
self.sections = syaml.syaml_dict() # sections read from config files. def _write_section(self, section: str) -> None:
raise NotImplementedError
@property @property
def is_platform_dependent(self) -> bool: def is_platform_dependent(self) -> bool:
"""Returns true if the scope name is platform specific""" return False
return os.sep in self.name
def clear(self) -> None:
"""Empty cached config information."""
self.sections = syaml.syaml_dict()
def __repr__(self) -> str:
return f"<ConfigScope: {self.name}>"
class DirectoryConfigScope(ConfigScope):
"""Config scope backed by a directory containing one file per section."""
def __init__(self, name: str, path: str, *, writable: bool = True) -> None:
super().__init__(name)
self.path = path
self.writable = writable
def get_section_filename(self, section: str) -> str: def get_section_filename(self, section: str) -> str:
"""Returns the filename associated with a given section""" """Returns the filename associated with a given section"""
@@ -148,6 +166,9 @@ def get_section(self, section: str) -> Optional[YamlConfigDict]:
return self.sections[section] return self.sections[section]
def _write_section(self, section: str) -> None: def _write_section(self, section: str) -> None:
if not self.writable:
raise ConfigError(f"Cannot write to immutable scope {self}")
filename = self.get_section_filename(section) filename = self.get_section_filename(section)
data = self.get_section(section) data = self.get_section(section)
if data is None: if data is None:
@@ -164,19 +185,23 @@ def _write_section(self, section: str) -> None:
except (syaml.SpackYAMLError, OSError) as e: except (syaml.SpackYAMLError, OSError) as e:
raise ConfigFileError(f"cannot write to '{filename}'") from e raise ConfigFileError(f"cannot write to '{filename}'") from e
def clear(self) -> None: @property
"""Empty cached config information.""" def is_platform_dependent(self) -> bool:
self.sections = syaml.syaml_dict() """Returns true if the scope name is platform specific"""
return "/" in self.name
def __repr__(self) -> str:
return f"<ConfigScope: {self.name}: {self.path}>"
class SingleFileScope(ConfigScope): class SingleFileScope(ConfigScope):
"""This class represents a configuration scope in a single YAML file.""" """This class represents a configuration scope in a single YAML file."""
def __init__( def __init__(
self, name: str, path: str, schema: YamlConfigDict, yaml_path: Optional[List[str]] = None self,
name: str,
path: str,
schema: YamlConfigDict,
*,
yaml_path: Optional[List[str]] = None,
writable: bool = True,
) -> None: ) -> None:
"""Similar to ``ConfigScope`` but can be embedded in another schema. """Similar to ``ConfigScope`` but can be embedded in another schema.
@@ -195,15 +220,13 @@ def __init__(
config: config:
install_tree: $spack/opt/spack install_tree: $spack/opt/spack
""" """
super().__init__(name, path) super().__init__(name)
self._raw_data: Optional[YamlConfigDict] = None self._raw_data: Optional[YamlConfigDict] = None
self.schema = schema self.schema = schema
self.path = path
self.writable = writable
self.yaml_path = yaml_path or [] self.yaml_path = yaml_path or []
@property
def is_platform_dependent(self) -> bool:
return False
def get_section_filename(self, section) -> str: def get_section_filename(self, section) -> str:
return self.path return self.path
@@ -257,6 +280,8 @@ def get_section(self, section: str) -> Optional[YamlConfigDict]:
return self.sections.get(section, None) return self.sections.get(section, None)
def _write_section(self, section: str) -> None: def _write_section(self, section: str) -> None:
if not self.writable:
raise ConfigError(f"Cannot write to immutable scope {self}")
data_to_write: Optional[YamlConfigDict] = self._raw_data data_to_write: Optional[YamlConfigDict] = self._raw_data
# If there is no existing data, this section SingleFileScope has never # If there is no existing data, this section SingleFileScope has never
@@ -301,19 +326,6 @@ def __repr__(self) -> str:
return f"<SingleFileScope: {self.name}: {self.path}>" return f"<SingleFileScope: {self.name}: {self.path}>"
class ImmutableConfigScope(ConfigScope):
"""A configuration scope that cannot be written to.
This is used for ConfigScopes passed on the command line.
"""
def _write_section(self, section) -> None:
raise ConfigError(f"Cannot write to immutable scope {self}")
def __repr__(self) -> str:
return f"<ImmutableConfigScope: {self.name}: {self.path}>"
class InternalConfigScope(ConfigScope): class InternalConfigScope(ConfigScope):
"""An internal configuration scope that is not persisted to a file. """An internal configuration scope that is not persisted to a file.
@@ -323,7 +335,7 @@ class InternalConfigScope(ConfigScope):
""" """
def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None: def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None:
super().__init__(name, None) super().__init__(name)
self.sections = syaml.syaml_dict() self.sections = syaml.syaml_dict()
if data is not None: if data is not None:
@@ -333,9 +345,6 @@ def __init__(self, name: str, data: Optional[YamlConfigDict] = None) -> None:
validate({section: dsec}, SECTION_SCHEMAS[section]) validate({section: dsec}, SECTION_SCHEMAS[section])
self.sections[section] = _mark_internal(syaml.syaml_dict({section: dsec}), name) self.sections[section] = _mark_internal(syaml.syaml_dict({section: dsec}), name)
def get_section_filename(self, section: str) -> str:
raise NotImplementedError("Cannot get filename for InternalConfigScope.")
def get_section(self, section: str) -> Optional[YamlConfigDict]: def get_section(self, section: str) -> Optional[YamlConfigDict]:
"""Just reads from an internal dictionary.""" """Just reads from an internal dictionary."""
if section not in self.sections: if section not in self.sections:
@@ -440,27 +449,21 @@ def remove_scope(self, scope_name: str) -> Optional[ConfigScope]:
return scope return scope
@property @property
def file_scopes(self) -> List[ConfigScope]: def writable_scopes(self) -> Generator[ConfigScope, None, None]:
"""List of writable scopes with an associated file.""" """Generator of writable scopes with an associated file."""
return [ return (s for s in self.scopes.values() if s.writable)
s
for s in self.scopes.values()
if (type(s) is ConfigScope or type(s) is SingleFileScope)
]
def highest_precedence_scope(self) -> ConfigScope: def highest_precedence_scope(self) -> ConfigScope:
"""Non-internal scope with highest precedence.""" """Writable scope with highest precedence."""
return next(reversed(self.file_scopes)) return next(s for s in reversed(self.scopes.values()) if s.writable) # type: ignore
def highest_precedence_non_platform_scope(self) -> ConfigScope: def highest_precedence_non_platform_scope(self) -> ConfigScope:
"""Non-internal non-platform scope with highest precedence """Writable non-platform scope with highest precedence"""
return next(
Platform-specific scopes are of the form scope/platform""" s
generator = reversed(self.file_scopes) for s in reversed(self.scopes.values()) # type: ignore
highest = next(generator) if s.writable and not s.is_platform_dependent
while highest and highest.is_platform_dependent: )
highest = next(generator)
return highest
def matching_scopes(self, reg_expr) -> List[ConfigScope]: def matching_scopes(self, reg_expr) -> List[ConfigScope]:
""" """
@@ -755,13 +758,14 @@ def override(
def _add_platform_scope( def _add_platform_scope(
cfg: Union[Configuration, lang.Singleton], scope_type: Type[ConfigScope], name: str, path: str cfg: Union[Configuration, lang.Singleton], name: str, path: str, writable: bool = True
) -> None: ) -> None:
"""Add a platform-specific subdirectory for the current platform.""" """Add a platform-specific subdirectory for the current platform."""
platform = spack.platforms.host().name platform = spack.platforms.host().name
plat_name = os.path.join(name, platform) scope = DirectoryConfigScope(
plat_path = os.path.join(path, platform) f"{name}/{platform}", os.path.join(path, platform), writable=writable
cfg.push_scope(scope_type(plat_name, plat_path)) )
cfg.push_scope(scope)
def config_paths_from_entry_points() -> List[Tuple[str, str]]: def config_paths_from_entry_points() -> List[Tuple[str, str]]:
@@ -806,8 +810,8 @@ def _add_command_line_scopes(
# name based on order on the command line # name based on order on the command line
name = f"cmd_scope_{i:d}" name = f"cmd_scope_{i:d}"
cfg.push_scope(ImmutableConfigScope(name, path)) cfg.push_scope(DirectoryConfigScope(name, path, writable=False))
_add_platform_scope(cfg, ImmutableConfigScope, name, path) _add_platform_scope(cfg, name, path, writable=False)
def create() -> Configuration: def create() -> Configuration:
@@ -851,10 +855,10 @@ def create() -> Configuration:
# add each scope and its platform-specific directory # add each scope and its platform-specific directory
for name, path in configuration_paths: for name, path in configuration_paths:
cfg.push_scope(ConfigScope(name, path)) cfg.push_scope(DirectoryConfigScope(name, path))
# Each scope can have per-platfom overrides in subdirectories # Each scope can have per-platfom overrides in subdirectories
_add_platform_scope(cfg, ConfigScope, name, path) _add_platform_scope(cfg, name, path)
# add command-line scopes # add command-line scopes
_add_command_line_scopes(cfg, COMMAND_LINE_SCOPES) _add_command_line_scopes(cfg, COMMAND_LINE_SCOPES)
@@ -969,7 +973,7 @@ def set(path: str, value: Any, scope: Optional[str] = None) -> None:
def add_default_platform_scope(platform: str) -> None: def add_default_platform_scope(platform: str) -> None:
plat_name = os.path.join("defaults", platform) plat_name = os.path.join("defaults", platform)
plat_path = os.path.join(CONFIGURATION_DEFAULTS_PATH[1], platform) plat_path = os.path.join(CONFIGURATION_DEFAULTS_PATH[1], platform)
CONFIG.push_scope(ConfigScope(plat_name, plat_path)) CONFIG.push_scope(DirectoryConfigScope(plat_name, plat_path))
def scopes() -> Dict[str, ConfigScope]: def scopes() -> Dict[str, ConfigScope]:
@@ -978,19 +982,10 @@ def scopes() -> Dict[str, ConfigScope]:
def writable_scopes() -> List[ConfigScope]: def writable_scopes() -> List[ConfigScope]:
""" """Return list of writable scopes. Higher-priority scopes come first in the list."""
Return list of writable scopes. Higher-priority scopes come first in the scopes = [x for x in CONFIG.scopes.values() if x.writable]
list. scopes.reverse()
""" return scopes
return list(
reversed(
list(
x
for x in CONFIG.scopes.values()
if not isinstance(x, (InternalConfigScope, ImmutableConfigScope))
)
)
)
def writable_scope_names() -> List[str]: def writable_scope_names() -> List[str]:
@@ -1599,7 +1594,7 @@ def _config_from(scopes_or_paths: List[Union[ConfigScope, str]]) -> Configuratio
path = os.path.normpath(scope_or_path) path = os.path.normpath(scope_or_path)
assert os.path.isdir(path), f'"{path}" must be a directory' assert os.path.isdir(path), f'"{path}" must be a directory'
name = os.path.basename(path) name = os.path.basename(path)
scopes.append(ConfigScope(name, path)) scopes.append(DirectoryConfigScope(name, path))
configuration = Configuration(*scopes) configuration = Configuration(*scopes)
return configuration return configuration

View File

@@ -24,6 +24,7 @@
from llnl.util.link_tree import ConflictingSpecsError from llnl.util.link_tree import ConflictingSpecsError
from llnl.util.symlink import readlink, symlink from llnl.util.symlink import readlink, symlink
import spack.caches
import spack.cmd import spack.cmd
import spack.compilers import spack.compilers
import spack.concretize import spack.concretize
@@ -2542,7 +2543,7 @@ def _concretize_task(packed_arguments) -> Tuple[int, Spec, float]:
def make_repo_path(root): def make_repo_path(root):
"""Make a RepoPath from the repo subdirectories in an environment.""" """Make a RepoPath from the repo subdirectories in an environment."""
path = spack.repo.RepoPath() path = spack.repo.RepoPath(cache=spack.caches.MISC_CACHE)
if os.path.isdir(root): if os.path.isdir(root):
for repo_root in os.listdir(root): for repo_root in os.listdir(root):
@@ -2551,7 +2552,7 @@ def make_repo_path(root):
if not os.path.isdir(repo_root): if not os.path.isdir(repo_root):
continue continue
repo = spack.repo.Repo(repo_root) repo = spack.repo.from_path(repo_root)
path.put_last(repo) path.put_last(repo)
return path return path
@@ -3027,7 +3028,7 @@ def included_config_scopes(self) -> List[spack.config.ConfigScope]:
SpackEnvironmentError: if the manifest includes a remote file but SpackEnvironmentError: if the manifest includes a remote file but
no configuration stage directory has been identified no configuration stage directory has been identified
""" """
scopes = [] scopes: List[spack.config.ConfigScope] = []
# load config scopes added via 'include:', in reverse so that # load config scopes added via 'include:', in reverse so that
# highest-precedence scopes are last. # highest-precedence scopes are last.
@@ -3096,23 +3097,21 @@ def included_config_scopes(self) -> List[spack.config.ConfigScope]:
if os.path.isdir(config_path): if os.path.isdir(config_path):
# directories are treated as regular ConfigScopes # directories are treated as regular ConfigScopes
config_name = "env:%s:%s" % (env_name, os.path.basename(config_path)) config_name = "env:%s:%s" % (env_name, os.path.basename(config_path))
tty.debug("Creating ConfigScope {0} for '{1}'".format(config_name, config_path)) tty.debug(f"Creating DirectoryConfigScope {config_name} for '{config_path}'")
scope = spack.config.ConfigScope(config_name, config_path) scopes.append(spack.config.DirectoryConfigScope(config_name, config_path))
elif os.path.exists(config_path): elif os.path.exists(config_path):
# files are assumed to be SingleFileScopes # files are assumed to be SingleFileScopes
config_name = "env:%s:%s" % (env_name, config_path) config_name = "env:%s:%s" % (env_name, config_path)
tty.debug( tty.debug(f"Creating SingleFileScope {config_name} for '{config_path}'")
"Creating SingleFileScope {0} for '{1}'".format(config_name, config_path) scopes.append(
) spack.config.SingleFileScope(
scope = spack.config.SingleFileScope( config_name, config_path, spack.schema.merged.schema
config_name, config_path, spack.schema.merged.schema )
) )
else: else:
missing.append(config_path) missing.append(config_path)
continue continue
scopes.append(scope)
if missing: if missing:
msg = "Detected {0} missing include path(s):".format(len(missing)) msg = "Detected {0} missing include path(s):".format(len(missing))
msg += "\n {0}".format("\n ".join(missing)) msg += "\n {0}".format("\n ".join(missing))
@@ -3129,7 +3128,10 @@ def env_config_scopes(self) -> List[spack.config.ConfigScope]:
scopes: List[spack.config.ConfigScope] = [ scopes: List[spack.config.ConfigScope] = [
*self.included_config_scopes, *self.included_config_scopes,
spack.config.SingleFileScope( spack.config.SingleFileScope(
self.scope_name, str(self.manifest_file), spack.schema.env.schema, [TOP_LEVEL_KEY] self.scope_name,
str(self.manifest_file),
spack.schema.env.schema,
yaml_path=[TOP_LEVEL_KEY],
), ),
] ]
ensure_no_disallowed_env_config_mods(scopes) ensure_no_disallowed_env_config_mods(scopes)

View File

@@ -582,7 +582,7 @@ def dump_packages(spec: "spack.spec.Spec", path: str) -> None:
# Create a source repo and get the pkg directory out of it. # Create a source repo and get the pkg directory out of it.
try: try:
source_repo = spack.repo.Repo(source_repo_root) source_repo = spack.repo.from_path(source_repo_root)
source_pkg_dir = source_repo.dirname_for_package_name(node.name) source_pkg_dir = source_repo.dirname_for_package_name(node.name)
except spack.repo.RepoError as err: except spack.repo.RepoError as err:
tty.debug(f"Failed to create source repo for {node.name}: {str(err)}") tty.debug(f"Failed to create source repo for {node.name}: {str(err)}")
@@ -593,7 +593,7 @@ def dump_packages(spec: "spack.spec.Spec", path: str) -> None:
dest_repo_root = os.path.join(path, node.namespace) dest_repo_root = os.path.join(path, node.namespace)
if not os.path.exists(dest_repo_root): if not os.path.exists(dest_repo_root):
spack.repo.create_repo(dest_repo_root) spack.repo.create_repo(dest_repo_root)
repo = spack.repo.Repo(dest_repo_root) repo = spack.repo.from_path(dest_repo_root)
# Get the location of the package in the dest repo. # Get the location of the package in the dest repo.
dest_pkg_dir = repo.dirname_for_package_name(node.name) dest_pkg_dir = repo.dirname_for_package_name(node.name)

View File

@@ -748,11 +748,6 @@ def __init__(self, spec):
self._fetch_time = 0.0 self._fetch_time = 0.0
self.win_rpath = fsys.WindowsSimulatedRPath(self) self.win_rpath = fsys.WindowsSimulatedRPath(self)
if self.is_extension:
pkg_cls = spack.repo.PATH.get_pkg_class(self.extendee_spec.name)
pkg_cls(self.extendee_spec)._check_extendable()
super().__init__() super().__init__()
@classmethod @classmethod
@@ -2388,10 +2383,6 @@ def do_deprecate(self, deprecator, link_fn):
PackageBase.uninstall_by_spec(spec, force=True, deprecator=deprecator) PackageBase.uninstall_by_spec(spec, force=True, deprecator=deprecator)
link_fn(deprecator.prefix, spec.prefix) link_fn(deprecator.prefix, spec.prefix)
def _check_extendable(self):
if not self.extendable:
raise ValueError("Package %s is not extendable!" % self.name)
def view(self): def view(self):
"""Create a view with the prefix of this package as the root. """Create a view with the prefix of this package as the root.
Extensions added to this view will modify the installation prefix of Extensions added to this view will modify the installation prefix of

View File

@@ -25,7 +25,8 @@
import traceback import traceback
import types import types
import uuid import uuid
from typing import Any, Dict, List, Set, Tuple, Union import warnings
from typing import Any, Dict, Generator, List, Optional, Set, Tuple, Type, Union
import llnl.path import llnl.path
import llnl.util.filesystem as fs import llnl.util.filesystem as fs
@@ -126,11 +127,35 @@ def exec_module(self, module):
class ReposFinder: class ReposFinder:
"""MetaPathFinder class that loads a Python module corresponding to a Spack package """MetaPathFinder class that loads a Python module corresponding to a Spack package.
Return a loader based on the inspection of the current global repository list. Returns a loader based on the inspection of the current repository list.
""" """
def __init__(self):
self._repo_init = _path
self._repo = None
@property
def current_repository(self):
if self._repo is None:
self._repo = self._repo_init()
return self._repo
@current_repository.setter
def current_repository(self, value):
self._repo = value
@contextlib.contextmanager
def switch_repo(self, substitute: "RepoType"):
"""Switch the current repository list for the duration of the context manager."""
old = self.current_repository
try:
self.current_repository = substitute
yield
finally:
self.current_repository = old
def find_spec(self, fullname, python_path, target=None): def find_spec(self, fullname, python_path, target=None):
# "target" is not None only when calling importlib.reload() # "target" is not None only when calling importlib.reload()
if target is not None: if target is not None:
@@ -149,9 +174,14 @@ def compute_loader(self, fullname):
# namespaces are added to repo, and package modules are leaves. # namespaces are added to repo, and package modules are leaves.
namespace, dot, module_name = fullname.rpartition(".") namespace, dot, module_name = fullname.rpartition(".")
# If it's a module in some repo, or if it is the repo's # If it's a module in some repo, or if it is the repo's namespace, let the repo handle it.
# namespace, let the repo handle it. is_repo_path = isinstance(self.current_repository, RepoPath)
for repo in PATH.repos: if is_repo_path:
repos = self.current_repository.repos
else:
repos = [self.current_repository]
for repo in repos:
# We are using the namespace of the repo and the repo contains the package # We are using the namespace of the repo and the repo contains the package
if namespace == repo.full_namespace: if namespace == repo.full_namespace:
# With 2 nested conditionals we can call "repo.real_name" only once # With 2 nested conditionals we can call "repo.real_name" only once
@@ -165,7 +195,7 @@ def compute_loader(self, fullname):
# No repo provides the namespace, but it is a valid prefix of # No repo provides the namespace, but it is a valid prefix of
# something in the RepoPath. # something in the RepoPath.
if PATH.by_namespace.is_prefix(fullname): if is_repo_path and self.current_repository.by_namespace.is_prefix(fullname):
return SpackNamespaceLoader() return SpackNamespaceLoader()
return None return None
@@ -560,7 +590,7 @@ def __init__(
self, self,
package_checker: FastPackageChecker, package_checker: FastPackageChecker,
namespace: str, namespace: str,
cache: spack.util.file_cache.FileCache, cache: spack.caches.FileCacheType,
): ):
self.checker = package_checker self.checker = package_checker
self.packages_path = self.checker.packages_path self.packages_path = self.checker.packages_path
@@ -648,11 +678,9 @@ class RepoPath:
repos (list): list Repo objects or paths to put in this RepoPath repos (list): list Repo objects or paths to put in this RepoPath
""" """
def __init__(self, *repos, **kwargs): def __init__(self, *repos, cache, overrides=None):
cache = kwargs.get("cache", spack.caches.MISC_CACHE)
self.repos = [] self.repos = []
self.by_namespace = nm.NamespaceTrie() self.by_namespace = nm.NamespaceTrie()
self._provider_index = None self._provider_index = None
self._patch_index = None self._patch_index = None
self._tag_index = None self._tag_index = None
@@ -661,7 +689,8 @@ def __init__(self, *repos, **kwargs):
for repo in repos: for repo in repos:
try: try:
if isinstance(repo, str): if isinstance(repo, str):
repo = Repo(repo, cache=cache) repo = Repo(repo, cache=cache, overrides=overrides)
repo.finder(self)
self.put_last(repo) self.put_last(repo)
except RepoError as e: except RepoError as e:
tty.warn( tty.warn(
@@ -915,18 +944,28 @@ class Repo:
Each package repository must have a top-level configuration file Each package repository must have a top-level configuration file
called `repo.yaml`. called `repo.yaml`.
Currently, `repo.yaml` this must define: Currently, `repo.yaml` must define:
`namespace`: `namespace`:
A Python namespace where the repository's packages should live. A Python namespace where the repository's packages should live.
`subdirectory`:
An optional subdirectory name where packages are placed
""" """
def __init__(self, root, cache=None): def __init__(
self,
root: str,
*,
cache: spack.caches.FileCacheType,
overrides: Optional[Dict[str, Any]] = None,
) -> None:
"""Instantiate a package repository from a filesystem path. """Instantiate a package repository from a filesystem path.
Args: Args:
root: the root directory of the repository root: the root directory of the repository
cache: file cache associated with this repository
overrides: dict mapping package name to class attribute overrides for that package
""" """
# Root directory, containing _repo.yaml and package dirs # Root directory, containing _repo.yaml and package dirs
# Allow roots to by spack-relative by starting with '$spack' # Allow roots to by spack-relative by starting with '$spack'
@@ -939,20 +978,20 @@ def check(condition, msg):
# Validate repository layout. # Validate repository layout.
self.config_file = os.path.join(self.root, repo_config_name) self.config_file = os.path.join(self.root, repo_config_name)
check(os.path.isfile(self.config_file), "No %s found in '%s'" % (repo_config_name, root)) check(os.path.isfile(self.config_file), f"No {repo_config_name} found in '{root}'")
# Read configuration and validate namespace # Read configuration and validate namespace
config = self._read_config() config = self._read_config()
check( check(
"namespace" in config, "namespace" in config,
"%s must define a namespace." % os.path.join(root, repo_config_name), f"{os.path.join(root, repo_config_name)} must define a namespace.",
) )
self.namespace = config["namespace"] self.namespace = config["namespace"]
check( check(
re.match(r"[a-zA-Z][a-zA-Z0-9_.]+", self.namespace), re.match(r"[a-zA-Z][a-zA-Z0-9_.]+", self.namespace),
("Invalid namespace '%s' in repo '%s'. " % (self.namespace, self.root)) f"Invalid namespace '{self.namespace}' in repo '{self.root}'. "
+ "Namespaces must be valid python identifiers separated by '.'", "Namespaces must be valid python identifiers separated by '.'",
) )
# Set up 'full_namespace' to include the super-namespace # Set up 'full_namespace' to include the super-namespace
@@ -964,23 +1003,26 @@ def check(condition, msg):
packages_dir = config.get("subdirectory", packages_dir_name) packages_dir = config.get("subdirectory", packages_dir_name)
self.packages_path = os.path.join(self.root, packages_dir) self.packages_path = os.path.join(self.root, packages_dir)
check( check(
os.path.isdir(self.packages_path), os.path.isdir(self.packages_path), f"No directory '{packages_dir}' found in '{root}'"
"No directory '%s' found in '%s'" % (packages_dir, root),
) )
# These are internal cache variables. # Class attribute overrides by package name
self._modules = {} self.overrides = overrides or {}
self._classes = {}
self._instances = {} # Optional reference to a RepoPath to influence module import from spack.pkg
self._finder: Optional[RepoPath] = None
# Maps that goes from package name to corresponding file stat # Maps that goes from package name to corresponding file stat
self._fast_package_checker = None self._fast_package_checker: Optional[FastPackageChecker] = None
# Indexes for this repository, computed lazily # Indexes for this repository, computed lazily
self._repo_index = None self._repo_index: Optional[RepoIndex] = None
self._cache = cache or spack.caches.MISC_CACHE self._cache = cache
def real_name(self, import_name): def finder(self, value: RepoPath) -> None:
self._finder = value
def real_name(self, import_name: str) -> Optional[str]:
"""Allow users to import Spack packages using Python identifiers. """Allow users to import Spack packages using Python identifiers.
A python identifier might map to many different Spack package A python identifier might map to many different Spack package
@@ -999,18 +1041,21 @@ def real_name(self, import_name):
return import_name return import_name
options = nm.possible_spack_module_names(import_name) options = nm.possible_spack_module_names(import_name)
options.remove(import_name) try:
options.remove(import_name)
except ValueError:
pass
for name in options: for name in options:
if name in self: if name in self:
return name return name
return None return None
def is_prefix(self, fullname): def is_prefix(self, fullname: str) -> bool:
"""True if fullname is a prefix of this Repo's namespace.""" """True if fullname is a prefix of this Repo's namespace."""
parts = fullname.split(".") parts = fullname.split(".")
return self._names[: len(parts)] == parts return self._names[: len(parts)] == parts
def _read_config(self): def _read_config(self) -> Dict[str, str]:
"""Check for a YAML config file in this db's root directory.""" """Check for a YAML config file in this db's root directory."""
try: try:
with open(self.config_file) as reponame_file: with open(self.config_file) as reponame_file:
@@ -1021,14 +1066,14 @@ def _read_config(self):
or "repo" not in yaml_data or "repo" not in yaml_data
or not isinstance(yaml_data["repo"], dict) or not isinstance(yaml_data["repo"], dict)
): ):
tty.die("Invalid %s in repository %s" % (repo_config_name, self.root)) tty.die(f"Invalid {repo_config_name} in repository {self.root}")
return yaml_data["repo"] return yaml_data["repo"]
except IOError: except IOError:
tty.die("Error reading %s when opening %s" % (self.config_file, self.root)) tty.die(f"Error reading {self.config_file} when opening {self.root}")
def get(self, spec): def get(self, spec: "spack.spec.Spec") -> "spack.package_base.PackageBase":
"""Returns the package associated with the supplied spec.""" """Returns the package associated with the supplied spec."""
msg = "Repo.get can only be called on concrete specs" msg = "Repo.get can only be called on concrete specs"
assert isinstance(spec, spack.spec.Spec) and spec.concrete, msg assert isinstance(spec, spack.spec.Spec) and spec.concrete, msg
@@ -1049,16 +1094,13 @@ def get(self, spec):
# pass these through as their error messages will be fine. # pass these through as their error messages will be fine.
raise raise
except Exception as e: except Exception as e:
tty.debug(e)
# Make sure other errors in constructors hit the error # Make sure other errors in constructors hit the error
# handler by wrapping them # handler by wrapping them
if spack.config.get("config:debug"): tty.debug(e)
sys.excepthook(*sys.exc_info()) raise FailedConstructorError(spec.fullname, *sys.exc_info()) from e
raise FailedConstructorError(spec.fullname, *sys.exc_info())
@autospec @autospec
def dump_provenance(self, spec, path): def dump_provenance(self, spec: "spack.spec.Spec", path: str) -> None:
"""Dump provenance information for a spec to a particular path. """Dump provenance information for a spec to a particular path.
This dumps the package file and any associated patch files. This dumps the package file and any associated patch files.
@@ -1066,7 +1108,7 @@ def dump_provenance(self, spec, path):
""" """
if spec.namespace and spec.namespace != self.namespace: if spec.namespace and spec.namespace != self.namespace:
raise UnknownPackageError( raise UnknownPackageError(
"Repository %s does not contain package %s." % (self.namespace, spec.fullname) f"Repository {self.namespace} does not contain package {spec.fullname}."
) )
package_path = self.filename_for_package_name(spec.name) package_path = self.filename_for_package_name(spec.name)
@@ -1083,17 +1125,13 @@ def dump_provenance(self, spec, path):
if os.path.exists(patch.path): if os.path.exists(patch.path):
fs.install(patch.path, path) fs.install(patch.path, path)
else: else:
tty.warn("Patch file did not exist: %s" % patch.path) warnings.warn(f"Patch file did not exist: {patch.path}")
# Install the package.py file itself. # Install the package.py file itself.
fs.install(self.filename_for_package_name(spec.name), path) fs.install(self.filename_for_package_name(spec.name), path)
def purge(self):
"""Clear entire package instance cache."""
self._instances.clear()
@property @property
def index(self): def index(self) -> RepoIndex:
"""Construct the index for this repo lazily.""" """Construct the index for this repo lazily."""
if self._repo_index is None: if self._repo_index is None:
self._repo_index = RepoIndex(self._pkg_checker, self.namespace, cache=self._cache) self._repo_index = RepoIndex(self._pkg_checker, self.namespace, cache=self._cache)
@@ -1103,42 +1141,40 @@ def index(self):
return self._repo_index return self._repo_index
@property @property
def provider_index(self): def provider_index(self) -> spack.provider_index.ProviderIndex:
"""A provider index with names *specific* to this repo.""" """A provider index with names *specific* to this repo."""
return self.index["providers"] return self.index["providers"]
@property @property
def tag_index(self): def tag_index(self) -> spack.tag.TagIndex:
"""Index of tags and which packages they're defined on.""" """Index of tags and which packages they're defined on."""
return self.index["tags"] return self.index["tags"]
@property @property
def patch_index(self): def patch_index(self) -> spack.patch.PatchCache:
"""Index of patches and packages they're defined on.""" """Index of patches and packages they're defined on."""
return self.index["patches"] return self.index["patches"]
@autospec @autospec
def providers_for(self, vpkg_spec): def providers_for(self, vpkg_spec: "spack.spec.Spec") -> List["spack.spec.Spec"]:
providers = self.provider_index.providers_for(vpkg_spec) providers = self.provider_index.providers_for(vpkg_spec)
if not providers: if not providers:
raise UnknownPackageError(vpkg_spec.fullname) raise UnknownPackageError(vpkg_spec.fullname)
return providers return providers
@autospec @autospec
def extensions_for(self, extendee_spec): def extensions_for(
return [ self, extendee_spec: "spack.spec.Spec"
pkg_cls(spack.spec.Spec(pkg_cls.name)) ) -> List["spack.package_base.PackageBase"]:
for pkg_cls in self.all_package_classes() result = [pkg_cls(spack.spec.Spec(pkg_cls.name)) for pkg_cls in self.all_package_classes()]
if pkg_cls(spack.spec.Spec(pkg_cls.name)).extends(extendee_spec) return [x for x in result if x.extends(extendee_spec)]
]
def dirname_for_package_name(self, pkg_name): def dirname_for_package_name(self, pkg_name: str) -> str:
"""Get the directory name for a particular package. This is the """Given a package name, get the directory containing its package.py file."""
directory that contains its package.py file."""
_, unqualified_name = self.partition_package_name(pkg_name) _, unqualified_name = self.partition_package_name(pkg_name)
return os.path.join(self.packages_path, unqualified_name) return os.path.join(self.packages_path, unqualified_name)
def filename_for_package_name(self, pkg_name): def filename_for_package_name(self, pkg_name: str) -> str:
"""Get the filename for the module we should load for a particular """Get the filename for the module we should load for a particular
package. Packages for a Repo live in package. Packages for a Repo live in
``$root/<package_name>/package.py`` ``$root/<package_name>/package.py``
@@ -1151,23 +1187,23 @@ def filename_for_package_name(self, pkg_name):
return os.path.join(pkg_dir, package_file_name) return os.path.join(pkg_dir, package_file_name)
@property @property
def _pkg_checker(self): def _pkg_checker(self) -> FastPackageChecker:
if self._fast_package_checker is None: if self._fast_package_checker is None:
self._fast_package_checker = FastPackageChecker(self.packages_path) self._fast_package_checker = FastPackageChecker(self.packages_path)
return self._fast_package_checker return self._fast_package_checker
def all_package_names(self, include_virtuals=False): def all_package_names(self, include_virtuals: bool = False) -> List[str]:
"""Returns a sorted list of all package names in the Repo.""" """Returns a sorted list of all package names in the Repo."""
names = sorted(self._pkg_checker.keys()) names = sorted(self._pkg_checker.keys())
if include_virtuals: if include_virtuals:
return names return names
return [x for x in names if not self.is_virtual(x)] return [x for x in names if not self.is_virtual(x)]
def package_path(self, name): def package_path(self, name: str) -> str:
"""Get path to package.py file for this repo.""" """Get path to package.py file for this repo."""
return os.path.join(self.packages_path, name, package_file_name) return os.path.join(self.packages_path, name, package_file_name)
def all_package_paths(self): def all_package_paths(self) -> Generator[str, None, None]:
for name in self.all_package_names(): for name in self.all_package_names():
yield self.package_path(name) yield self.package_path(name)
@@ -1176,7 +1212,7 @@ def packages_with_tags(self, *tags: str) -> Set[str]:
v.intersection_update(*(self.tag_index[tag.lower()] for tag in tags)) v.intersection_update(*(self.tag_index[tag.lower()] for tag in tags))
return v return v
def all_package_classes(self): def all_package_classes(self) -> Generator[Type["spack.package_base.PackageBase"], None, None]:
"""Iterator over all package *classes* in the repository. """Iterator over all package *classes* in the repository.
Use this with care, because loading packages is slow. Use this with care, because loading packages is slow.
@@ -1184,7 +1220,7 @@ def all_package_classes(self):
for name in self.all_package_names(): for name in self.all_package_names():
yield self.get_pkg_class(name) yield self.get_pkg_class(name)
def exists(self, pkg_name): def exists(self, pkg_name: str) -> bool:
"""Whether a package with the supplied name exists.""" """Whether a package with the supplied name exists."""
if pkg_name is None: if pkg_name is None:
return False return False
@@ -1201,28 +1237,22 @@ def last_mtime(self):
"""Time a package file in this repo was last updated.""" """Time a package file in this repo was last updated."""
return self._pkg_checker.last_mtime() return self._pkg_checker.last_mtime()
def is_virtual(self, pkg_name): def is_virtual(self, pkg_name: str) -> bool:
"""Return True if the package with this name is virtual, False otherwise. """Return True if the package with this name is virtual, False otherwise.
This function use the provider index. If calling from a code block that This function use the provider index. If calling from a code block that
is used to construct the provider index use the ``is_virtual_safe`` function. is used to construct the provider index use the ``is_virtual_safe`` function.
Args:
pkg_name (str): name of the package we want to check
""" """
return pkg_name in self.provider_index return pkg_name in self.provider_index
def is_virtual_safe(self, pkg_name): def is_virtual_safe(self, pkg_name: str) -> bool:
"""Return True if the package with this name is virtual, False otherwise. """Return True if the package with this name is virtual, False otherwise.
This function doesn't use the provider index. This function doesn't use the provider index.
Args:
pkg_name (str): name of the package we want to check
""" """
return not self.exists(pkg_name) or self.get_pkg_class(pkg_name).virtual return not self.exists(pkg_name) or self.get_pkg_class(pkg_name).virtual
def get_pkg_class(self, pkg_name): def get_pkg_class(self, pkg_name: str) -> Type["spack.package_base.PackageBase"]:
"""Get the class for the package out of its module. """Get the class for the package out of its module.
First loads (or fetches from cache) a module for the First loads (or fetches from cache) a module for the
@@ -1234,7 +1264,8 @@ def get_pkg_class(self, pkg_name):
fullname = f"{self.full_namespace}.{pkg_name}" fullname = f"{self.full_namespace}.{pkg_name}"
try: try:
module = importlib.import_module(fullname) with REPOS_FINDER.switch_repo(self._finder or self):
module = importlib.import_module(fullname)
except ImportError: except ImportError:
raise UnknownPackageError(fullname) raise UnknownPackageError(fullname)
except Exception as e: except Exception as e:
@@ -1245,26 +1276,21 @@ def get_pkg_class(self, pkg_name):
if not inspect.isclass(cls): if not inspect.isclass(cls):
tty.die(f"{pkg_name}.{class_name} is not a class") tty.die(f"{pkg_name}.{class_name} is not a class")
new_cfg_settings = ( # Clear any prior changes to class attributes in case the class was loaded from the
spack.config.get("packages").get(pkg_name, {}).get("package_attributes", {}) # same repo, but with different overrides
)
overridden_attrs = getattr(cls, "overridden_attrs", {}) overridden_attrs = getattr(cls, "overridden_attrs", {})
attrs_exclusively_from_config = getattr(cls, "attrs_exclusively_from_config", []) attrs_exclusively_from_config = getattr(cls, "attrs_exclusively_from_config", [])
# Clear any prior changes to class attributes in case the config has
# since changed
for key, val in overridden_attrs.items(): for key, val in overridden_attrs.items():
setattr(cls, key, val) setattr(cls, key, val)
for key in attrs_exclusively_from_config: for key in attrs_exclusively_from_config:
delattr(cls, key) delattr(cls, key)
# Keep track of every class attribute that is overridden by the config: # Keep track of every class attribute that is overridden: if different overrides
# if the config changes between calls to this method, we make sure to # dictionaries are used on the same physical repo, we make sure to restore the original
# restore the original config values (in case the new config no longer # config values
# sets attributes that it used to)
new_overridden_attrs = {} new_overridden_attrs = {}
new_attrs_exclusively_from_config = set() new_attrs_exclusively_from_config = set()
for key, val in new_cfg_settings.items(): for key, val in self.overrides.get(pkg_name, {}).items():
if hasattr(cls, key): if hasattr(cls, key):
new_overridden_attrs[key] = getattr(cls, key) new_overridden_attrs[key] = getattr(cls, key)
else: else:
@@ -1291,13 +1317,13 @@ def partition_package_name(self, pkg_name: str) -> Tuple[str, str]:
return namespace, pkg_name return namespace, pkg_name
def __str__(self): def __str__(self) -> str:
return "[Repo '%s' at '%s']" % (self.namespace, self.root) return f"Repo '{self.namespace}' at {self.root}"
def __repr__(self): def __repr__(self) -> str:
return self.__str__() return self.__str__()
def __contains__(self, pkg_name): def __contains__(self, pkg_name: str) -> bool:
return self.exists(pkg_name) return self.exists(pkg_name)
@@ -1373,12 +1399,17 @@ def create_repo(root, namespace=None, subdir=packages_dir_name):
return full_path, namespace return full_path, namespace
def from_path(path: str) -> "Repo":
"""Returns a repository from the path passed as input. Injects the global misc cache."""
return Repo(path, cache=spack.caches.MISC_CACHE)
def create_or_construct(path, namespace=None): def create_or_construct(path, namespace=None):
"""Create a repository, or just return a Repo if it already exists.""" """Create a repository, or just return a Repo if it already exists."""
if not os.path.exists(path): if not os.path.exists(path):
fs.mkdirp(path) fs.mkdirp(path)
create_repo(path, namespace) create_repo(path, namespace)
return Repo(path) return from_path(path)
def _path(configuration=None): def _path(configuration=None):
@@ -1396,7 +1427,17 @@ def create(configuration):
repo_dirs = configuration.get("repos") repo_dirs = configuration.get("repos")
if not repo_dirs: if not repo_dirs:
raise NoRepoConfiguredError("Spack configuration contains no package repositories.") raise NoRepoConfiguredError("Spack configuration contains no package repositories.")
return RepoPath(*repo_dirs)
overrides = {}
for pkg_name, data in configuration.get("packages").items():
if pkg_name == "all":
continue
value = data.get("package_attributes", {})
if not value:
continue
overrides[pkg_name] = value
return RepoPath(*repo_dirs, cache=spack.caches.MISC_CACHE, overrides=overrides)
#: Singleton repo path instance #: Singleton repo path instance

View File

@@ -115,8 +115,8 @@ def default_config(tmpdir, config_directory, monkeypatch, install_mockery_mutabl
cfg = spack.config.Configuration( cfg = spack.config.Configuration(
*[ *[
spack.config.ConfigScope(name, str(mutable_dir)) spack.config.DirectoryConfigScope(name, str(mutable_dir))
for name in ["site/%s" % platform.system().lower(), "site", "user"] for name in [f"site/{platform.system().lower()}", "site", "user"]
] ]
) )

View File

@@ -13,6 +13,7 @@
import spack.cmd.pkg import spack.cmd.pkg
import spack.main import spack.main
import spack.repo import spack.repo
import spack.util.file_cache
#: new fake package template #: new fake package template
pkg_template = """\ pkg_template = """\
@@ -34,13 +35,14 @@ def install(self, spec, prefix):
# Force all tests to use a git repository *in* the mock packages repo. # Force all tests to use a git repository *in* the mock packages repo.
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def mock_pkg_git_repo(git, tmpdir_factory): def mock_pkg_git_repo(git, tmp_path_factory):
"""Copy the builtin.mock repo and make a mutable git repo inside it.""" """Copy the builtin.mock repo and make a mutable git repo inside it."""
tmproot = tmpdir_factory.mktemp("mock_pkg_git_repo") root_dir = tmp_path_factory.mktemp("mock_pkg_git_repo")
repo_path = tmproot.join("builtin.mock") repo_dir = root_dir / "builtin.mock"
shutil.copytree(spack.paths.mock_packages_path, str(repo_dir))
shutil.copytree(spack.paths.mock_packages_path, str(repo_path)) repo_cache = spack.util.file_cache.FileCache(str(root_dir / "cache"))
mock_repo = spack.repo.RepoPath(str(repo_path)) mock_repo = spack.repo.RepoPath(str(repo_dir), cache=repo_cache)
mock_repo_packages = mock_repo.repos[0].packages_path mock_repo_packages = mock_repo.repos[0].packages_path
with working_dir(mock_repo_packages): with working_dir(mock_repo_packages):
@@ -75,7 +77,7 @@ def mock_pkg_git_repo(git, tmpdir_factory):
git("rm", "-rf", "pkg-c") git("rm", "-rf", "pkg-c")
git("-c", "commit.gpgsign=false", "commit", "-m", "change pkg-b, remove pkg-c, add pkg-d") git("-c", "commit.gpgsign=false", "commit", "-m", "change pkg-b, remove pkg-c, add pkg-d")
with spack.repo.use_repositories(str(repo_path)): with spack.repo.use_repositories(str(repo_dir)):
yield mock_repo_packages yield mock_repo_packages

View File

@@ -38,7 +38,7 @@ def flake8_package(tmpdir):
change to the ``flake8`` mock package, yields the filename, then undoes the change to the ``flake8`` mock package, yields the filename, then undoes the
change on cleanup. change on cleanup.
""" """
repo = spack.repo.Repo(spack.paths.mock_packages_path) repo = spack.repo.from_path(spack.paths.mock_packages_path)
filename = repo.filename_for_package_name("flake8") filename = repo.filename_for_package_name("flake8")
rel_path = os.path.dirname(os.path.relpath(filename, spack.paths.prefix)) rel_path = os.path.dirname(os.path.relpath(filename, spack.paths.prefix))
tmp = tmpdir / rel_path / "flake8-ci-package.py" tmp = tmpdir / rel_path / "flake8-ci-package.py"
@@ -54,7 +54,7 @@ def flake8_package(tmpdir):
@pytest.fixture @pytest.fixture
def flake8_package_with_errors(scope="function"): def flake8_package_with_errors(scope="function"):
"""A flake8 package with errors.""" """A flake8 package with errors."""
repo = spack.repo.Repo(spack.paths.mock_packages_path) repo = spack.repo.from_path(spack.paths.mock_packages_path)
filename = repo.filename_for_package_name("flake8") filename = repo.filename_for_package_name("flake8")
tmp = filename + ".tmp" tmp = filename + ".tmp"
@@ -130,7 +130,7 @@ def test_changed_files_all_files():
assert os.path.join(spack.paths.module_path, "spec.py") in files assert os.path.join(spack.paths.module_path, "spec.py") in files
# a mock package # a mock package
repo = spack.repo.Repo(spack.paths.mock_packages_path) repo = spack.repo.from_path(spack.paths.mock_packages_path)
filename = repo.filename_for_package_name("flake8") filename = repo.filename_for_package_name("flake8")
assert filename in files assert filename in files

View File

@@ -24,6 +24,7 @@
import spack.platforms import spack.platforms
import spack.repo import spack.repo
import spack.solver.asp import spack.solver.asp
import spack.util.file_cache
import spack.util.libc import spack.util.libc
import spack.variant as vt import spack.variant as vt
from spack.concretize import find_spec from spack.concretize import find_spec
@@ -168,19 +169,18 @@ def reverser(pkg_name):
@pytest.fixture() @pytest.fixture()
def repo_with_changing_recipe(tmpdir_factory, mutable_mock_repo): def repo_with_changing_recipe(tmp_path_factory, mutable_mock_repo):
repo_namespace = "changing" repo_namespace = "changing"
repo_dir = tmpdir_factory.mktemp(repo_namespace) repo_dir = tmp_path_factory.mktemp(repo_namespace)
repo_dir.join("repo.yaml").write( (repo_dir / "repo.yaml").write_text(
""" """
repo: repo:
namespace: changing namespace: changing
""", """
ensure=True,
) )
packages_dir = repo_dir.ensure("packages", dir=True) packages_dir = repo_dir / "packages"
root_pkg_str = """ root_pkg_str = """
class Root(Package): class Root(Package):
homepage = "http://www.example.com" homepage = "http://www.example.com"
@@ -191,7 +191,9 @@ class Root(Package):
conflicts("^changing~foo") conflicts("^changing~foo")
""" """
packages_dir.join("root", "package.py").write(root_pkg_str, ensure=True) package_py = packages_dir / "root" / "package.py"
package_py.parent.mkdir(parents=True)
package_py.write_text(root_pkg_str)
changing_template = """ changing_template = """
class Changing(Package): class Changing(Package):
@@ -225,7 +227,9 @@ class _ChangingPackage:
def __init__(self, repo_directory): def __init__(self, repo_directory):
self.repo_dir = repo_directory self.repo_dir = repo_directory
self.repo = spack.repo.Repo(str(repo_directory)) cache_dir = tmp_path_factory.mktemp("cache")
self.repo_cache = spack.util.file_cache.FileCache(str(cache_dir))
self.repo = spack.repo.Repo(str(repo_directory), cache=self.repo_cache)
def change(self, changes=None): def change(self, changes=None):
changes = changes or {} changes = changes or {}
@@ -246,10 +250,12 @@ def change(self, changes=None):
# Change the recipe # Change the recipe
t = jinja2.Template(changing_template) t = jinja2.Template(changing_template)
changing_pkg_str = t.render(**context) changing_pkg_str = t.render(**context)
packages_dir.join("changing", "package.py").write(changing_pkg_str, ensure=True) package_py = packages_dir / "changing" / "package.py"
package_py.parent.mkdir(parents=True, exist_ok=True)
package_py.write_text(changing_pkg_str)
# Re-add the repository # Re-add the repository
self.repo = spack.repo.Repo(str(self.repo_dir)) self.repo = spack.repo.Repo(str(self.repo_dir), cache=self.repo_cache)
repository.put_first(self.repo) repository.put_first(self.repo)
_changing_pkg = _ChangingPackage(repo_dir) _changing_pkg = _ChangingPackage(repo_dir)

View File

@@ -161,21 +161,24 @@ def test_preferred_providers(self):
spec = concretize("mpileaks") spec = concretize("mpileaks")
assert "zmpi" in spec assert "zmpi" in spec
def test_config_set_pkg_property_url(self, mutable_mock_repo): @pytest.mark.parametrize(
"update,expected",
[
(
{"url": "http://www.somewhereelse.com/mpileaks-1.0.tar.gz"},
"http://www.somewhereelse.com/mpileaks-2.3.tar.gz",
),
({}, "http://www.llnl.gov/mpileaks-2.3.tar.gz"),
],
)
def test_config_set_pkg_property_url(self, update, expected, mock_repo_path):
"""Test setting an existing attribute in the package class""" """Test setting an existing attribute in the package class"""
update_packages( update_packages("mpileaks", "package_attributes", update)
"mpileaks", with spack.repo.use_repositories(mock_repo_path):
"package_attributes", spec = concretize("mpileaks")
{"url": "http://www.somewhereelse.com/mpileaks-1.0.tar.gz"}, assert spec.package.fetcher.url == expected
)
spec = concretize("mpileaks")
assert spec.package.fetcher.url == "http://www.somewhereelse.com/mpileaks-2.3.tar.gz"
update_packages("mpileaks", "package_attributes", {}) def test_config_set_pkg_property_new(self, mock_repo_path):
spec = concretize("mpileaks")
assert spec.package.fetcher.url == "http://www.llnl.gov/mpileaks-2.3.tar.gz"
def test_config_set_pkg_property_new(self, mutable_mock_repo):
"""Test that you can set arbitrary attributes on the Package class""" """Test that you can set arbitrary attributes on the Package class"""
conf = syaml.load_config( conf = syaml.load_config(
"""\ """\
@@ -194,19 +197,20 @@ def test_config_set_pkg_property_new(self, mutable_mock_repo):
""" """
) )
spack.config.set("packages", conf, scope="concretize") spack.config.set("packages", conf, scope="concretize")
with spack.repo.use_repositories(mock_repo_path):
spec = concretize("mpileaks") spec = concretize("mpileaks")
assert spec.package.v1 == 1 assert spec.package.v1 == 1
assert spec.package.v2 is True assert spec.package.v2 is True
assert spec.package.v3 == "yesterday" assert spec.package.v3 == "yesterday"
assert spec.package.v4 == "true" assert spec.package.v4 == "true"
assert dict(spec.package.v5) == {"x": 1, "y": 2} assert dict(spec.package.v5) == {"x": 1, "y": 2}
assert list(spec.package.v6) == [1, 2] assert list(spec.package.v6) == [1, 2]
update_packages("mpileaks", "package_attributes", {}) update_packages("mpileaks", "package_attributes", {})
spec = concretize("mpileaks") with spack.repo.use_repositories(mock_repo_path):
with pytest.raises(AttributeError): spec = concretize("mpileaks")
spec.package.v1 with pytest.raises(AttributeError):
spec.package.v1
def test_preferred(self): def test_preferred(self):
""" "Test packages with some version marked as preferred=True""" """ "Test packages with some version marked as preferred=True"""

View File

@@ -774,7 +774,7 @@ def test_keys_are_ordered(configuration_dir):
"./", "./",
) )
config_scope = spack.config.ConfigScope("modules", configuration_dir.join("site")) config_scope = spack.config.DirectoryConfigScope("modules", configuration_dir.join("site"))
data = config_scope.get_section("modules") data = config_scope.get_section("modules")
@@ -956,7 +956,7 @@ def test_immutable_scope(tmpdir):
root: dummy_tree_value root: dummy_tree_value
""" """
) )
scope = spack.config.ImmutableConfigScope("test", str(tmpdir)) scope = spack.config.DirectoryConfigScope("test", str(tmpdir), writable=False)
data = scope.get_section("config") data = scope.get_section("config")
assert data["config"]["install_tree"] == {"root": "dummy_tree_value"} assert data["config"]["install_tree"] == {"root": "dummy_tree_value"}
@@ -966,7 +966,9 @@ def test_immutable_scope(tmpdir):
def test_single_file_scope(config, env_yaml): def test_single_file_scope(config, env_yaml):
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"]) scope = spack.config.SingleFileScope(
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
)
with spack.config.override(scope): with spack.config.override(scope):
# from the single-file config # from the single-file config
@@ -1002,7 +1004,9 @@ def test_single_file_scope_section_override(tmpdir, config):
""" """
) )
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"]) scope = spack.config.SingleFileScope(
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
)
with spack.config.override(scope): with spack.config.override(scope):
# from the single-file config # from the single-file config
@@ -1018,7 +1022,7 @@ def test_single_file_scope_section_override(tmpdir, config):
def test_write_empty_single_file_scope(tmpdir): def test_write_empty_single_file_scope(tmpdir):
env_schema = spack.schema.env.schema env_schema = spack.schema.env.schema
scope = spack.config.SingleFileScope( scope = spack.config.SingleFileScope(
"test", str(tmpdir.ensure("config.yaml")), env_schema, ["spack"] "test", str(tmpdir.ensure("config.yaml")), env_schema, yaml_path=["spack"]
) )
scope._write_section("config") scope._write_section("config")
# confirm we can write empty config # confirm we can write empty config
@@ -1217,7 +1221,9 @@ def test_license_dir_config(mutable_config, mock_packages):
@pytest.mark.regression("22547") @pytest.mark.regression("22547")
def test_single_file_scope_cache_clearing(env_yaml): def test_single_file_scope_cache_clearing(env_yaml):
scope = spack.config.SingleFileScope("env", env_yaml, spack.schema.env.schema, ["spack"]) scope = spack.config.SingleFileScope(
"env", env_yaml, spack.schema.env.schema, yaml_path=["spack"]
)
# Check that we can retrieve data from the single file scope # Check that we can retrieve data from the single file scope
before = scope.get_section("config") before = scope.get_section("config")
assert before assert before

View File

@@ -561,7 +561,7 @@ def _use_test_platform(test_platform):
# #
@pytest.fixture(scope="session") @pytest.fixture(scope="session")
def mock_repo_path(): def mock_repo_path():
yield spack.repo.Repo(spack.paths.mock_packages_path) yield spack.repo.from_path(spack.paths.mock_packages_path)
def _pkg_install_fn(pkg, spec, prefix): def _pkg_install_fn(pkg, spec, prefix):
@@ -588,7 +588,7 @@ def mock_packages(mock_repo_path, mock_pkg_install, request):
def mutable_mock_repo(mock_repo_path, request): def mutable_mock_repo(mock_repo_path, request):
"""Function-scoped mock packages, for tests that need to modify them.""" """Function-scoped mock packages, for tests that need to modify them."""
ensure_configuration_fixture_run_before(request) ensure_configuration_fixture_run_before(request)
mock_repo = spack.repo.Repo(spack.paths.mock_packages_path) mock_repo = spack.repo.from_path(spack.paths.mock_packages_path)
with spack.repo.use_repositories(mock_repo) as mock_repo_path: with spack.repo.use_repositories(mock_repo) as mock_repo_path:
yield mock_repo_path yield mock_repo_path
@@ -719,9 +719,9 @@ def _create_mock_configuration_scopes(configuration_dir):
"""Create the configuration scopes used in `config` and `mutable_config`.""" """Create the configuration scopes used in `config` and `mutable_config`."""
return [ return [
spack.config.InternalConfigScope("_builtin", spack.config.CONFIG_DEFAULTS), spack.config.InternalConfigScope("_builtin", spack.config.CONFIG_DEFAULTS),
spack.config.ConfigScope("site", str(configuration_dir.join("site"))), spack.config.DirectoryConfigScope("site", str(configuration_dir.join("site"))),
spack.config.ConfigScope("system", str(configuration_dir.join("system"))), spack.config.DirectoryConfigScope("system", str(configuration_dir.join("system"))),
spack.config.ConfigScope("user", str(configuration_dir.join("user"))), spack.config.DirectoryConfigScope("user", str(configuration_dir.join("user"))),
spack.config.InternalConfigScope("command_line"), spack.config.InternalConfigScope("command_line"),
] ]
@@ -755,7 +755,7 @@ def mutable_empty_config(tmpdir_factory, configuration_dir):
"""Empty configuration that can be modified by the tests.""" """Empty configuration that can be modified by the tests."""
mutable_dir = tmpdir_factory.mktemp("mutable_config").join("tmp") mutable_dir = tmpdir_factory.mktemp("mutable_config").join("tmp")
scopes = [ scopes = [
spack.config.ConfigScope(name, str(mutable_dir.join(name))) spack.config.DirectoryConfigScope(name, str(mutable_dir.join(name)))
for name in ["site", "system", "user"] for name in ["site", "system", "user"]
] ]
@@ -790,7 +790,7 @@ def concretize_scope(mutable_config, tmpdir):
"""Adds a scope for concretization preferences""" """Adds a scope for concretization preferences"""
tmpdir.ensure_dir("concretize") tmpdir.ensure_dir("concretize")
mutable_config.push_scope( mutable_config.push_scope(
spack.config.ConfigScope("concretize", str(tmpdir.join("concretize"))) spack.config.DirectoryConfigScope("concretize", str(tmpdir.join("concretize")))
) )
yield str(tmpdir.join("concretize")) yield str(tmpdir.join("concretize"))
@@ -802,10 +802,10 @@ def concretize_scope(mutable_config, tmpdir):
@pytest.fixture @pytest.fixture
def no_compilers_yaml(mutable_config): def no_compilers_yaml(mutable_config):
"""Creates a temporary configuration without compilers.yaml""" """Creates a temporary configuration without compilers.yaml"""
for scope, local_config in mutable_config.scopes.items(): for local_config in mutable_config.scopes.values():
if not local_config.path: # skip internal scopes if not isinstance(local_config, spack.config.DirectoryConfigScope):
continue continue
compilers_yaml = os.path.join(local_config.path, "compilers.yaml") compilers_yaml = local_config.get_section_filename("compilers")
if os.path.exists(compilers_yaml): if os.path.exists(compilers_yaml):
os.remove(compilers_yaml) os.remove(compilers_yaml)
return mutable_config return mutable_config
@@ -814,7 +814,9 @@ def no_compilers_yaml(mutable_config):
@pytest.fixture() @pytest.fixture()
def mock_low_high_config(tmpdir): def mock_low_high_config(tmpdir):
"""Mocks two configuration scopes: 'low' and 'high'.""" """Mocks two configuration scopes: 'low' and 'high'."""
scopes = [spack.config.ConfigScope(name, str(tmpdir.join(name))) for name in ["low", "high"]] scopes = [
spack.config.DirectoryConfigScope(name, str(tmpdir.join(name))) for name in ["low", "high"]
]
with spack.config.use_configuration(*scopes) as config: with spack.config.use_configuration(*scopes) as config:
yield config yield config
@@ -2019,7 +2021,8 @@ def create_test_repo(tmpdir, pkg_name_content_tuples):
with open(str(pkg_file), "w") as f: with open(str(pkg_file), "w") as f:
f.write(pkg_str) f.write(pkg_str)
return spack.repo.Repo(repo_path) repo_cache = spack.util.file_cache.FileCache(str(tmpdir.join("cache")))
return spack.repo.Repo(repo_path, cache=repo_cache)
@pytest.fixture() @pytest.fixture()
@@ -2061,3 +2064,9 @@ def _c_compiler_always_exists():
spack.solver.asp.c_compiler_runs = _true spack.solver.asp.c_compiler_runs = _true
yield yield
spack.solver.asp.c_compiler_runs = fn spack.solver.asp.c_compiler_runs = fn
@pytest.fixture(scope="session")
def mock_test_cache(tmp_path_factory):
cache_dir = tmp_path_factory.mktemp("cache")
return spack.util.file_cache.FileCache(str(cache_dir))

View File

@@ -146,7 +146,7 @@ def test_read_and_write_spec(temporary_store, config, mock_packages):
assert not os.path.exists(install_dir) assert not os.path.exists(install_dir)
def test_handle_unknown_package(temporary_store, config, mock_packages): def test_handle_unknown_package(temporary_store, config, mock_packages, tmp_path):
"""This test ensures that spack can at least do *some* """This test ensures that spack can at least do *some*
operations with packages that are installed but that it operations with packages that are installed but that it
does not know about. This is actually not such an uncommon does not know about. This is actually not such an uncommon
@@ -158,7 +158,9 @@ def test_handle_unknown_package(temporary_store, config, mock_packages):
or query them again if the package goes away. or query them again if the package goes away.
""" """
layout = temporary_store.layout layout = temporary_store.layout
mock_db = spack.repo.RepoPath(spack.paths.mock_packages_path)
repo_cache = spack.util.file_cache.FileCache(str(tmp_path / "cache"))
mock_db = spack.repo.RepoPath(spack.paths.mock_packages_path, cache=repo_cache)
not_in_mock = set.difference( not_in_mock = set.difference(
set(spack.repo.all_package_names()), set(mock_db.all_package_names()) set(spack.repo.all_package_names()), set(mock_db.all_package_names())

View File

@@ -32,12 +32,12 @@ def test_package_name(self):
assert pkg_cls.name == "mpich" assert pkg_cls.name == "mpich"
def test_package_filename(self): def test_package_filename(self):
repo = spack.repo.Repo(mock_packages_path) repo = spack.repo.from_path(mock_packages_path)
filename = repo.filename_for_package_name("mpich") filename = repo.filename_for_package_name("mpich")
assert filename == os.path.join(mock_packages_path, "packages", "mpich", "package.py") assert filename == os.path.join(mock_packages_path, "packages", "mpich", "package.py")
def test_nonexisting_package_filename(self): def test_nonexisting_package_filename(self):
repo = spack.repo.Repo(mock_packages_path) repo = spack.repo.from_path(mock_packages_path)
filename = repo.filename_for_package_name("some-nonexisting-package") filename = repo.filename_for_package_name("some-nonexisting-package")
assert filename == os.path.join( assert filename == os.path.join(
mock_packages_path, "packages", "some-nonexisting-package", "package.py" mock_packages_path, "packages", "some-nonexisting-package", "package.py"

View File

@@ -12,21 +12,28 @@
@pytest.fixture(params=["packages", "", "foo"]) @pytest.fixture(params=["packages", "", "foo"])
def extra_repo(tmpdir_factory, request): def extra_repo(tmp_path_factory, request):
repo_namespace = "extra_test_repo" repo_namespace = "extra_test_repo"
repo_dir = tmpdir_factory.mktemp(repo_namespace) repo_dir = tmp_path_factory.mktemp(repo_namespace)
repo_dir.ensure(request.param, dir=True) cache_dir = tmp_path_factory.mktemp("cache")
(repo_dir / request.param).mkdir(parents=True, exist_ok=True)
with open(str(repo_dir.join("repo.yaml")), "w") as f: if request.param == "packages":
f.write( (repo_dir / "repo.yaml").write_text(
""" """
repo: repo:
namespace: extra_test_repo namespace: extra_test_repo
""" """
) )
if request.param != "packages": else:
f.write(f" subdirectory: '{request.param}'") (repo_dir / "repo.yaml").write_text(
return (spack.repo.Repo(str(repo_dir)), request.param) f"""
repo:
namespace: extra_test_repo
subdirectory: '{request.param}'
"""
)
repo_cache = spack.util.file_cache.FileCache(str(cache_dir))
return spack.repo.Repo(str(repo_dir), cache=repo_cache), request.param
def test_repo_getpkg(mutable_mock_repo): def test_repo_getpkg(mutable_mock_repo):
@@ -177,8 +184,11 @@ def test_repo_dump_virtuals(tmpdir, mutable_mock_repo, mock_packages, ensure_deb
([spack.paths.mock_packages_path, spack.paths.packages_path], ["builtin.mock", "builtin"]), ([spack.paths.mock_packages_path, spack.paths.packages_path], ["builtin.mock", "builtin"]),
], ],
) )
def test_repository_construction_doesnt_use_globals(nullify_globals, repo_paths, namespaces): def test_repository_construction_doesnt_use_globals(
repo_path = spack.repo.RepoPath(*repo_paths) nullify_globals, tmp_path, repo_paths, namespaces
):
repo_cache = spack.util.file_cache.FileCache(str(tmp_path / "cache"))
repo_path = spack.repo.RepoPath(*repo_paths, cache=repo_cache)
assert len(repo_path.repos) == len(namespaces) assert len(repo_path.repos) == len(namespaces)
assert [x.namespace for x in repo_path.repos] == namespaces assert [x.namespace for x in repo_path.repos] == namespaces
@@ -188,8 +198,84 @@ def test_path_computation_with_names(method_name, mock_repo_path):
"""Tests that repositories can compute the correct paths when using both fully qualified """Tests that repositories can compute the correct paths when using both fully qualified
names and unqualified names. names and unqualified names.
""" """
repo_path = spack.repo.RepoPath(mock_repo_path) repo_path = spack.repo.RepoPath(mock_repo_path, cache=None)
method = getattr(repo_path, method_name) method = getattr(repo_path, method_name)
unqualified = method("mpileaks") unqualified = method("mpileaks")
qualified = method("builtin.mock.mpileaks") qualified = method("builtin.mock.mpileaks")
assert qualified == unqualified assert qualified == unqualified
@pytest.mark.usefixtures("nullify_globals")
class TestRepo:
"""Test that the Repo class work correctly, and does not depend on globals,
except the REPOS_FINDER.
"""
def test_creation(self, mock_test_cache):
repo = spack.repo.Repo(spack.paths.mock_packages_path, cache=mock_test_cache)
assert repo.config_file.endswith("repo.yaml")
assert repo.namespace == "builtin.mock"
@pytest.mark.parametrize(
"name,expected", [("mpi", True), ("mpich", False), ("mpileaks", False)]
)
def test_is_virtual(self, name, expected, mock_test_cache):
repo = spack.repo.Repo(spack.paths.mock_packages_path, cache=mock_test_cache)
assert repo.is_virtual(name) is expected
assert repo.is_virtual_safe(name) is expected
@pytest.mark.parametrize(
"module_name,expected",
[
("dla_future", "dla-future"),
("num7zip", "7zip"),
# If no package is there, None is returned
("unknown", None),
],
)
def test_real_name(self, module_name, expected, mock_test_cache):
"""Test that we can correctly compute the 'real' name of a package, from the one
used to import the Python module.
"""
repo = spack.repo.Repo(spack.paths.mock_packages_path, cache=mock_test_cache)
assert repo.real_name(module_name) == expected
@pytest.mark.parametrize("name", ["mpileaks", "7zip", "dla-future"])
def test_get(self, name, mock_test_cache):
repo = spack.repo.Repo(spack.paths.mock_packages_path, cache=mock_test_cache)
mock_spec = spack.spec.Spec(name)
mock_spec._mark_concrete()
pkg = repo.get(mock_spec)
assert pkg.__class__ == repo.get_pkg_class(name)
@pytest.mark.parametrize("virtual_name,expected", [("mpi", ["mpich", "zmpi"])])
def test_providers(self, virtual_name, expected, mock_test_cache):
repo = spack.repo.Repo(spack.paths.mock_packages_path, cache=mock_test_cache)
provider_names = {x.name for x in repo.providers_for(virtual_name)}
assert provider_names.issuperset(expected)
@pytest.mark.parametrize(
"extended,expected",
[("python", ["py-extension1", "python-venv"]), ("perl", ["perl-extension"])],
)
def test_extensions(self, extended, expected, mock_test_cache):
repo = spack.repo.Repo(spack.paths.mock_packages_path, cache=mock_test_cache)
provider_names = {x.name for x in repo.extensions_for(extended)}
assert provider_names.issuperset(expected)
def test_all_package_names(self, mock_test_cache):
repo = spack.repo.Repo(spack.paths.mock_packages_path, cache=mock_test_cache)
all_names = repo.all_package_names(include_virtuals=True)
real_names = repo.all_package_names(include_virtuals=False)
assert set(all_names).issuperset(real_names)
for name in set(all_names) - set(real_names):
assert repo.is_virtual(name)
assert repo.is_virtual_safe(name)
def test_packages_with_tags(self, mock_test_cache):
repo = spack.repo.Repo(spack.paths.mock_packages_path, cache=mock_test_cache)
r1 = repo.packages_with_tags("tag1")
r2 = repo.packages_with_tags("tag1", "tag2")
assert "mpich" in r1 and "mpich" in r2
assert "mpich2" in r1 and "mpich2" not in r2
assert set(r2).issubset(r1)

View File

@@ -0,0 +1,14 @@
# Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
# Spack Project Developers. See the top-level COPYRIGHT file for details.
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
from spack.package import *
class _7zip(AutotoolsPackage):
"""Simple package with a name starting with a digit"""
homepage = "http://www.example.com"
url = "http://www.example.com/a-1.0.tar.gz"
version("1.0", md5="0123456789abcdef0123456789abcdef")

View File

@@ -12,7 +12,7 @@ class ActsDd4hep(CMakePackage):
homepage = "https://github.com/acts-project/acts-dd4hep" homepage = "https://github.com/acts-project/acts-dd4hep"
url = "https://github.com/acts-project/acts-dd4hep/archive/refs/tags/v1.0.0.tar.gz" url = "https://github.com/acts-project/acts-dd4hep/archive/refs/tags/v1.0.0.tar.gz"
maintainers("HadrienG2", "wdconinc") maintainers("wdconinc")
version("1.0.1", sha256="e40f34ebc30b3c33a6802c9d94136e65072d8dcee0b7db57a645f08a64ea5334") version("1.0.1", sha256="e40f34ebc30b3c33a6802c9d94136e65072d8dcee0b7db57a645f08a64ea5334")
version("1.0.0", sha256="991f996944c88efa837880f919239e50d12c5c9361e220bc9422438dd608308c") version("1.0.0", sha256="991f996944c88efa837880f919239e50d12c5c9361e220bc9422438dd608308c")

View File

@@ -33,7 +33,7 @@ class Acts(CMakePackage, CudaPackage):
homepage = "https://acts.web.cern.ch/ACTS/" homepage = "https://acts.web.cern.ch/ACTS/"
git = "https://github.com/acts-project/acts.git" git = "https://github.com/acts-project/acts.git"
list_url = "https://github.com/acts-project/acts/releases/" list_url = "https://github.com/acts-project/acts/releases/"
maintainers("HadrienG2") maintainers("wdconinc")
tags = ["hep"] tags = ["hep"]

View File

@@ -16,7 +16,7 @@ class Actsvg(CMakePackage):
list_url = "https://github.com/acts-project/actsvg/tags" list_url = "https://github.com/acts-project/actsvg/tags"
git = "https://github.com/acts-project/actsvg.git" git = "https://github.com/acts-project/actsvg.git"
maintainers("HadrienG2", "wdconinc", "stephenswat") maintainers("wdconinc", "stephenswat")
license("MPL-2.0") license("MPL-2.0")

View File

@@ -14,7 +14,7 @@ class Autodiff(CMakePackage):
list_url = "https://github.com/autodiff/autodiff/tags" list_url = "https://github.com/autodiff/autodiff/tags"
git = "https://github.com/autodiff/autodiff.git" git = "https://github.com/autodiff/autodiff.git"
maintainers("wdconinc", "HadrienG2") maintainers("wdconinc")
license("MIT") license("MIT")

View File

@@ -26,7 +26,7 @@ class Gmsh(CMakePackage):
version("master", branch="master") version("master", branch="master")
version("4.13.1", sha256="77972145f431726026d50596a6a44fb3c1c95c21255218d66955806b86edbe8d") version("4.13.1", sha256="77972145f431726026d50596a6a44fb3c1c95c21255218d66955806b86edbe8d")
version("4.13.0", sha256="c85f056ee549a433e814a61c385c97952bbfe514b442b999f6149fffb1e54f64.") version("4.13.0", sha256="c85f056ee549a433e814a61c385c97952bbfe514b442b999f6149fffb1e54f64")
version("4.12.2", sha256="13e09d9ca8102e5c40171d6ee150c668742b98c3a6ca57f837f7b64e1e2af48f") version("4.12.2", sha256="13e09d9ca8102e5c40171d6ee150c668742b98c3a6ca57f837f7b64e1e2af48f")
version("4.12.0", sha256="2a6007872ba85abd9901914826f6986a2437ab7104f564ccefa1b7a3de742c17") version("4.12.0", sha256="2a6007872ba85abd9901914826f6986a2437ab7104f564ccefa1b7a3de742c17")
version("4.11.1", sha256="c5fe1b7cbd403888a814929f2fd0f5d69e27600222a18c786db5b76e8005b365") version("4.11.1", sha256="c5fe1b7cbd403888a814929f2fd0f5d69e27600222a18c786db5b76e8005b365")

View File

@@ -11,17 +11,30 @@ class PyFlashAttn(PythonPackage):
This package provides the official implementation of FlashAttention. This package provides the official implementation of FlashAttention.
""" """
pypi = "flash-attn/flash_attn-2.5.4.tar.gz" homepage = "https://github.com/Dao-AILab/flash-attention.git"
pypi = "flash-attn/flash_attn-0.0.0.tar.gz"
git = "https://github.com/Dao-AILab/flash-attention.git"
maintainers("aurianer") maintainers("aurianer")
license("BSD") license("BSD")
version("main", branch="main")
version(
"2.5.9.post1", sha256="a92db1683a5b141a0f4371d251ae9f73e9aef629b3a58a50d0ef430266c68782"
)
version("2.5.8", sha256="2e5b2bcff6d5cff40d494af91ecd1eb3c5b4520a6ce7a0a8b1f9c1ed129fb402")
version("2.5.7", sha256="7c079aef4e77c4e9a71a3cd88662362e0fe82f658db0b2dbff6f279de2a387a8")
version("2.5.6", sha256="d25801aa060877cad997939bd7130faf620fdbeda947c3ffde5865906d430c36")
version("2.5.5", sha256="751cee17711d006fe7341cdd78584af86a6239afcfe43b9ed11c84db93126267") version("2.5.5", sha256="751cee17711d006fe7341cdd78584af86a6239afcfe43b9ed11c84db93126267")
version("2.5.4", sha256="d83bb427b517b07e9db655f6e5166eb2607dccf4d6ca3229e3a3528c206b0175") version("2.5.4", sha256="d83bb427b517b07e9db655f6e5166eb2607dccf4d6ca3229e3a3528c206b0175")
version("2.4.2", sha256="eb822a8c4219b610e9d734cbc8cd9ee4547f27433815a2b90dc1462766feefc1") version("2.4.2", sha256="eb822a8c4219b610e9d734cbc8cd9ee4547f27433815a2b90dc1462766feefc1")
depends_on("py-setuptools", type="build") with default_args(type="build"):
depends_on("py-ninja")
depends_on("py-packaging")
depends_on("py-psutil")
depends_on("py-setuptools")
with default_args(type=("build", "run")): with default_args(type=("build", "run")):
depends_on("py-torch+cuda") depends_on("py-torch+cuda")
@@ -32,6 +45,4 @@ class PyFlashAttn(PythonPackage):
with default_args(type=("build", "link", "run")): with default_args(type=("build", "link", "run")):
depends_on("py-pybind11") depends_on("py-pybind11")
depends_on("py-psutil", type="build")
depends_on("python@3.7:", type=("build", "run")) depends_on("python@3.7:", type=("build", "run"))

View File

@@ -12,7 +12,9 @@ class PySafetensors(PythonPackage):
homepage = "https://github.com/huggingface/safetensors" homepage = "https://github.com/huggingface/safetensors"
pypi = "safetensors/safetensors-0.3.1.tar.gz" pypi = "safetensors/safetensors-0.3.1.tar.gz"
version("0.4.3", sha256="2f85fc50c4e07a21e95c24e07460fe6f7e2859d0ce88092838352b798ce711c2")
version("0.3.1", sha256="571da56ff8d0bec8ae54923b621cda98d36dcef10feb36fd492c4d0c2cd0e869") version("0.3.1", sha256="571da56ff8d0bec8ae54923b621cda98d36dcef10feb36fd492c4d0c2cd0e869")
depends_on("py-setuptools", type="build") depends_on("py-setuptools", type="build")
depends_on("py-setuptools-rust", type="build") depends_on("py-setuptools-rust", type="build")
depends_on("py-maturin", type="build", when="@0.4.3")

View File

@@ -13,6 +13,7 @@ class PyTokenizers(PythonPackage):
homepage = "https://github.com/huggingface/tokenizers" homepage = "https://github.com/huggingface/tokenizers"
pypi = "tokenizers/tokenizers-0.6.0.tar.gz" pypi = "tokenizers/tokenizers-0.6.0.tar.gz"
version("0.19.1", sha256="ee59e6680ed0fdbe6b724cf38bd70400a0c1dd623b07ac729087270caeac88e3")
version("0.15.0", sha256="10c7e6e7b4cabd757da59e93f5f8d1126291d16f8b54f28510825ef56a3e5d0e") version("0.15.0", sha256="10c7e6e7b4cabd757da59e93f5f8d1126291d16f8b54f28510825ef56a3e5d0e")
version("0.13.3", sha256="2e546dbb68b623008a5442353137fbb0123d311a6d7ba52f2667c8862a75af2e") version("0.13.3", sha256="2e546dbb68b623008a5442353137fbb0123d311a6d7ba52f2667c8862a75af2e")
version("0.13.1", sha256="3333d1cee5c8f47c96362ea0abc1f81c77c9b92c6c3d11cbf1d01985f0d5cf1d") version("0.13.1", sha256="3333d1cee5c8f47c96362ea0abc1f81c77c9b92c6c3d11cbf1d01985f0d5cf1d")

View File

@@ -18,33 +18,42 @@ class PyTransformers(PythonPackage):
license("Apache-2.0") license("Apache-2.0")
version("4.42.3", sha256="7539873ff45809145265cbc94ea4619d2713c41ceaa277b692d8b0be3430f7eb")
version("4.38.1", sha256="86dc84ccbe36123647e84cbd50fc31618c109a41e6be92514b064ab55bf1304c")
version("4.35.2", sha256="2d125e197d77b0cdb6c9201df9fa7e2101493272e448b9fba9341c695bee2f52") version("4.35.2", sha256="2d125e197d77b0cdb6c9201df9fa7e2101493272e448b9fba9341c695bee2f52")
version("4.31.0", sha256="4302fba920a1c24d3a429a29efff6a63eac03f3f3cf55b55927fc795d01cb273") version("4.31.0", sha256="4302fba920a1c24d3a429a29efff6a63eac03f3f3cf55b55927fc795d01cb273")
version("4.24.0", sha256="486f353a8e594002e48be0e2aba723d96eda839e63bfe274702a4b5eda85559b") version("4.24.0", sha256="486f353a8e594002e48be0e2aba723d96eda839e63bfe274702a4b5eda85559b")
version("4.6.1", sha256="83dbff763b7e7dc57cbef1a6b849655d4fcab6bffdd955c5e8bea12a4f76dc10") version("4.6.1", sha256="83dbff763b7e7dc57cbef1a6b849655d4fcab6bffdd955c5e8bea12a4f76dc10")
version("2.8.0", sha256="b9f29cdfd39c28f29e0806c321270dea337d6174a7aa60daf9625bf83dbb12ee") version("2.8.0", sha256="b9f29cdfd39c28f29e0806c321270dea337d6174a7aa60daf9625bf83dbb12ee")
depends_on("py-setuptools", type="build") with default_args(type="build"):
depends_on("py-filelock", type=("build", "run")) depends_on("py-setuptools")
depends_on("py-huggingface-hub@0.16.4:0", when="@4.34:", type=("build", "run"))
depends_on("py-huggingface-hub@0.14.1:0", when="@4.26:", type=("build", "run"))
depends_on("py-huggingface-hub@0.10:0", when="@4.24:", type=("build", "run"))
depends_on("py-huggingface-hub@0.0.8", when="@4.6.1", type=("build", "run"))
depends_on("py-numpy@1.17:", when="@4.6:", type=("build", "run"))
depends_on("py-numpy", type=("build", "run"))
depends_on("py-packaging@20:", when="@4.24:", type=("build", "run"))
depends_on("py-packaging", when="@4.6.1", type=("build", "run"))
depends_on("py-pyyaml@5.1:", when="@4.24:", type=("build", "run"))
depends_on("py-regex@:2019.12.16,2019.12.18:", type=("build", "run"))
depends_on("py-requests", type=("build", "run"))
depends_on("py-safetensors@0.3.1:", when="@4.31:", type=("build", "run"))
depends_on("py-tokenizers@0.14:0.18", when="@4.35:", type=("build", "run"))
depends_on("py-tokenizers@0.11.1:0.11.2,0.11.4:0.13", when="@4.24:4.33", type=("build", "run"))
depends_on("py-tokenizers@0.10.1:0.10", when="@4.6.1", type=("build", "run"))
depends_on("py-tokenizers@0.5.2", when="@2.8.0", type=("build", "run"))
depends_on("py-tqdm@4.27:", type=("build", "run"))
# Historical requirements with default_args(type=("build", "run")):
depends_on("py-sacremoses", when="@:4.6", type=("build", "run")) depends_on("py-filelock")
depends_on("py-boto3", when="@2.8.0", type=("build", "run")) depends_on("py-huggingface-hub@0.23.2:", when="@4.42.3:")
depends_on("py-sentencepiece", when="@2.8.0", type=("build", "run")) depends_on("py-huggingface-hub@0.19.3:", when="@4.38.1:")
depends_on("py-huggingface-hub@0.16.4:0", when="@4.34:")
depends_on("py-huggingface-hub@0.14.1:0", when="@4.26:")
depends_on("py-huggingface-hub@0.10:0", when="@4.24:")
depends_on("py-huggingface-hub@0.0.8", when="@4.6.1")
depends_on("py-numpy@1.17:", when="@4.6:")
depends_on("py-numpy")
depends_on("py-packaging@20:", when="@4.24:")
depends_on("py-packaging", when="@4.6.1")
depends_on("py-pyyaml@5.1:", when="@4.24:")
depends_on("py-regex@:2019.12.16,2019.12.18:")
depends_on("py-requests")
depends_on("py-safetensors@0.4.1:", when="@4.38.1:")
depends_on("py-safetensors@0.3.1:", when="@4.31:")
depends_on("py-tokenizers@0.19", when="@4.40.0:")
depends_on("py-tokenizers@0.14:0.18", when="@4.35:4.39.3")
depends_on("py-tokenizers@0.11.1:0.11.2,0.11.4:0.13", when="@4.24:4.33")
depends_on("py-tokenizers@0.10.1:0.10", when="@4.6.1")
depends_on("py-tokenizers@0.5.2", when="@2.8.0")
depends_on("py-tqdm@4.27:")
# Historical requirements
depends_on("py-sacremoses", when="@:4.6")
depends_on("py-boto3", when="@2.8.0")
depends_on("py-sentencepiece", when="@2.8.0")

View File

@@ -22,9 +22,7 @@ class Root(CMakePackage):
tags = ["hep"] tags = ["hep"]
maintainers( maintainers("drbenmorgan", "gartung", "greenc-FNAL", "marcmengel", "vitodb", "vvolkl")
"drbenmorgan", "gartung", "greenc-FNAL", "HadrienG2", "marcmengel", "vitodb", "vvolkl"
)
# ###################### Versions ########################## # ###################### Versions ##########################

View File

@@ -45,19 +45,39 @@ class UtilLinux(AutotoolsPackage):
depends_on("libxcrypt", type="link") # sbin/sulogin depends_on("libxcrypt", type="link") # sbin/sulogin
variant("bash", default=False, description="Install bash completion scripts") variant("bash", default=False, description="Install bash completion scripts")
variant("uuid", default=False, description="Build libuuid and uuid utilities")
depends_on("bash", when="+bash", type="run") depends_on("bash", when="+bash", type="run")
depends_on("pkgconfig", when="+uuid", type="build")
# TODO likely applies regardless of uuid
conflicts("%gcc@:4", when="@2.37: +uuid")
provides("uuid", when="+uuid")
def url_for_version(self, version): def url_for_version(self, version):
url = "https://www.kernel.org/pub/linux/utils/util-linux/v{0}/util-linux-{1}.tar.gz" url = "https://www.kernel.org/pub/linux/utils/util-linux/v{0}/util-linux-{1}.tar.gz"
return url.format(version.up_to(2), version) return url.format(version.up_to(2), version)
# TODO does not appear used by builtin packages
# TODO does when=[virtual=uuid] work?
@property
@when("[virtual=uuid]")
def libs(self):
return find_libraries("libuuid", self.prefix, recursive=True)
# TODO does not appear used by builtin packages
# TODO does when=[virtual=uuid] work?
@property
@when("[virtual=uuid]")
def headers(self):
return find_headers("uuid", self.prefix, recursive=True)
def configure_args(self): def configure_args(self):
config_args = [ config_args = [
"--disable-use-tty-group", "--disable-use-tty-group",
"--disable-makeinstall-chown", "--disable-makeinstall-chown",
"--without-systemd", "--without-systemd",
"--disable-libuuid",
] ]
if "+bash" in self.spec: if "+bash" in self.spec:
config_args.extend( config_args.extend(
@@ -72,6 +92,11 @@ def configure_args(self):
else: else:
config_args.append("--disable-bash-completion") config_args.append("--disable-bash-completion")
if self.spec.satisfied("+uuid"):
config_args.append("--enable-libuuid")
else:
config.args.append("--disable-libuuid")
if self.spec.satisfies("platform=darwin"): if self.spec.satisfies("platform=darwin"):
# Does not build on macOS # Does not build on macOS
config_args.extend( config_args.extend(
@@ -82,6 +107,10 @@ def configure_args(self):
# Disable liblastlog2, which depends on sqlite # Disable liblastlog2, which depends on sqlite
config_args.append("--disable-liblastlog2") config_args.append("--disable-liblastlog2")
# Fixes #31123
if self.spec.satisfies("+uuid %intel"):
config_args.append("CFLAGS=-restrict")
return config_args return config_args
def install(self, spec, prefix): def install(self, spec, prefix):

View File

@@ -13,7 +13,7 @@ class Vecmem(CMakePackage, CudaPackage):
url = "https://github.com/acts-project/vecmem/archive/refs/tags/v0.5.0.tar.gz" url = "https://github.com/acts-project/vecmem/archive/refs/tags/v0.5.0.tar.gz"
list_url = "https://github.com/acts-project/vecmem/tags" list_url = "https://github.com/acts-project/vecmem/tags"
maintainers("wdconinc", "HadrienG2", "stephenswat") maintainers("wdconinc", "stephenswat")
license("MPL-2.0-no-copyleft-exception") license("MPL-2.0-no-copyleft-exception")

View File

@@ -25,8 +25,6 @@ class Verrou(AutotoolsPackage):
url = "https://github.com/edf-hpc/verrou/archive/v2.0.0.tar.gz" url = "https://github.com/edf-hpc/verrou/archive/v2.0.0.tar.gz"
git = "https://github.com/edf-hpc/verrou.git" git = "https://github.com/edf-hpc/verrou.git"
maintainers("HadrienG2")
license("GPL-2.0-only") license("GPL-2.0-only")
version("develop", branch="master") version("develop", branch="master")