2024-01-02 00:21:30 -08:00
.. Copyright 2013-2024 Lawrence Livermore National Security, LLC and other
2019-05-17 02:27:42 +02:00
Spack Project Developers. See the top-level COPYRIGHT file for details.
SPDX-License-Identifier: (Apache-2.0 OR MIT)
.. extensions:
=================
Custom Extensions
=================
2023-12-05 09:49:35 +01:00
*Spack extensions* allow you to extend Spack capabilities by deploying your
2019-05-17 02:27:42 +02:00
own custom commands or logic in an arbitrary location on your filesystem.
This might be extremely useful e.g. to develop and maintain a command whose purpose is
too specific to be considered for reintegration into the mainline or to
evolve a command through its early stages before starting a discussion to merge
it upstream.
2023-12-05 09:49:35 +01:00
2019-05-17 02:27:42 +02:00
From Spack's point of view an extension is any path in your filesystem which
2023-12-05 09:49:35 +01:00
respects the following naming and layout for files:
2019-05-17 02:27:42 +02:00
.. code-block :: console
spack-scripting/ # The top level directory must match the format 'spack-{extension_name}'
├── pytest.ini # Optional file if the extension ships its own tests
├── scripting # Folder that may contain modules that are needed for the extension commands
2023-12-05 09:49:35 +01:00
│ ├── cmd # Folder containing extension commands
│ │ └── filter.py # A new command that will be available
│ └── functions.py # Module with internal details
└── tests # Tests for this extension
2019-05-17 02:27:42 +02:00
│ ├── conftest.py
│ └── test_filter.py
└── templates # Templates that may be needed by the extension
2023-12-05 09:49:35 +01:00
In the example above, the extension is named *scripting* . It adds an additional command
(`` spack filter `` ) and unit tests to verify its behavior.
2019-05-17 02:27:42 +02:00
2023-12-05 09:49:35 +01:00
The extension can import any core Spack module in its implementation. When loaded by
the `` spack `` command, the extension itself is imported as a Python package in the
`` spack.extensions `` namespace. In the example above, since the extension is named
"scripting", the corresponding Python module is `` spack.extensions.scripting `` .
2019-05-17 02:27:42 +02:00
2023-12-05 09:49:35 +01:00
The code for this example extension can be obtained by cloning the corresponding git repository:
2019-05-17 02:27:42 +02:00
2023-12-05 09:49:35 +01:00
.. code-block :: console
2019-05-17 02:27:42 +02:00
2023-12-05 09:49:35 +01:00
$ git -C /tmp clone https://github.com/spack/spack-scripting.git
2019-05-17 02:27:42 +02:00
---------------------------------
Configure Spack to Use Extensions
---------------------------------
To make your current Spack instance aware of extensions you should add their root
paths to `` config.yaml `` . In the case of our example this means ensuring that:
.. code-block :: yaml
config:
extensions:
2023-12-05 09:49:35 +01:00
- /tmp/spack-scripting
2019-05-17 02:27:42 +02:00
is part of your configuration file. Once this is setup any command that the extension provides
will be available from the command line:
.. code-block :: console
$ spack filter --help
usage: spack filter [-h] [--installed | --not-installed]
[--explicit | --implicit] [--output OUTPUT]
...
filter specs based on their properties
positional arguments:
specs specs to be filtered
optional arguments:
-h, --help show this help message and exit
--installed select installed specs
--not-installed select specs that are not yet installed
--explicit select specs that were installed explicitly
--implicit select specs that are not installed or were installed implicitly
--output OUTPUT where to dump the result
2023-12-05 09:49:35 +01:00
The corresponding unit tests can be run giving the appropriate options to `` spack unit-test `` :
2019-05-17 02:27:42 +02:00
.. code-block :: console
spack test (#15702)
Users can add test() methods to their packages to run smoke tests on
installations with the new `spack test` command (the old `spack test` is
now `spack unit-test`). spack test is environment-aware, so you can
`spack install` an environment and then run `spack test run` to run smoke
tests on all of its packages. Historical test logs can be perused with
`spack test results`. Generic smoke tests for MPI implementations, C,
C++, and Fortran compilers as well as specific smoke tests for 18
packages.
Inside the test method, individual tests can be run separately (and
continue to run best-effort after a test failure) using the `run_test`
method. The `run_test` method encapsulates finding test executables,
running and checking return codes, checking output, and error handling.
This handles the following trickier aspects of testing with direct
support in Spack's package API:
- [x] Caching source or intermediate build files at build time for
use at test time.
- [x] Test dependencies,
- [x] packages that require a compiler for testing (such as library only
packages).
See the packaging guide for more details on using Spack testing support.
Included is support for package.py files for virtual packages. This does
not change the Spack interface, but is a major change in internals.
Co-authored-by: Tamara Dahlgren <dahlgren1@llnl.gov>
Co-authored-by: wspear <wjspear@gmail.com>
Co-authored-by: Adam J. Stewart <ajstewart426@gmail.com>
2020-11-18 02:39:02 -08:00
$ spack unit-test --extension=scripting
2023-12-05 09:49:35 +01:00
========================================== test session starts ===========================================
platform linux -- Python 3.11.5, pytest-7.4.3, pluggy-1.3.0
rootdir: /home/culpo/github/spack-scripting
configfile: pytest.ini
testpaths: tests
plugins: xdist-3.5.0
2019-05-17 02:27:42 +02:00
collected 5 items
2023-12-05 09:49:35 +01:00
tests/test_filter.py ..... [100%]
========================================== slowest 30 durations ==========================================
2.31s setup tests/test_filter.py::test_filtering_specs[kwargs0-specs0-expected0]
0.57s call tests/test_filter.py::test_filtering_specs[kwargs2-specs2-expected2]
0.56s call tests/test_filter.py::test_filtering_specs[kwargs4-specs4-expected4]
0.54s call tests/test_filter.py::test_filtering_specs[kwargs3-specs3-expected3]
0.54s call tests/test_filter.py::test_filtering_specs[kwargs1-specs1-expected1]
0.48s call tests/test_filter.py::test_filtering_specs[kwargs0-specs0-expected0]
0.01s setup tests/test_filter.py::test_filtering_specs[kwargs4-specs4-expected4]
0.01s setup tests/test_filter.py::test_filtering_specs[kwargs2-specs2-expected2]
0.01s setup tests/test_filter.py::test_filtering_specs[kwargs1-specs1-expected1]
0.01s setup tests/test_filter.py::test_filtering_specs[kwargs3-specs3-expected3]
(5 durations < 0.005s hidden. Use -vv to show these durations.)
=========================================== 5 passed in 5.06s ============================================
2024-03-06 03:18:49 -07:00
---------------------------------------
Registering Extensions via Entry Points
---------------------------------------
.. note ::
Python version >= 3.8 is required to register extensions via entry points.
Spack can be made aware of extensions that are installed as part of a python package. To do so, register a function that returns the extension path, or paths, to the `` "spack.extensions" `` entry point. Consider the Python package `` my_package `` that includes a Spack extension:
.. code-block :: console
my-package/
├── src
│ ├── my_package
│ │ └── __init__.py
│ └── spack-scripting/ # the spack extensions
└── pyproject.toml
adding the following to `` my_package `` 's `` pyproject.toml `` will make the `` spack-scripting `` extension visible to Spack when `` my_package `` is installed:
.. code-block :: toml
[project.entry_points."spack.extenions"]
my_package = "my_package:get_extension_path"
The function `` my_package.get_extension_path `` in `` my_package/__init__.py `` might look like
.. code-block :: python
import importlib.resources
def get_extension_path():
dirname = importlib.resources.files("my_package").joinpath("spack-scripting")
if dirname.exists():
return str(dirname)