builder: parametrize package type

and fix a few cases of builders that didn't inherit from
BuilderWithDefaults
This commit is contained in:
Harmen Stoppels 2025-04-16 10:44:20 +02:00
parent b932c14008
commit cdc67d6105
23 changed files with 38 additions and 29 deletions

View File

@ -2,7 +2,7 @@
# #
# SPDX-License-Identifier: (Apache-2.0 OR MIT) # SPDX-License-Identifier: (Apache-2.0 OR MIT)
import os import os
from typing import List from typing import Generic, List
import llnl.util.lang import llnl.util.lang
@ -127,7 +127,7 @@ def execute_install_time_tests(builder: spack.builder.Builder):
builder.pkg.tester.phase_tests(builder, "install", builder.install_time_test_callbacks) builder.pkg.tester.phase_tests(builder, "install", builder.install_time_test_callbacks)
class BuilderWithDefaults(spack.builder.Builder): class BuilderWithDefaults(Generic[spack.builder.B], spack.builder.Builder[spack.builder.B]):
"""Base class for all specific builders with common callbacks registered.""" """Base class for all specific builders with common callbacks registered."""
# Check that self.prefix is there after installation # Check that self.prefix is there after installation

View File

@ -79,7 +79,7 @@ def with_or_without(self, *args, **kwargs):
@spack.builder.builder("autotools") @spack.builder.builder("autotools")
class AutotoolsBuilder(BuilderWithDefaults): class AutotoolsBuilder(BuilderWithDefaults[AutotoolsPackage]):
"""The autotools builder encodes the default way of installing software built """The autotools builder encodes the default way of installing software built
with autotools. It has four phases that can be overridden, if need be: with autotools. It has four phases that can be overridden, if need be:

View File

@ -5,6 +5,8 @@
import spack.directives import spack.directives
import spack.package_base import spack.package_base
from ._checks import BuilderWithDefaults
class BundlePackage(spack.package_base.PackageBase): class BundlePackage(spack.package_base.PackageBase):
"""General purpose bundle, or no-code, package class.""" """General purpose bundle, or no-code, package class."""
@ -23,7 +25,7 @@ class BundlePackage(spack.package_base.PackageBase):
@spack.builder.builder("bundle") @spack.builder.builder("bundle")
class BundleBuilder(spack.builder.Builder): class BundleBuilder(BuilderWithDefaults[BundlePackage]):
phases = ("install",) phases = ("install",)
def install(self, pkg, spec, prefix): def install(self, pkg, spec, prefix):

View File

@ -30,7 +30,7 @@ class CargoPackage(spack.package_base.PackageBase):
@spack.builder.builder("cargo") @spack.builder.builder("cargo")
class CargoBuilder(BuilderWithDefaults): class CargoBuilder(BuilderWithDefaults[CargoPackage]):
"""The Cargo builder encodes the most common way of building software with """The Cargo builder encodes the most common way of building software with
a rust Cargo.toml file. It has two phases that can be overridden, if need be: a rust Cargo.toml file. It has two phases that can be overridden, if need be:

View File

@ -284,7 +284,7 @@ def define_from_variant(self, cmake_var: str, variant: Optional[str] = None) ->
@spack.builder.builder("cmake") @spack.builder.builder("cmake")
class CMakeBuilder(BuilderWithDefaults): class CMakeBuilder(BuilderWithDefaults[CMakePackage]):
"""The cmake builder encodes the default way of building software with CMake. IT """The cmake builder encodes the default way of building software with CMake. IT
has three phases that can be overridden: has three phases that can be overridden:

View File

@ -28,7 +28,7 @@ class Package(spack.package_base.PackageBase):
@spack.builder.builder("generic") @spack.builder.builder("generic")
class GenericBuilder(BuilderWithDefaults): class GenericBuilder(BuilderWithDefaults[Package]):
"""A builder for a generic build system, that require packagers """A builder for a generic build system, that require packagers
to implement an "install" phase. to implement an "install" phase.
""" """

View File

@ -33,7 +33,7 @@ class GoPackage(spack.package_base.PackageBase):
@spack.builder.builder("go") @spack.builder.builder("go")
class GoBuilder(BuilderWithDefaults): class GoBuilder(BuilderWithDefaults[GoPackage]):
"""The Go builder encodes the most common way of building software with """The Go builder encodes the most common way of building software with
a golang go.mod file. It has two phases that can be overridden, if need be: a golang go.mod file. It has two phases that can be overridden, if need be:

View File

@ -14,6 +14,8 @@
from spack.directives import build_system, depends_on, extends from spack.directives import build_system, depends_on, extends
from spack.multimethod import when from spack.multimethod import when
from ._checks import BuilderWithDefaults
class LuaPackage(spack.package_base.PackageBase): class LuaPackage(spack.package_base.PackageBase):
"""Specialized class for lua packages""" """Specialized class for lua packages"""
@ -49,7 +51,7 @@ def luarocks(self):
@spack.builder.builder("lua") @spack.builder.builder("lua")
class LuaBuilder(spack.builder.Builder): class LuaBuilder(BuilderWithDefaults[LuaPackage]):
phases = ("unpack", "generate_luarocks_config", "preprocess", "install") phases = ("unpack", "generate_luarocks_config", "preprocess", "install")
#: Names associated with package methods in the old build-system format #: Names associated with package methods in the old build-system format

