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(