diff options
author | Harmen Stoppels <me@harmenstoppels.nl> | 2024-10-30 19:57:49 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-30 18:57:49 +0000 |
commit | c3435b4e7df11d0ecf4ced529e56ec84ba3d5067 (patch) | |
tree | 6185e300baf3ab24884a37ba7ad230e943e3ab4f /lib | |
parent | 02d2c4a9ffee22c8aca8e5c4b10d40ee3a9183d5 (diff) | |
download | spack-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.rst | 10 | ||||
-rw-r--r-- | lib/spack/spack/hooks/__init__.py | 47 |
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__"): |