diff --git a/src/bci_build/package/__init__.py b/src/bci_build/package/__init__.py index 356d75124..f33750fb3 100644 --- a/src/bci_build/package/__init__.py +++ b/src/bci_build/package/__init__.py @@ -28,6 +28,7 @@ from bci_build.registry import ApplicationCollectionRegistry from bci_build.registry import Registry from bci_build.registry import publish_registry +from bci_build.service import Service from bci_build.templates import DOCKERFILE_TEMPLATE from bci_build.templates import INFOHEADER_TEMPLATE from bci_build.templates import KIWI_TEMPLATE @@ -107,6 +108,21 @@ def __post_init__(self) -> None: if self.file_name and "readme" in self.file_name.lower(): raise ValueError(f"Cannot replace variables in {self.file_name}!") + def to_service(self, default_file_name: str) -> Service: + """Convert this replacement into a + :py:class:`~bci__build.service.Service`. + + """ + return Service( + name="replace_using_package_version", + param=[ + ("file", self.file_name or default_file_name), + ("regex", self.regex_in_build_description), + ("package", self.package_name), + ] + + ([("parse-version", self.parse_version)] if self.parse_version else []), + ) + def _build_tag_prefix(os_version: OsVersion) -> str: if os_version == OsVersion.TUMBLEWEED: diff --git a/src/bci_build/service.py b/src/bci_build/service.py new file mode 100644 index 000000000..24dea7348 --- /dev/null +++ b/src/bci_build/service.py @@ -0,0 +1,41 @@ +"""This module includes an abstraction over source services in the Open Build +Service. + +""" + +import xml.etree.ElementTree as ET +from dataclasses import dataclass +from dataclasses import field +from typing import Literal + + +@dataclass(kw_only=True, frozen=True) +class Service: + """Representation of an arbitrary source service in the Open Build Service.""" + + #: name of this service + name: str + + #: unsorted list of parameters of this source service as a list of tuples + #: where the first value is the parameter's name and the second is the + #: parameter's value + param: list[tuple[str, str]] = field(default_factory=list) + + #: service mode (i.e. when the service runs) + mode: Literal["buildtime"] = "buildtime" + + def as_xml_element(self) -> ET.Element: + """Coverts this source service into a + :py:class:`~xml.etree.ElementTree.Element`. + + """ + root = ET.Element("service", attrib={"name": self.name, "mode": self.mode}) + + for param in self.param: + (p := ET.Element("param", attrib={"name": param[0]})).text = param[1] + root.append(p) + + return root + + def __str__(self) -> str: + return ET.tostring(self.as_xml_element()).decode("utf-8") diff --git a/tests/test_service.py b/tests/test_service.py index 10ab80d7f..7dd59d2c7 100644 --- a/tests/test_service.py +++ b/tests/test_service.py @@ -1,11 +1,69 @@ +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 DevelopmentContainer from bci_build.package import ParseVersion from bci_build.package import Replacement +from bci_build.service import Service from bci_build.templates import SERVICE_TEMPLATE + +def test_service_without_params_as_xml(): + assert """""" == str(Service(name="foo")) + + +def test_service_with_params_as_xml(): + assert ( + """barfoo""" + == str(Service(name="foo", param=[("baz", "bar"), ("baz", "foo")])) + ) + + +@pytest.mark.parametrize( + "replacement, default_file_name, service", + [ + # bare bone example + ( + Replacement(regex := "%%ver%%", pkg := "pkgFoo"), + "Dockerfile", + Service( + name=(name := "replace_using_package_version"), + param=[("file", "Dockerfile"), ("regex", regex), ("package", pkg)], + ), + ), + # the default file name is ignored if the parameter file_name is given + ( + Replacement(regex, pkg, file_name=(fname := "testfile")), + "Dockerfile", + Service( + name=name, + param=[("file", fname), ("regex", regex), ("package", pkg)], + ), + ), + # specify a parse_version + ( + Replacement(regex, pkg, parse_version=ParseVersion.MAJOR), + "Dockerfile", + Service( + name=name, + param=[ + ("file", "Dockerfile"), + ("regex", regex), + ("package", pkg), + ("parse-version", "major"), + ], + ), + ), + ], +) +def test_replacement_to_service( + replacement: Replacement, default_file_name: str, service: Service +): + assert replacement.to_service(default_file_name) == service + + _BASE_KWARGS = { "name": "test", "package_name": "test-image",