View File

@ -38,7 +38,7 @@ class MakefilePackage(spack.package_base.PackageBase):
@spack.builder.builder("makefile") @spack.builder.builder("makefile")
class MakefileBuilder(BuilderWithDefaults): class MakefileBuilder(BuilderWithDefaults[MakefilePackage]):
"""The Makefile builder encodes the most common way of building software with """The Makefile builder encodes the most common way of building software with
Makefiles. It has three phases that can be overridden, if need be: Makefiles. It has three phases that can be overridden, if need be:

View File

@ -35,7 +35,7 @@ class MavenPackage(spack.package_base.PackageBase):
@spack.builder.builder("maven") @spack.builder.builder("maven")
class MavenBuilder(BuilderWithDefaults): class MavenBuilder(BuilderWithDefaults[MavenPackage]):
"""The Maven builder encodes the default way to build software with Maven. """The Maven builder encodes the default way to build software with Maven.
It has two phases that can be overridden, if need be: It has two phases that can be overridden, if need be:

View File

@ -67,7 +67,7 @@ def flags_to_build_system_args(self, flags):
@spack.builder.builder("meson") @spack.builder.builder("meson")
class MesonBuilder(BuilderWithDefaults): class MesonBuilder(BuilderWithDefaults[MesonPackage]):
"""The Meson builder encodes the default way to build software with Meson. """The Meson builder encodes the default way to build software with Meson.
The builder has three phases that can be overridden, if need be: The builder has three phases that can be overridden, if need be:

View File

@ -27,7 +27,7 @@ class MSBuildPackage(spack.package_base.PackageBase):
@spack.builder.builder("msbuild") @spack.builder.builder("msbuild")
class MSBuildBuilder(BuilderWithDefaults): class MSBuildBuilder(BuilderWithDefaults[MSBuildPackage]):
"""The MSBuild builder encodes the most common way of building software with """The MSBuild builder encodes the most common way of building software with
Mircosoft's MSBuild tool. It has two phases that can be overridden, if need be: Mircosoft's MSBuild tool. It has two phases that can be overridden, if need be:

View File

@ -27,7 +27,7 @@ class NMakePackage(spack.package_base.PackageBase):
@spack.builder.builder("nmake") @spack.builder.builder("nmake")
class NMakeBuilder(BuilderWithDefaults): class NMakeBuilder(BuilderWithDefaults[NMakePackage]):
"""The NMake builder encodes the most common way of building software with """The NMake builder encodes the most common way of building software with
Mircosoft's NMake tool. It has two phases that can be overridden, if need be: Mircosoft's NMake tool. It has two phases that can be overridden, if need be:

View File

@ -31,7 +31,7 @@ class OctavePackage(spack.package_base.PackageBase):
@spack.builder.builder("octave") @spack.builder.builder("octave")
class OctaveBuilder(BuilderWithDefaults): class OctaveBuilder(BuilderWithDefaults[OctavePackage]):
"""The octave builder provides the following phases that can be overridden: """The octave builder provides the following phases that can be overridden:
1. :py:meth:`~.OctaveBuilder.install` 1. :py:meth:`~.OctaveBuilder.install`

View File

@ -89,7 +89,7 @@ def test_use(self):
@spack.builder.builder("perl") @spack.builder.builder("perl")
class PerlBuilder(BuilderWithDefaults): class PerlBuilder(BuilderWithDefaults[PerlPackage]):
"""The perl builder provides four phases that can be overridden, if required: """The perl builder provides four phases that can be overridden, if required:
1. :py:meth:`~.PerlBuilder.configure` 1. :py:meth:`~.PerlBuilder.configure`

View File

@ -428,7 +428,7 @@ def libs(self) -> LibraryList:
@spack.builder.builder("python_pip") @spack.builder.builder("python_pip")
class PythonPipBuilder(BuilderWithDefaults): class PythonPipBuilder(BuilderWithDefaults[PythonPackage]):
phases = ("install",) phases = ("install",)
#: Names associated with package methods in the old build-system format #: Names associated with package methods in the old build-system format

View File

@ -33,7 +33,7 @@ class QMakePackage(spack.package_base.PackageBase):
@spack.builder.builder("qmake") @spack.builder.builder("qmake")
class QMakeBuilder(BuilderWithDefaults): class QMakeBuilder(BuilderWithDefaults[QMakePackage]):
"""The qmake builder provides three phases that can be overridden: """The qmake builder provides three phases that can be overridden:
1. :py:meth:`~.QMakeBuilder.qmake` 1. :py:meth:`~.QMakeBuilder.qmake`

View File

