diff --git a/src/bci_build/containercrate.py b/src/bci_build/containercrate.py deleted file mode 100644 index 6a429434e..000000000 --- a/src/bci_build/containercrate.py +++ /dev/null @@ -1,50 +0,0 @@ -"""Crate to handle multibuild containers in the generator.""" - - -class ContainerCrate: - """ContainerCrate is combining multiple container build flavors. - - This provides package-central functions like generating _service and - _multibuild files. - """ - - def __init__(self, containers: list): - """Assign the crate for every container.""" - self._all_build_flavors: dict[tuple, set] = {} - for container in containers: - if container.build_flavor: - self._all_build_flavors.setdefault( - (container.os_version, container.package_name), set() - ).add(container.build_flavor) - - for container in containers: - if container.crate is not None: - raise ValueError("Container is already part of a ContainerCrate") - container.crate = self - - def all_build_flavors(self, container) -> list[str]: - """Return all build flavors for this container in the crate""" - return sorted( - self._all_build_flavors.get( - (container.os_version, container.package_name), [""] - ) - ) - - def default_dockerfile(self, container) -> str: - buildrelease: str = "" - if container.build_release: - buildrelease = f"\n#!BuildVersion: workaround-for-an-obs-bug\n#!BuildRelease: {container.build_release}" - """Return a default Dockerfile to disable build on default flavor.""" - return f"""#!ExclusiveArch: do-not-build -#!ForceMultiVersion{buildrelease} - -# For this container we only build the Dockerfile.$flavor builds. -""" - - def multibuild(self, container) -> str: - """Return the _multibuild file string to write for this ContainerCrate.""" - flavors: str = "\n".join( - " " * 4 + f"{pkg}" - for pkg in self.all_build_flavors(container) - ) - return f"\n{flavors}\n" diff --git a/src/bci_build/package/__init__.py b/src/bci_build/package/__init__.py index c4d552972..f91dcd8a5 100644 --- a/src/bci_build/package/__init__.py +++ b/src/bci_build/package/__init__.py @@ -11,6 +11,7 @@ from dataclasses import field from pathlib import Path from typing import Literal +from typing import Sequence from typing import overload import jinja2 @@ -22,7 +23,6 @@ from bci_build.container_attributes import PackageType from bci_build.container_attributes import ReleaseStage from bci_build.container_attributes import SupportLevel -from bci_build.containercrate import ContainerCrate from bci_build.os_version import ALL_OS_LTSS_VERSIONS from bci_build.os_version import RELEASED_OS_VERSIONS from bci_build.os_version import OsVersion @@ -209,7 +209,7 @@ class BaseContainerImage(abc.ABC): build_flavor: str | None = None #: create that this container is part of - crate: ContainerCrate = None + family: ContainerFamily = None #: Add any replacements via `obs-service-replace_using_package_version #: `_ @@ -1108,11 +1108,17 @@ async def write_file_to_dest(fname: str, contents: str | bytes) -> None: if self.build_flavor: dfile = "Dockerfile" - tasks.append(write_file_to_dest(dfile, self.crate.default_dockerfile(self))) + tasks.append( + write_file_to_dest( + dfile, self.family.get_default_dockerfile_content(self) + ) + ) files.append(dfile) mname = "_multibuild" - tasks.append(write_file_to_dest(mname, self.crate.multibuild(self))) + tasks.append( + write_file_to_dest(mname, self.family.get_multibuild_file_content(self)) + ) files.append(mname) tasks.append( @@ -1435,6 +1441,85 @@ def prepare_template(self) -> None: pass +class ContainerFamily: + """ContainerFamily is grouping multiple containers build flavors. + + This provides package-central functions like generating _service and + _multibuild files, checking version_uid + """ + + def __init__( + self, + containers: Sequence[BaseContainerImage], + ): + # Assign the family for every container build flavor based on os version and package name + # Sample family structure: + # { + # (OsVersion.TumbleWeed, "test-package-name"): {"flavor1", "flavor2"} + # } + self._container_families: dict[tuple, set] = {} + for container in containers: + if container.build_flavor: + self._container_families.setdefault( + (container.os_version, container.package_name), set() + ).add(container.build_flavor) + + for container in containers: + if container.family is not None: + raise ValueError("Container is already part of a ContainerFamily") + container.family = self + + def get_all_build_flavors( + self, + container: BaseContainerImage, + ) -> list[str]: + """Return all available build flavors for this container in based on its family""" + return sorted( + self._container_families.get( + (container.os_version, container.package_name), [""] + ) + ) + + def get_default_dockerfile_content( + self, + container: BaseContainerImage, + ) -> str: + buildrelease: str = "" + if container.build_release: + buildrelease = f"\n#!BuildVersion: workaround-for-an-obs-bug\n#!BuildRelease: {container.build_release}" + """Return a default Dockerfile to disable build on default flavor.""" + return f"""#!ExclusiveArch: do-not-build +#!ForceMultiVersion{buildrelease} + +# For this container we only build the Dockerfile.$flavor builds. +""" + + def get_multibuild_file_content( + self, + container: BaseContainerImage, + ) -> str: + """Return the _multibuild file string to write for this container based on its family.""" + if not self.check_version_in_uid(container): + return "" + + flavors: str = "\n".join( + " " * 4 + f"{pkg}" + for pkg in self.get_all_build_flavors(container) + ) + return f"\n{flavors}\n" + + def check_version_in_uid( + self, + container: BaseContainerImage, + ) -> bool: + """check if version_in_uid is set to False if a container has more than one flavour""" + if len(self.get_all_build_flavors(container)) > 1 and getattr( + container, "version_in_uid", False + ): + return False + return True + + def generate_disk_size_constraints(size_gb: int) -> str: """Creates the contents of a :file:`_constraints` file for OBS to require workers with at least ``size_gb`` GB of disk space. diff --git a/src/bci_build/package/apache_tomcat.py b/src/bci_build/package/apache_tomcat.py index 1e3125280..417a73cc0 100644 --- a/src/bci_build/package/apache_tomcat.py +++ b/src/bci_build/package/apache_tomcat.py @@ -4,11 +4,11 @@ from bci_build.container_attributes import TCP from bci_build.container_attributes import PackageType -from bci_build.containercrate import ContainerCrate from bci_build.os_version import CAN_BE_LATEST_OS_VERSION from bci_build.os_version import OsVersion from bci_build.package import DOCKERFILE_RUN from bci_build.package import ApplicationStackContainer +from bci_build.package import ContainerFamily from bci_build.package import OsContainer from bci_build.package import Package from bci_build.package import Replacement @@ -150,4 +150,4 @@ def _get_java_packages(jre_major: int) -> list[str]: ) ] -TOMCAT_CRATE = ContainerCrate(TOMCAT_CONTAINERS) +TOMCAT_FAMILIES = ContainerFamily(TOMCAT_CONTAINERS) diff --git a/src/bci_build/package/package_versions.json b/src/bci_build/package/package_versions.json index db05ff168..f098d2d62 100644 --- a/src/bci_build/package/package_versions.json +++ b/src/bci_build/package/package_versions.json @@ -10,7 +10,7 @@ "5": "2.35", "6": "2.43", "7": "2.43", - "Tumbleweed": "2.47", + "Tumbleweed": "2.48", "version_format": "minor" }, "helm": { @@ -54,7 +54,7 @@ }, "spack": { "6": "0.21.3", - "7": "0.21.3", + "7": "0.23.0", "Tumbleweed": "0.23.0" }, "valkey": { diff --git a/src/bci_build/templates.py b/src/bci_build/templates.py index 64ebf2ed9..90cd45183 100644 --- a/src/bci_build/templates.py +++ b/src/bci_build/templates.py @@ -202,8 +202,8 @@ {%- set all_build_flavors = [""] %} -{%- if image.crate and image.build_flavor %} -{%- set all_build_flavors = image.crate.all_build_flavors(image) %} +{%- if image.family and image.build_flavor %} +{%- set all_build_flavors = image.family.get_all_build_flavors(image) %} {%- endif %} {%- for flavor in all_build_flavors %} {%- for replacement in image.replacements_via_service %} diff --git a/tests/test_crate.py b/tests/test_container_family.py similarity index 82% rename from tests/test_crate.py rename to tests/test_container_family.py index 15d0635ba..aaef5e639 100644 --- a/tests/test_crate.py +++ b/tests/test_container_family.py @@ -1,6 +1,6 @@ from bci_build.container_attributes import BuildType -from bci_build.containercrate import ContainerCrate from bci_build.os_version import OsVersion +from bci_build.package import ContainerFamily from bci_build.package import DevelopmentContainer _BASE_KWARGS = { @@ -19,11 +19,12 @@ def test_multibuild_with_multi_flavor_docker(): **_BASE_KWARGS, build_recipe_type=BuildType.DOCKER, build_flavor=flavor, + version_in_uid=False, ) for flavor in ("flavor1", "flavor2") ] assert ( - ContainerCrate(containers).multibuild(containers[0]) + ContainerFamily(containers).get_multibuild_file_content(containers[0]) == """ flavor1 flavor2 diff --git a/tests/test_service.py b/tests/test_service.py index bf7c74baf..71449b930 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -1,8 +1,8 @@ import pytest from bci_build.container_attributes import BuildType -from bci_build.containercrate import ContainerCrate from bci_build.os_version import OsVersion +from bci_build.package import ContainerFamily from bci_build.package import DevelopmentContainer from bci_build.package import ParseVersion from bci_build.package import Replacement @@ -181,7 +181,7 @@ def test_service_with_multi_flavor_docker(): ) for flavor in ("flavor1", "flavor2") ] - ContainerCrate(containers) + ContainerFamily(containers) assert ( SERVICE_TEMPLATE.render(