summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorHarmen Stoppels <me@harmenstoppels.nl>2024-10-30 19:57:49 +0100
committerGitHub <noreply@github.com>2024-10-30 18:57:49 +0000
commitc3435b4e7df11d0ecf4ced529e56ec84ba3d5067 (patch)
tree6185e300baf3ab24884a37ba7ad230e943e3ab4f /lib
parent02d2c4a9ffee22c8aca8e5c4b10d40ee3a9183d5 (diff)
downloadspack-c3435b4e7df11d0ecf4ced529e56ec84ba3d5067.tar.gz
spack-c3435b4e7df11d0ecf4ced529e56ec84ba3d5067.tar.bz2
spack-c3435b4e7df11d0ecf4ced529e56ec84ba3d5067.tar.xz
spack-c3435b4e7df11d0ecf4ced529e56ec84ba3d5067.zip
hooks: run in clear, fixed order (#47329)
Currently the order in which hooks are run is arbitrary. This can be fixed by sorted(list_modules(...)) but I think it is much more clear to just have a static list. Hooks are not extensible other than modifying Spack code, which means it's unlikely people maintain custom hooks since they'd have to fork Spack. And if they fork Spack, they might as well add an entry to the list when they're continuously rebasing.
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/docs/developer_guide.rst10
-rw-r--r--lib/spack/spack/hooks/__init__.py47
2 files changed, 25 insertions, 32 deletions
diff --git a/lib/spack/docs/developer_guide.rst b/lib/spack/docs/developer_guide.rst
index f538f75206..21204ba077 100644
--- a/lib/spack/docs/developer_guide.rst
+++ b/lib/spack/docs/developer_guide.rst
@@ -333,13 +333,9 @@ inserting them at different places in the spack code base. Whenever a hook
type triggers by way of a function call, we find all the hooks of that type,
and run them.
-Spack defines hooks by way of a module at ``lib/spack/spack/hooks`` where we can define
-types of hooks in the ``__init__.py``, and then python files in that folder
-can use hook functions. The files are automatically parsed, so if you write
-a new file for some integration (e.g., ``lib/spack/spack/hooks/myintegration.py``
-you can then write hook functions in that file that will be automatically detected,
-and run whenever your hook is called. This section will cover the basic kind
-of hooks, and how to write them.
+Spack defines hooks by way of a module in the ``lib/spack/spack/hooks`` directory.
+This module has to be registered in ``__init__.py`` so that Spack is aware of it.
+This section will cover the basic kind of hooks, and how to write them.
^^^^^^^^^^^^^^
Types of Hooks
diff --git a/lib/spack/spack/hooks/__init__.py b/lib/spack/spack/hooks/__init__.py
index 0e7e303692..73fad62d6a 100644
--- a/lib/spack/spack/hooks/__init__.py
+++ b/lib/spack/spack/hooks/__init__.py
@@ -21,43 +21,40 @@ systems (e.g. modules, lmod, etc.) or to add other custom
features.
"""
import importlib
-
-from llnl.util.lang import ensure_last, list_modules
-
-import spack.paths
+import types
+from typing import List, Optional
class _HookRunner:
- #: Stores all hooks on first call, shared among
- #: all HookRunner objects
- _hooks = None
+ #: Order in which hooks are executed
+ HOOK_ORDER = [
+ "spack.hooks.module_file_generation",
+ "spack.hooks.licensing",
+ "spack.hooks.sbang",
+ "spack.hooks.windows_runtime_linkage",
+ "spack.hooks.drop_redundant_rpaths",
+ "spack.hooks.absolutify_elf_sonames",
+ "spack.hooks.permissions_setters",
+ # after all mutations to the install prefix, write metadata
+ "spack.hooks.write_install_manifest",
+ # after all metadata is written
+ "spack.hooks.autopush",
+ ]
+
+ #: Contains all hook modules after first call, shared among all HookRunner objects
+ _hooks: Optional[List[types.ModuleType]] = None
def __init__(self, hook_name):
self.hook_name = hook_name
- @classmethod
- def _populate_hooks(cls):
- # Lazily populate the list of hooks
- cls._hooks = []
-
- relative_names = list(list_modules(spack.paths.hooks_path))
-
- # Ensure that write_install_manifest comes last
- ensure_last(relative_names, "absolutify_elf_sonames", "write_install_manifest")
-
- for name in relative_names:
- module_name = __name__ + "." + name
- module_obj = importlib.import_module(module_name)
- cls._hooks.append((module_name, module_obj))
-
@property
- def hooks(self):
+ def hooks(self) -> List[types.ModuleType]:
if not self._hooks:
- self._populate_hooks()
+ self._hooks = [importlib.import_module(module_name) for module_name in self.HOOK_ORDER]
return self._hooks
def __call__(self, *args, **kwargs):
- for _, module in self.hooks:
+ for module in self.hooks:
if hasattr(module, self.hook_name):
hook = getattr(module, self.hook_name)
if hasattr(hook, "__call__"):