diff --git a/src/gardenlinux/features/cname.py b/src/gardenlinux/features/cname.py index a1e2554c..27c8d064 100644 --- a/src/gardenlinux/features/cname.py +++ b/src/gardenlinux/features/cname.py @@ -8,7 +8,7 @@ from configparser import UNNAMED_SECTION, ConfigParser from os import PathLike, environ from pathlib import Path -from typing import List, Optional +from typing import List, Optional, Self from ..constants import ( ARCHS, @@ -74,7 +74,7 @@ def __init__( cname, ) - assert re_match, f"Not a valid GardenLinux canonical name {cname}" + assert re_match, f"Not a valid Garden Linux canonical name {cname}" if re_match.lastindex == 1: self._flavor = re_match[1] @@ -106,7 +106,7 @@ def __init__( if commit_id_or_hash is not None: self._commit_id = commit_id_or_hash[:8] - if len(commit_id_or_hash) == 40: # sha1 hex + if len(commit_id_or_hash) == 40 or commit_id_or_hash == "local": # sha1 hex self._commit_hash = commit_id_or_hash @property @@ -140,7 +140,7 @@ def cname(self) -> str: return cname @property - def commit_hash(self) -> str: + def commit_hash(self) -> Optional[str]: """ Returns the commit hash if part of the cname parsed. @@ -148,11 +148,6 @@ def commit_hash(self) -> str: :since: 1.0.0 """ - if self._commit_hash is None: - raise RuntimeError( - "GardenLinux canonical name given does not contain the commit hash" - ) - return self._commit_hash @commit_hash.setter @@ -391,6 +386,25 @@ def version_epoch(self) -> Optional[int]: return epoch + def _copy_from_cname_object(self, cname_object: Self) -> None: + """ + Copies values from a given Garden Linux canonical name instance. + + :param cname_object: Garden Linux canonical name instance + + :since: 1.0.0 + """ + + self._arch = cname_object.arch + self._commit_hash = cname_object.commit_hash + self._commit_id = cname_object.commit_id + self._feature_set_cached = cname_object.feature_set + self._feature_elements_cached = cname_object.feature_set_element.split(",") + self._feature_flags_cached = cname_object.feature_set_flag.split(",") + self._feature_platforms_cached = cname_object.feature_set_platform.split(",") + self._platform_variant_cached = cname_object.platform_variant + self._version = cname_object.version + def load_from_release_file(self, release_file: PathLike[str] | str) -> None: """ Loads and parses a release metadata file. @@ -400,6 +414,54 @@ def load_from_release_file(self, release_file: PathLike[str] | str) -> None: :since: 1.0.0 """ + cname_object = CName.new_from_release_file(release_file) + + if ( + cname_object.flavor != self.flavor + or ( + self._commit_id is not None + and self._commit_id != cname_object.commit_id + ) + or (self._version is not None and self._version != cname_object.version) + ): + raise RuntimeError( + f"Release metadata file given is invalid: {release_file} failed consistency check - {self.cname} != {cname_object.cname}" + ) + + self._copy_from_cname_object(cname_object) + + def save_to_release_file( + self, release_file: PathLike[str] | str, overwrite: Optional[bool] = False + ) -> None: + """ + Saves the release metadata file. + + :param release_file: Release metadata file + + :since: 1.0.0 + """ + + if not isinstance(release_file, PathLike): + release_file = Path(release_file) + + if not overwrite and release_file.exists(): # type: ignore[attr-defined] + raise RuntimeError( + f"Refused to overwrite existing release metadata file: {release_file}" + ) + + with release_file.open("w") as fp: # type: ignore[attr-defined] + fp.write(self.release_metadata_string) + + @staticmethod + def new_from_release_file(release_file: PathLike[str] | str) -> "CName": + """ + Loads and parses a release metadata file. + + :param release_file: Release metadata file + + :since: 0.10.10 + """ + if not isinstance(release_file, PathLike): release_file = Path(release_file) @@ -413,6 +475,7 @@ def load_from_release_file(self, release_file: PathLike[str] | str) -> None: for release_field in ( "GARDENLINUX_CNAME", + "GARDENLINUX_COMMIT_ID_LONG", "GARDENLINUX_FEATURES", "GARDENLINUX_FEATURES_ELEMENTS", "GARDENLINUX_FEATURES_FLAGS", @@ -424,14 +487,6 @@ def load_from_release_file(self, release_file: PathLike[str] | str) -> None: f"Release metadata file given is invalid: {release_file} misses {release_field}" ) - loaded_cname_instance = CName( - release_config.get(UNNAMED_SECTION, "GARDENLINUX_CNAME").strip("\"'") - ) - - commit_id = release_config.get(UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID").strip( - "\"'" - ) - commit_hash = release_config.get( UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID_LONG" ).strip("\"'") @@ -440,68 +495,37 @@ def load_from_release_file(self, release_file: PathLike[str] | str) -> None: "\"'" ) - if ( - loaded_cname_instance.flavor != self.flavor - or loaded_cname_instance.commit_id != commit_id - or (self._commit_id is not None and self._commit_id != commit_id) - or loaded_cname_instance.version != version - or (self._version is not None and self._version != version) - ): - raise RuntimeError( - f"Release metadata file given is invalid: {release_file} failed consistency check - {self.cname} != {loaded_cname_instance.cname}" - ) - - self._arch = loaded_cname_instance.arch - self._flavor = loaded_cname_instance.flavor - self._commit_hash = commit_hash - self._commit_id = commit_id - self._version = version + cname_object = CName( + release_config.get(UNNAMED_SECTION, "GARDENLINUX_CNAME").strip("\"'"), + commit_hash=commit_hash, + version=version, + ) - self._feature_set_cached = release_config.get( + cname_object._feature_set_cached = release_config.get( UNNAMED_SECTION, "GARDENLINUX_FEATURES" ).strip("\"'") - self._feature_elements_cached = ( + cname_object._feature_elements_cached = ( release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_ELEMENTS") .strip("\"'") .split(",") ) - self._feature_flags_cached = ( + cname_object._feature_flags_cached = ( release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_FLAGS") .strip("\"'") .split(",") ) - self._feature_platforms_cached = ( + cname_object._feature_platforms_cached = ( release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_PLATFORMS") .strip("\"'") .split(",") ) if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_PLATFORM_VARIANT"): - self._platform_variant_cached = release_config.get( + cname_object._platform_variant_cached = release_config.get( UNNAMED_SECTION, "GARDENLINUX_PLATFORM_VARIANT" ).strip("\"'") - def save_to_release_file( - self, release_file: PathLike[str] | str, overwrite: Optional[bool] = False - ) -> None: - """ - Saves the release metadata file. - - :param release_file: Release metadata file - - :since: 1.0.0 - """ - - if not isinstance(release_file, PathLike): - release_file = Path(release_file) - - if not overwrite and release_file.exists(): # type: ignore[attr-defined] - raise RuntimeError( - f"Refused to overwrite existing release metadata file: {release_file}" - ) - - with release_file.open("w") as fp: # type: ignore[attr-defined] - fp.write(self.release_metadata_string) + return cname_object diff --git a/src/gardenlinux/features/cname_main.py b/src/gardenlinux/features/cname_main.py index d5cf3ba1..517d1cd0 100644 --- a/src/gardenlinux/features/cname_main.py +++ b/src/gardenlinux/features/cname_main.py @@ -40,7 +40,7 @@ def main() -> None: args.cname, ) - assert re_match, f"Not a valid GardenLinux canonical name {args.cname}" + assert re_match, f"Not a valid Garden Linux canonical name {args.cname}" arch = args.arch commit_id_or_hash = args.commit diff --git a/src/gardenlinux/s3/s3_artifacts.py b/src/gardenlinux/s3/s3_artifacts.py index 25bb030d..30a181a9 100644 --- a/src/gardenlinux/s3/s3_artifacts.py +++ b/src/gardenlinux/s3/s3_artifacts.py @@ -158,6 +158,11 @@ def upload_from_directory( if secureboot is None: secureboot = "_trustedboot" in feature_list + commit_hash = cname_object.commit_hash + + if commit_hash is None: + commit_hash = "" + version_epoch = str(cname_object.version_epoch) if version_epoch is None: @@ -167,7 +172,7 @@ def upload_from_directory( "platform": cname_object.feature_set_platform, "architecture": cname_object.arch, "base_image": None, - "build_committish": cname_object.commit_hash, + "build_committish": commit_hash, "build_timestamp": datetime.fromtimestamp(release_timestamp).isoformat(), "gardenlinux_epoch": {version_epoch}, "logs": None, @@ -219,7 +224,7 @@ def upload_from_directory( "architecture": re_object.sub("+", cname_object.arch), "platform": re_object.sub("+", cname_object.platform), "version": re_object.sub("+", cname_object.version), # type: ignore[arg-type] - "committish": cname_object.commit_hash, + "committish": commit_hash, "md5sum": md5sum, "sha256sum": sha256sum, }