@ -18,6 +18,8 @@
from spack.util.environment import env_flag from spack.util.environment import env_flag
from spack.util.executable import Executable, ProcessError from spack.util.executable import Executable, ProcessError
from ._checks import BuilderWithDefaults
def _homepage(cls: "RacketPackage") -> Optional[str]: def _homepage(cls: "RacketPackage") -> Optional[str]:
if cls.racket_name: if cls.racket_name:
@ -47,7 +49,7 @@ class RacketPackage(PackageBase):
@spack.builder.builder("racket") @spack.builder.builder("racket")
class RacketBuilder(spack.builder.Builder): class RacketBuilder(BuilderWithDefaults[RacketPackage]):
"""The Racket builder provides an ``install`` phase that can be overridden.""" """The Racket builder provides an ``install`` phase that can be overridden."""
phases = ("install",) phases = ("install",)

View File

@ -29,7 +29,7 @@ class RubyPackage(spack.package_base.PackageBase):
@spack.builder.builder("ruby") @spack.builder.builder("ruby")
class RubyBuilder(BuilderWithDefaults): class RubyBuilder(BuilderWithDefaults[RubyPackage]):
"""The Ruby builder provides two phases that can be overridden if required: """The Ruby builder provides two phases that can be overridden if required:
#. :py:meth:`~.RubyBuilder.build` #. :py:meth:`~.RubyBuilder.build`

View File

@ -30,7 +30,7 @@ class SConsPackage(spack.package_base.PackageBase):
@spack.builder.builder("scons") @spack.builder.builder("scons")
class SConsBuilder(BuilderWithDefaults): class SConsBuilder(BuilderWithDefaults[SConsPackage]):
"""The Scons builder provides the following phases that can be overridden: """The Scons builder provides the following phases that can be overridden:
1. :py:meth:`~.SConsBuilder.build` 1. :py:meth:`~.SConsBuilder.build`

View File

@ -106,7 +106,7 @@ def test_imports(self):
@spack.builder.builder("sip") @spack.builder.builder("sip")
class SIPBuilder(BuilderWithDefaults): class SIPBuilder(BuilderWithDefaults[SIPPackage]):
"""The SIP builder provides the following phases that can be overridden: """The SIP builder provides the following phases that can be overridden:
* configure * configure

View File

@ -32,7 +32,7 @@ class WafPackage(spack.package_base.PackageBase):
@spack.builder.builder("waf") @spack.builder.builder("waf")
class WafBuilder(BuilderWithDefaults): class WafBuilder(BuilderWithDefaults[WafPackage]):
"""The WAF builder provides the following phases that can be overridden: """The WAF builder provides the following phases that can be overridden:
* configure * configure

View File

@ -5,7 +5,7 @@
import collections.abc import collections.abc
import copy import copy
import functools import functools
from typing import Dict, List, Optional, Tuple, Type from typing import Dict, Generic, List, Optional, Tuple, Type, TypeVar
import spack.error import spack.error
import spack.multimethod import spack.multimethod
@ -393,7 +393,10 @@ def copy(self):
return copy.deepcopy(self) return copy.deepcopy(self)
class BaseBuilder(metaclass=BuilderMeta): B = TypeVar("B", bound=spack.package_base.PackageBase)
class BaseBuilder(Generic[B], metaclass=BuilderMeta):
"""An interface for builders, without any phases defined. This class is exposed in the package """An interface for builders, without any phases defined. This class is exposed in the package
API, so that packagers can create a single class to define ``setup_build_environment`` and API, so that packagers can create a single class to define ``setup_build_environment`` and
``@run_before`` and ``@run_after`` callbacks that can be shared among different builders. ``@run_before`` and ``@run_after`` callbacks that can be shared among different builders.
@ -402,7 +405,7 @@ class BaseBuilder(metaclass=BuilderMeta):
.. code-block:: python .. code-block:: python
class AnyBuilder(BaseBuilder): class AnyBuilder(BaseBuilder[AnyPackage]):
@run_after("install") @run_after("install")
def fixup_install(self): def fixup_install(self):
# do something after the package is installed # do something after the package is installed
@ -418,7 +421,7 @@ class AutotoolsBuilder(autotools.AutotoolsBuilder, AnyBuilder):
pass pass
""" """
def __init__(self, pkg: spack.package_base.PackageBase) -> None: def __init__(self, pkg: B) -> None:
self.pkg = pkg self.pkg = pkg
@property @property
@ -484,7 +487,7 @@ def __str__(self):
return f'"{self.__class__.__name__}" builder for "{self.spec.format(fmt)}"' return f'"{self.__class__.__name__}" builder for "{self.spec.format(fmt)}"'
class Builder(BaseBuilder, collections.abc.Sequence): class Builder(Generic[B], BaseBuilder[B], collections.abc.Sequence):
"""A builder is a class that, given a package object (i.e. associated with concrete spec), """A builder is a class that, given a package object (i.e. associated with concrete spec),
knows how to install it. knows how to install it.
@ -511,7 +514,7 @@ class Builder(BaseBuilder, collections.abc.Sequence):
def archive_files(self) -> List[str]: def archive_files(self) -> List[str]:
return [] return []
def __init__(self, pkg: spack.package_base.PackageBase) -> None: def __init__(self, pkg: B) -> None:
super().__init__(pkg) super().__init__(pkg)
self.callbacks = {} self.callbacks = {}
for phase in self.phases: for phase in self.phases: