From cdc67d6105a6a1f3c602551cbae5b7386ae8f34f Mon Sep 17 00:00:00 2001 From: Harmen Stoppels Date: Wed, 16 Apr 2025 10:44:20 +0200 Subject: [PATCH] builder: parametrize package type and fix a few cases of builders that didn't inherit from BuilderWithDefaults --- lib/spack/spack/build_systems/_checks.py | 4 ++-- lib/spack/spack/build_systems/autotools.py | 2 +- lib/spack/spack/build_systems/bundle.py | 4 +++- lib/spack/spack/build_systems/cargo.py | 2 +- lib/spack/spack/build_systems/cmake.py | 2 +- lib/spack/spack/build_systems/generic.py | 2 +- lib/spack/spack/build_systems/go.py | 2 +- lib/spack/spack/build_systems/lua.py | 4 +++- lib/spack/spack/build_systems/makefile.py | 2 +- lib/spack/spack/build_systems/maven.py | 2 +- lib/spack/spack/build_systems/meson.py | 2 +- lib/spack/spack/build_systems/msbuild.py | 2 +- lib/spack/spack/build_systems/nmake.py | 2 +- lib/spack/spack/build_systems/octave.py | 2 +- lib/spack/spack/build_systems/perl.py | 2 +- lib/spack/spack/build_systems/python.py | 2 +- lib/spack/spack/build_systems/qmake.py | 2 +- lib/spack/spack/build_systems/racket.py | 4 +++- lib/spack/spack/build_systems/ruby.py | 2 +- lib/spack/spack/build_systems/scons.py | 2 +- lib/spack/spack/build_systems/sip.py | 2 +- lib/spack/spack/build_systems/waf.py | 2 +- lib/spack/spack/builder.py | 15 +++++++++------ 23 files changed, 38 insertions(+), 29 deletions(-) diff --git a/lib/spack/spack/build_systems/_checks.py b/lib/spack/spack/build_systems/_checks.py index c1a9c529875..21efacd742f 100644 --- a/lib/spack/spack/build_systems/_checks.py +++ b/lib/spack/spack/build_systems/_checks.py @@ -2,7 +2,7 @@ # # SPDX-License-Identifier: (Apache-2.0 OR MIT) import os -from typing import List +from typing import Generic, List 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) -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.""" # Check that self.prefix is there after installation diff --git a/lib/spack/spack/build_systems/autotools.py b/lib/spack/spack/build_systems/autotools.py index b98f889c9d4..e4577ff7c16 100644 --- a/lib/spack/spack/build_systems/autotools.py +++ b/lib/spack/spack/build_systems/autotools.py @@ -79,7 +79,7 @@ def with_or_without(self, *args, **kwargs): @spack.builder.builder("autotools") -class AutotoolsBuilder(BuilderWithDefaults): +class AutotoolsBuilder(BuilderWithDefaults[AutotoolsPackage]): """The autotools builder encodes the default way of installing software built with autotools. It has four phases that can be overridden, if need be: diff --git a/lib/spack/spack/build_systems/bundle.py b/lib/spack/spack/build_systems/bundle.py index a9e8d83b57a..ab35a3a6da2 100644 --- a/lib/spack/spack/build_systems/bundle.py +++ b/lib/spack/spack/build_systems/bundle.py @@ -5,6 +5,8 @@ import spack.directives import spack.package_base +from ._checks import BuilderWithDefaults + class BundlePackage(spack.package_base.PackageBase): """General purpose bundle, or no-code, package class.""" @@ -23,7 +25,7 @@ class BundlePackage(spack.package_base.PackageBase): @spack.builder.builder("bundle") -class BundleBuilder(spack.builder.Builder): +class BundleBuilder(BuilderWithDefaults[BundlePackage]): phases = ("install",) def install(self, pkg, spec, prefix): diff --git a/lib/spack/spack/build_systems/cargo.py b/lib/spack/spack/build_systems/cargo.py index 5cfed66063b..c895d470872 100644 --- a/lib/spack/spack/build_systems/cargo.py +++ b/lib/spack/spack/build_systems/cargo.py @@ -30,7 +30,7 @@ class CargoPackage(spack.package_base.PackageBase): @spack.builder.builder("cargo") -class CargoBuilder(BuilderWithDefaults): +class CargoBuilder(BuilderWithDefaults[CargoPackage]): """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: diff --git a/lib/spack/spack/build_systems/cmake.py b/lib/spack/spack/build_systems/cmake.py index 87fa6f23fa3..c5462c1df7f 100644 --- a/lib/spack/spack/build_systems/cmake.py +++ b/lib/spack/spack/build_systems/cmake.py @@ -284,7 +284,7 @@ def define_from_variant(self, cmake_var: str, variant: Optional[str] = None) -> @spack.builder.builder("cmake") -class CMakeBuilder(BuilderWithDefaults): +class CMakeBuilder(BuilderWithDefaults[CMakePackage]): """The cmake builder encodes the default way of building software with CMake. IT has three phases that can be overridden: diff --git a/lib/spack/spack/build_systems/generic.py b/lib/spack/spack/build_systems/generic.py index d27495b31cf..908d73240cb 100644 --- a/lib/spack/spack/build_systems/generic.py +++ b/lib/spack/spack/build_systems/generic.py @@ -28,7 +28,7 @@ class Package(spack.package_base.PackageBase): @spack.builder.builder("generic") -class GenericBuilder(BuilderWithDefaults): +class GenericBuilder(BuilderWithDefaults[Package]): """A builder for a generic build system, that require packagers to implement an "install" phase. """ diff --git a/lib/spack/spack/build_systems/go.py b/lib/spack/spack/build_systems/go.py index 1c510679199..4a10267c8e3 100644 --- a/lib/spack/spack/build_systems/go.py +++ b/lib/spack/spack/build_systems/go.py @@ -33,7 +33,7 @@ class GoPackage(spack.package_base.PackageBase): @spack.builder.builder("go") -class GoBuilder(BuilderWithDefaults): +class GoBuilder(BuilderWithDefaults[GoPackage]): """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: diff --git a/lib/spack/spack/build_systems/lua.py b/lib/spack/spack/build_systems/lua.py index e9d05b2c75c..ae1e99eb90b 100644 --- a/lib/spack/spack/build_systems/lua.py +++ b/lib/spack/spack/build_systems/lua.py @@ -14,6 +14,8 @@ from spack.directives import build_system, depends_on, extends from spack.multimethod import when +from ._checks import BuilderWithDefaults + class LuaPackage(spack.package_base.PackageBase): """Specialized class for lua packages""" @@ -49,7 +51,7 @@ def luarocks(self): @spack.builder.builder("lua") -class LuaBuilder(spack.builder.Builder): +class LuaBuilder(BuilderWithDefaults[LuaPackage]): phases = ("unpack", "generate_luarocks_config", "preprocess", "install") #: Names associated with package methods in the old build-system format diff --git a/lib/spack/spack/build_systems/makefile.py b/lib/spack/spack/build_systems/makefile.py index 017e8e9decf..76477ba230d 100644 --- a/lib/spack/spack/build_systems/makefile.py +++ b/lib/spack/spack/build_systems/makefile.py @@ -38,7 +38,7 @@ class MakefilePackage(spack.package_base.PackageBase): @spack.builder.builder("makefile") -class MakefileBuilder(BuilderWithDefaults): +class MakefileBuilder(BuilderWithDefaults[MakefilePackage]): """The Makefile builder encodes the most common way of building software with Makefiles. It has three phases that can be overridden, if need be: diff --git a/lib/spack/spack/build_systems/maven.py b/lib/spack/spack/build_systems/maven.py index 4713d20e046..e89ef51a93a 100644 --- a/lib/spack/spack/build_systems/maven.py +++ b/lib/spack/spack/build_systems/maven.py @@ -35,7 +35,7 @@ class MavenPackage(spack.package_base.PackageBase): @spack.builder.builder("maven") -class MavenBuilder(BuilderWithDefaults): +class MavenBuilder(BuilderWithDefaults[MavenPackage]): """The Maven builder encodes the default way to build software with Maven. It has two phases that can be overridden, if need be: diff --git a/lib/spack/spack/build_systems/meson.py b/lib/spack/spack/build_systems/meson.py index 675623e4f4d..1cf372db6a3 100644 --- a/lib/spack/spack/build_systems/meson.py +++ b/lib/spack/spack/build_systems/meson.py @@ -67,7 +67,7 @@ def flags_to_build_system_args(self, flags): @spack.builder.builder("meson") -class MesonBuilder(BuilderWithDefaults): +class MesonBuilder(BuilderWithDefaults[MesonPackage]): """The Meson builder encodes the default way to build software with Meson. The builder has three phases that can be overridden, if need be: diff --git a/lib/spack/spack/build_systems/msbuild.py b/lib/spack/spack/build_systems/msbuild.py index 2081e688a6d..8861df1cd2d 100644 --- a/lib/spack/spack/build_systems/msbuild.py +++ b/lib/spack/spack/build_systems/msbuild.py @@ -27,7 +27,7 @@ class MSBuildPackage(spack.package_base.PackageBase): @spack.builder.builder("msbuild") -class MSBuildBuilder(BuilderWithDefaults): +class MSBuildBuilder(BuilderWithDefaults[MSBuildPackage]): """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: diff --git a/lib/spack/spack/build_systems/nmake.py b/lib/spack/spack/build_systems/nmake.py index 8362a0e5b5b..5c0174b868a 100644 --- a/lib/spack/spack/build_systems/nmake.py +++ b/lib/spack/spack/build_systems/nmake.py @@ -27,7 +27,7 @@ class NMakePackage(spack.package_base.PackageBase): @spack.builder.builder("nmake") -class NMakeBuilder(BuilderWithDefaults): +class NMakeBuilder(BuilderWithDefaults[NMakePackage]): """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: diff --git a/lib/spack/spack/build_systems/octave.py b/lib/spack/spack/build_systems/octave.py index 79e9bfd5708..6e2c035677e 100644 --- a/lib/spack/spack/build_systems/octave.py +++ b/lib/spack/spack/build_systems/octave.py @@ -31,7 +31,7 @@ class OctavePackage(spack.package_base.PackageBase): @spack.builder.builder("octave") -class OctaveBuilder(BuilderWithDefaults): +class OctaveBuilder(BuilderWithDefaults[OctavePackage]): """The octave builder provides the following phases that can be overridden: 1. :py:meth:`~.OctaveBuilder.install` diff --git a/lib/spack/spack/build_systems/perl.py b/lib/spack/spack/build_systems/perl.py index 4784d21b2a2..21e8bf976f9 100644 --- a/lib/spack/spack/build_systems/perl.py +++ b/lib/spack/spack/build_systems/perl.py @@ -89,7 +89,7 @@ def test_use(self): @spack.builder.builder("perl") -class PerlBuilder(BuilderWithDefaults): +class PerlBuilder(BuilderWithDefaults[PerlPackage]): """The perl builder provides four phases that can be overridden, if required: 1. :py:meth:`~.PerlBuilder.configure` diff --git a/lib/spack/spack/build_systems/python.py b/lib/spack/spack/build_systems/python.py index a88927a8a72..aae85fdd916 100644 --- a/lib/spack/spack/build_systems/python.py +++ b/lib/spack/spack/build_systems/python.py @@ -428,7 +428,7 @@ def libs(self) -> LibraryList: @spack.builder.builder("python_pip") -class PythonPipBuilder(BuilderWithDefaults): +class PythonPipBuilder(BuilderWithDefaults[PythonPackage]): phases = ("install",) #: Names associated with package methods in the old build-system format diff --git a/lib/spack/spack/build_systems/qmake.py b/lib/spack/spack/build_systems/qmake.py index 7d95db4d8e0..970c9268999 100644 --- a/lib/spack/spack/build_systems/qmake.py +++ b/lib/spack/spack/build_systems/qmake.py @@ -33,7 +33,7 @@ class QMakePackage(spack.package_base.PackageBase): @spack.builder.builder("qmake") -class QMakeBuilder(BuilderWithDefaults): +class QMakeBuilder(BuilderWithDefaults[QMakePackage]): """The qmake builder provides three phases that can be overridden: 1. :py:meth:`~.QMakeBuilder.qmake` diff --git a/lib/spack/spack/build_systems/racket.py b/lib/spack/spack/build_systems/racket.py index 5ea5c9444d3..0c681825b35 100644 --- a/lib/spack/spack/build_systems/racket.py +++ b/lib/spack/spack/build_systems/racket.py @@ -18,6 +18,8 @@ from spack.util.environment import env_flag from spack.util.executable import Executable, ProcessError +from ._checks import BuilderWithDefaults + def _homepage(cls: "RacketPackage") -> Optional[str]: if cls.racket_name: @@ -47,7 +49,7 @@ class RacketPackage(PackageBase): @spack.builder.builder("racket") -class RacketBuilder(spack.builder.Builder): +class RacketBuilder(BuilderWithDefaults[RacketPackage]): """The Racket builder provides an ``install`` phase that can be overridden.""" phases = ("install",) diff --git a/lib/spack/spack/build_systems/ruby.py b/lib/spack/spack/build_systems/ruby.py index f1263396c3e..525a9acabe4 100644 --- a/lib/spack/spack/build_systems/ruby.py +++ b/lib/spack/spack/build_systems/ruby.py @@ -29,7 +29,7 @@ class RubyPackage(spack.package_base.PackageBase): @spack.builder.builder("ruby") -class RubyBuilder(BuilderWithDefaults): +class RubyBuilder(BuilderWithDefaults[RubyPackage]): """The Ruby builder provides two phases that can be overridden if required: #. :py:meth:`~.RubyBuilder.build` diff --git a/lib/spack/spack/build_systems/scons.py b/lib/spack/spack/build_systems/scons.py index d47f0a428a3..c19cfb202ec 100644 --- a/lib/spack/spack/build_systems/scons.py +++ b/lib/spack/spack/build_systems/scons.py @@ -30,7 +30,7 @@ class SConsPackage(spack.package_base.PackageBase): @spack.builder.builder("scons") -class SConsBuilder(BuilderWithDefaults): +class SConsBuilder(BuilderWithDefaults[SConsPackage]): """The Scons builder provides the following phases that can be overridden: 1. :py:meth:`~.SConsBuilder.build` diff --git a/lib/spack/spack/build_systems/sip.py b/lib/spack/spack/build_systems/sip.py index 691e06605db..1f5841232a6 100644 --- a/lib/spack/spack/build_systems/sip.py +++ b/lib/spack/spack/build_systems/sip.py @@ -106,7 +106,7 @@ def test_imports(self): @spack.builder.builder("sip") -class SIPBuilder(BuilderWithDefaults): +class SIPBuilder(BuilderWithDefaults[SIPPackage]): """The SIP builder provides the following phases that can be overridden: * configure diff --git a/lib/spack/spack/build_systems/waf.py b/lib/spack/spack/build_systems/waf.py index 7bc7c889788..6c49f966b2b 100644 --- a/lib/spack/spack/build_systems/waf.py +++ b/lib/spack/spack/build_systems/waf.py @@ -32,7 +32,7 @@ class WafPackage(spack.package_base.PackageBase): @spack.builder.builder("waf") -class WafBuilder(BuilderWithDefaults): +class WafBuilder(BuilderWithDefaults[WafPackage]): """The WAF builder provides the following phases that can be overridden: * configure diff --git a/lib/spack/spack/builder.py b/lib/spack/spack/builder.py index ba9d7be3c04..bf0c1912283 100644 --- a/lib/spack/spack/builder.py +++ b/lib/spack/spack/builder.py @@ -5,7 +5,7 @@ import collections.abc import copy 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.multimethod @@ -393,7 +393,10 @@ def copy(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 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. @@ -402,7 +405,7 @@ class BaseBuilder(metaclass=BuilderMeta): .. code-block:: python - class AnyBuilder(BaseBuilder): + class AnyBuilder(BaseBuilder[AnyPackage]): @run_after("install") def fixup_install(self): # do something after the package is installed @@ -418,7 +421,7 @@ class AutotoolsBuilder(autotools.AutotoolsBuilder, AnyBuilder): pass """ - def __init__(self, pkg: spack.package_base.PackageBase) -> None: + def __init__(self, pkg: B) -> None: self.pkg = pkg @property @@ -484,7 +487,7 @@ def __str__(self): 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), knows how to install it. @@ -511,7 +514,7 @@ class Builder(BaseBuilder, collections.abc.Sequence): def archive_files(self) -> List[str]: return [] - def __init__(self, pkg: spack.package_base.PackageBase) -> None: + def __init__(self, pkg: B) -> None: super().__init__(pkg) self.callbacks = {} for phase in self.phases: