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.
This commit is contained in:
parent
02d2c4a9ff
commit
c3435b4e7d
@ -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,
|
type triggers by way of a function call, we find all the hooks of that type,
|
||||||
and run them.
|
and run them.
|
||||||
|
|
||||||
Spack defines hooks by way of a module at ``lib/spack/spack/hooks`` where we can define
|
Spack defines hooks by way of a module in the ``lib/spack/spack/hooks`` directory.
|
||||||
types of hooks in the ``__init__.py``, and then python files in that folder
|
This module has to be registered in ``__init__.py`` so that Spack is aware of it.
|
||||||
can use hook functions. The files are automatically parsed, so if you write
|
This section will cover the basic kind of hooks, and how to write them.
|
||||||
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.
|
|
||||||
|
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
Types of Hooks
|
Types of Hooks
|
||||||
|
@ -21,43 +21,40 @@
|
|||||||
features.
|
features.
|
||||||
"""
|
"""
|
||||||
import importlib
|
import importlib
|
||||||
|
import types
|
||||||
from llnl.util.lang import ensure_last, list_modules
|
from typing import List, Optional
|
||||||
|
|
||||||
import spack.paths
|
|
||||||
|
|
||||||
|
|
||||||
class _HookRunner:
|
class _HookRunner:
|
||||||
#: Stores all hooks on first call, shared among
|
#: Order in which hooks are executed
|
||||||
#: all HookRunner objects
|
HOOK_ORDER = [
|
||||||
_hooks = None
|
"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):
|
def __init__(self, hook_name):
|
||||||
self.hook_name = 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
|
@property
|
||||||
def hooks(self):
|
def hooks(self) -> List[types.ModuleType]:
|
||||||
if not self._hooks:
|
if not self._hooks:
|
||||||
self._populate_hooks()
|
self._hooks = [importlib.import_module(module_name) for module_name in self.HOOK_ORDER]
|
||||||
return self._hooks
|
return self._hooks
|
||||||
|
|
||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
for _, module in self.hooks:
|
for module in self.hooks:
|
||||||
if hasattr(module, self.hook_name):
|
if hasattr(module, self.hook_name):
|
||||||
hook = getattr(module, self.hook_name)
|
hook = getattr(module, self.hook_name)
|
||||||
if hasattr(hook, "__call__"):
|
if hasattr(hook, "__call__"):
|
||||||
|
Loading…
Reference in New Issue
Block a user