Compare commits
1 Commits
develop-20
...
disinherit
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a438076473 |
@@ -2410,7 +2410,7 @@ package, and a `canonical hash <https://github.com/spack/spack/pull/28156>`_ of
|
|||||||
the ``package.py`` recipes). ``test`` dependencies do not affect the package
|
the ``package.py`` recipes). ``test`` dependencies do not affect the package
|
||||||
hash, as they are only used to construct a test environment *after* building and
|
hash, as they are only used to construct a test environment *after* building and
|
||||||
installing a given package installation. Older versions of Spack did not include
|
installing a given package installation. Older versions of Spack did not include
|
||||||
build dependencies in the hash, but this has been
|
build dependencies in the hash, but this has been
|
||||||
`fixed <https://github.com/spack/spack/pull/28504>`_ as of |Spack v0.18|_.
|
`fixed <https://github.com/spack/spack/pull/28504>`_ as of |Spack v0.18|_.
|
||||||
|
|
||||||
.. |Spack v0.18| replace:: Spack ``v0.18``
|
.. |Spack v0.18| replace:: Spack ``v0.18``
|
||||||
@@ -3604,6 +3604,70 @@ In the example above ``Cp2k`` inherits all the conflicts and variants that ``Cud
|
|||||||
|
|
||||||
.. _install-environment:
|
.. _install-environment:
|
||||||
|
|
||||||
|
--------------------------------
|
||||||
|
Package Inheritance
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Spack packages are Python classes, and you can use inheritance with them just as you can
|
||||||
|
with any Python class. This is common when you have your own package :ref:`repository
|
||||||
|
<repositories>` with packages that extend Spack's ``builtin`` packages.
|
||||||
|
|
||||||
|
You can extend a ``builtin`` package like this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from spack.pkg.builtin.mpich import Mpich
|
||||||
|
|
||||||
|
class MyPackage(Mpich):
|
||||||
|
version("1.0", "0209444070d9c8af9b62c94095a217e3bc6843692d1e3fdc1ff5371e03aac47c")
|
||||||
|
version("2.0", "5dda192154047d6296ba14a4ab2d869c6926fd7f44dce8ce94f63aae2e359c5b")
|
||||||
|
|
||||||
|
Every repository registered with Spack ends up in a submodule of ``spack.pkg`` with a
|
||||||
|
name corresponding to its :ref:`namespace <namespaces>`. So, if you have a different
|
||||||
|
repository with namespace ``myrepo`` you want to import packages from , you might write:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from spack.pkg.myrepo.my_package import MyPackage
|
||||||
|
|
||||||
|
class NewPackage(MyPackage):
|
||||||
|
version("3.0", "08721a102fefcea2ae4add8c9cc548df77e9224f5385ad0872a9150fdd26a415")
|
||||||
|
version("4.0", "9cc39dd33dd4227bb82301d285437588d705290846d22ab6b8791c7e631ce385")
|
||||||
|
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
``disinherit``
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
When you inherit from a package in Spack, you inherit all the metadata from its
|
||||||
|
directives, including ``version``, ``provides``, ``depends_on``, ``conflicts``, etc. For
|
||||||
|
example, ``NewPackage`` above will have four versions: ``1.0`` and ``2.0`` inherited
|
||||||
|
from ``MyPackage``, as well as, ``3.0``, and ``4.0`` defined in ``NewPackage``.
|
||||||
|
|
||||||
|
If you do not want your package to define all the same things as its base class, you can
|
||||||
|
use the ``disinherit`` directive to start fresh in your subclass:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from spack.pkg.myrepo.my_package import MyPackage
|
||||||
|
|
||||||
|
class NewerPackage(MyPackage):
|
||||||
|
disinherit("versions") # don't inherit any versions from MyPackage
|
||||||
|
version("5.0", "08721a102fefcea2ae4add8c9cc548df77e9224f5385ad0872a9150fdd26a415")
|
||||||
|
version("6.0", "9cc39dd33dd4227bb82301d285437588d705290846d22ab6b8791c7e631ce385")
|
||||||
|
|
||||||
|
Now, ``NewerPackage`` will have **only** versions ``5.0`` and ``6.0``, and will not
|
||||||
|
inherit ``1.0`` or ``2.0`` from ``MyPackage``. You can ``disinherit`` many different
|
||||||
|
properties from base packages. The full list of options is:
|
||||||
|
|
||||||
|
* ``conflicts``
|
||||||
|
* ``dependencies``
|
||||||
|
* ``extendees``
|
||||||
|
* ``patches``
|
||||||
|
* ``provided``
|
||||||
|
* ``resources``
|
||||||
|
* ``variants``
|
||||||
|
* ``versions``
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
The build environment
|
The build environment
|
||||||
-----------------------
|
-----------------------
|
||||||
|
@@ -91,6 +91,8 @@ packages and use the first valid file:
|
|||||||
to eventually support URLs in ``repos.yaml``, so that you can easily
|
to eventually support URLs in ``repos.yaml``, so that you can easily
|
||||||
point to remote package repositories, but that is not yet implemented.
|
point to remote package repositories, but that is not yet implemented.
|
||||||
|
|
||||||
|
.. _namespaces:
|
||||||
|
|
||||||
---------------------
|
---------------------
|
||||||
Namespaces
|
Namespaces
|
||||||
---------------------
|
---------------------
|
||||||
@@ -426,36 +428,3 @@ By path:
|
|||||||
$ spack repo list
|
$ spack repo list
|
||||||
==> 1 package repository.
|
==> 1 package repository.
|
||||||
builtin ~/spack/var/spack/repos/builtin
|
builtin ~/spack/var/spack/repos/builtin
|
||||||
|
|
||||||
--------------------------------
|
|
||||||
Repo namespaces and Python
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
You may have noticed that namespace notation for repositories is similar
|
|
||||||
to the notation for namespaces in Python. As it turns out, you *can*
|
|
||||||
treat Spack repositories like Python packages; this is how they are
|
|
||||||
implemented.
|
|
||||||
|
|
||||||
You could, for example, extend a ``builtin`` package in your own
|
|
||||||
repository:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from spack.pkg.builtin.mpich import Mpich
|
|
||||||
|
|
||||||
class MyPackage(Mpich):
|
|
||||||
...
|
|
||||||
|
|
||||||
Spack repo namespaces are actually Python namespaces tacked on under
|
|
||||||
``spack.pkg``. The search semantics of ``repos.yaml`` are actually
|
|
||||||
implemented using Python's built-in `sys.path
|
|
||||||
<https://docs.python.org/2/library/sys.html#sys.path>`_ search. The
|
|
||||||
:py:mod:`spack.repo` module implements a custom `Python importer
|
|
||||||
<https://docs.python.org/2/library/imp.html>`_.
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
|
|
||||||
The mechanism for extending packages is not yet extensively tested,
|
|
||||||
and extending packages across repositories imposes inter-repo
|
|
||||||
dependencies, which may be hard to manage. Use this feature at your
|
|
||||||
own risk, but let us know if you have a use case for it.
|
|
||||||
|
@@ -53,6 +53,7 @@ class OpenMpi(Package):
|
|||||||
"version",
|
"version",
|
||||||
"conflicts",
|
"conflicts",
|
||||||
"depends_on",
|
"depends_on",
|
||||||
|
"disinherit",
|
||||||
"extends",
|
"extends",
|
||||||
"provides",
|
"provides",
|
||||||
"patch",
|
"patch",
|
||||||
@@ -235,12 +236,12 @@ class Foo(Package):
|
|||||||
if isinstance(dicts, str):
|
if isinstance(dicts, str):
|
||||||
dicts = (dicts,)
|
dicts = (dicts,)
|
||||||
|
|
||||||
if not isinstance(dicts, collections.abc.Sequence):
|
if dicts is not None:
|
||||||
message = "dicts arg must be list, tuple, or string. Found {0}"
|
if not isinstance(dicts, collections.abc.Sequence):
|
||||||
raise TypeError(message.format(type(dicts)))
|
raise TypeError(f"dicts arg must be list, tuple, or string. Found {type(dicts)}")
|
||||||
|
|
||||||
# Add the dictionary names if not already there
|
# Add the dictionary names if not already there
|
||||||
DirectiveMeta._directive_dict_names |= set(dicts)
|
DirectiveMeta._directive_dict_names |= set(dicts)
|
||||||
|
|
||||||
# This decorator just returns the directive functions
|
# This decorator just returns the directive functions
|
||||||
def _decorator(decorated_function):
|
def _decorator(decorated_function):
|
||||||
@@ -767,6 +768,35 @@ def build_system(*values, **kwargs):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@directive()
|
||||||
|
def disinherit(dict_name: str):
|
||||||
|
"""Clear all values in a dict inherited from base packages.
|
||||||
|
|
||||||
|
You can use this to, e.g., remove all inherited versions from a base package:
|
||||||
|
|
||||||
|
disinherit("versions") # this package doesn't share any versions w/parents
|
||||||
|
version("2.0", ...) # new versions specific to this package
|
||||||
|
version("3.0", ...)
|
||||||
|
|
||||||
|
The dictionary name is checked, so you can't call this on somethign that's not a
|
||||||
|
valid directive dictonary.
|
||||||
|
|
||||||
|
Arguments:
|
||||||
|
dict_name: name of directive dictionary to clear.
|
||||||
|
|
||||||
|
"""
|
||||||
|
if dict_name not in DirectiveMeta._directive_dict_names:
|
||||||
|
names = ", ".join(DirectiveMeta._directive_dict_names)
|
||||||
|
raise DirectiveError(f"Can't disinherit '{dict_name}'. Options are: {names}")
|
||||||
|
|
||||||
|
def _execute_disinherit(pkg):
|
||||||
|
dictionary = getattr(pkg, dict_name, None)
|
||||||
|
if dictionary:
|
||||||
|
dictionary.clear()
|
||||||
|
|
||||||
|
return _execute_disinherit
|
||||||
|
|
||||||
|
|
||||||
class DirectiveError(spack.error.SpackError):
|
class DirectiveError(spack.error.SpackError):
|
||||||
"""This is raised when something is wrong with a package directive."""
|
"""This is raised when something is wrong with a package directive."""
|
||||||
|
|
||||||
|
@@ -68,3 +68,21 @@ def test_error_on_anonymous_dependency(config, mock_packages):
|
|||||||
pkg = spack.repo.path.get_pkg_class("a")
|
pkg = spack.repo.path.get_pkg_class("a")
|
||||||
with pytest.raises(spack.directives.DependencyError):
|
with pytest.raises(spack.directives.DependencyError):
|
||||||
spack.directives._depends_on(pkg, "@4.5")
|
spack.directives._depends_on(pkg, "@4.5")
|
||||||
|
|
||||||
|
|
||||||
|
def test_disinherited_version(config, mock_packages):
|
||||||
|
pkg = spack.repo.path.get_pkg_class("disinherit")
|
||||||
|
|
||||||
|
# these would be inherited from A if disinherit failed
|
||||||
|
assert "1.0" not in pkg.versions
|
||||||
|
assert "2.0" not in pkg.versions
|
||||||
|
|
||||||
|
# these are defined in dininherit
|
||||||
|
assert "3.0" not in pkg.versions
|
||||||
|
assert "4.0" not in pkg.versions
|
||||||
|
|
||||||
|
|
||||||
|
def test_disinherit(config, mock_packages):
|
||||||
|
with pytest.raises(spack.directives.DirectiveError):
|
||||||
|
# This is not a valid thing to disinherit
|
||||||
|
spack.directives.disinherit("foobarbaz")
|
||||||
|
15
var/spack/repos/builtin.mock/packages/disinherit/package.py
Normal file
15
var/spack/repos/builtin.mock/packages/disinherit/package.py
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Copyright 2013-2022 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 *
|
||||||
|
from spack.pkg.builtin.mock.a import A
|
||||||
|
|
||||||
|
|
||||||
|
class Disinherit(A):
|
||||||
|
"""Disinherit from A and add our own versions."""
|
||||||
|
|
||||||
|
disinherit("versions")
|
||||||
|
version("4.0", "abcdef0123456789abcdef0123456789")
|
||||||
|
version("3.0", "0123456789abcdef0123456789abcdef")
|
@@ -18,14 +18,13 @@ class GromacsChainCoordinate(Gromacs):
|
|||||||
git = "https://gitlab.com/cbjh/gromacs-chain-coordinate.git"
|
git = "https://gitlab.com/cbjh/gromacs-chain-coordinate.git"
|
||||||
maintainers = ["w8jcik"]
|
maintainers = ["w8jcik"]
|
||||||
|
|
||||||
|
disinherit("versions")
|
||||||
version("main", branch="main")
|
version("main", branch="main")
|
||||||
|
|
||||||
version(
|
version(
|
||||||
"2021.5-0.2",
|
"2021.5-0.2",
|
||||||
sha256="33dda1e39cd47c5ae32b5455af8534225d3888fd7e4968f499b8483620fa770a",
|
sha256="33dda1e39cd47c5ae32b5455af8534225d3888fd7e4968f499b8483620fa770a",
|
||||||
url="https://gitlab.com/cbjh/gromacs-chain-coordinate/-/archive/release-2021.chaincoord-0.2/gromacs-chain-coordinate-release-2021.chaincoord-0.2.tar.bz2",
|
url="https://gitlab.com/cbjh/gromacs-chain-coordinate/-/archive/release-2021.chaincoord-0.2/gromacs-chain-coordinate-release-2021.chaincoord-0.2.tar.bz2",
|
||||||
)
|
)
|
||||||
|
|
||||||
version(
|
version(
|
||||||
"2021.2-0.1",
|
"2021.2-0.1",
|
||||||
sha256="879fdd04662370a76408b72c9fbc4aff60a6387b459322ac2700d27359d0dd87",
|
sha256="879fdd04662370a76408b72c9fbc4aff60a6387b459322ac2700d27359d0dd87",
|
||||||
@@ -34,21 +33,6 @@ class GromacsChainCoordinate(Gromacs):
|
|||||||
|
|
||||||
conflicts("+plumed")
|
conflicts("+plumed")
|
||||||
|
|
||||||
def remove_parent_versions(self):
|
|
||||||
"""
|
|
||||||
By inheriting GROMACS package we also inherit versions.
|
|
||||||
They are not valid, so we are removing them.
|
|
||||||
"""
|
|
||||||
|
|
||||||
for version_key in Gromacs.versions.keys():
|
|
||||||
if version_key in self.versions:
|
|
||||||
del self.versions[version_key]
|
|
||||||
|
|
||||||
def __init__(self, spec):
|
|
||||||
super(GromacsChainCoordinate, self).__init__(spec)
|
|
||||||
|
|
||||||
self.remove_parent_versions()
|
|
||||||
|
|
||||||
def check(self):
|
def check(self):
|
||||||
"""The default 'test' targets does not compile the test programs"""
|
"""The default 'test' targets does not compile the test programs"""
|
||||||
with working_dir(self.build_directory):
|
with working_dir(self.build_directory):
|
||||||
|
@@ -15,6 +15,7 @@ class GromacsSwaxs(Gromacs):
|
|||||||
git = "https://gitlab.com/cbjh/gromacs-swaxs.git"
|
git = "https://gitlab.com/cbjh/gromacs-swaxs.git"
|
||||||
maintainers = ["w8jcik"]
|
maintainers = ["w8jcik"]
|
||||||
|
|
||||||
|
disinherit("versions")
|
||||||
version(
|
version(
|
||||||
"2021.5-0.4",
|
"2021.5-0.4",
|
||||||
sha256="9f8ed6d448a04789d45e847cbbc706a07130377f578388220a9d5357fae9d1c3",
|
sha256="9f8ed6d448a04789d45e847cbbc706a07130377f578388220a9d5357fae9d1c3",
|
||||||
@@ -136,18 +137,3 @@ class GromacsSwaxs(Gromacs):
|
|||||||
conflicts("+plumed")
|
conflicts("+plumed")
|
||||||
conflicts("+opencl")
|
conflicts("+opencl")
|
||||||
conflicts("+sycl")
|
conflicts("+sycl")
|
||||||
|
|
||||||
def remove_parent_versions(self):
|
|
||||||
"""
|
|
||||||
By inheriting GROMACS package we also inherit versions.
|
|
||||||
They are not valid, so we are removing them.
|
|
||||||
"""
|
|
||||||
|
|
||||||
for version_key in Gromacs.versions.keys():
|
|
||||||
if version_key in self.versions:
|
|
||||||
del self.versions[version_key]
|
|
||||||
|
|
||||||
def __init__(self, spec):
|
|
||||||
super(GromacsSwaxs, self).__init__(spec)
|
|
||||||
|
|
||||||
self.remove_parent_versions()
|
|
||||||
|
Reference in New Issue
Block a user