88from configparser import UNNAMED_SECTION , ConfigParser
99from os import PathLike , environ
1010from pathlib import Path
11- from typing import List , Optional
11+ from typing import List , Optional , Self
1212
1313from ..constants import (
1414 ARCHS ,
@@ -74,7 +74,7 @@ def __init__(
7474 cname ,
7575 )
7676
77- assert re_match , f"Not a valid GardenLinux canonical name { cname } "
77+ assert re_match , f"Not a valid Garden Linux canonical name { cname } "
7878
7979 if re_match .lastindex == 1 :
8080 self ._flavor = re_match [1 ]
@@ -106,7 +106,7 @@ def __init__(
106106 if commit_id_or_hash is not None :
107107 self ._commit_id = commit_id_or_hash [:8 ]
108108
109- if len (commit_id_or_hash ) == 40 : # sha1 hex
109+ if len (commit_id_or_hash ) == 40 or commit_id_or_hash == "local" : # sha1 hex
110110 self ._commit_hash = commit_id_or_hash
111111
112112 @property
@@ -140,19 +140,14 @@ def cname(self) -> str:
140140 return cname
141141
142142 @property
143- def commit_hash (self ) -> str :
143+ def commit_hash (self ) -> Optional [ str ] :
144144 """
145145 Returns the commit hash if part of the cname parsed.
146146
147147 :return: (str) Commit hash
148148 :since: 1.0.0
149149 """
150150
151- if self ._commit_hash is None :
152- raise RuntimeError (
153- "GardenLinux canonical name given does not contain the commit hash"
154- )
155-
156151 return self ._commit_hash
157152
158153 @commit_hash .setter
@@ -391,6 +386,25 @@ def version_epoch(self) -> Optional[int]:
391386
392387 return epoch
393388
389+ def _copy_from_cname_object (self , cname_object : Self ) -> None :
390+ """
391+ Copies values from a given Garden Linux canonical name instance.
392+
393+ :param cname_object: Garden Linux canonical name instance
394+
395+ :since: 1.0.0
396+ """
397+
398+ self ._arch = cname_object .arch
399+ self ._commit_hash = cname_object .commit_hash
400+ self ._commit_id = cname_object .commit_id
401+ self ._feature_set_cached = cname_object .feature_set
402+ self ._feature_elements_cached = cname_object .feature_set_element .split ("," )
403+ self ._feature_flags_cached = cname_object .feature_set_flag .split ("," )
404+ self ._feature_platforms_cached = cname_object .feature_set_platform .split ("," )
405+ self ._platform_variant_cached = cname_object .platform_variant
406+ self ._version = cname_object .version
407+
394408 def load_from_release_file (self , release_file : PathLike [str ] | str ) -> None :
395409 """
396410 Loads and parses a release metadata file.
@@ -400,6 +414,54 @@ def load_from_release_file(self, release_file: PathLike[str] | str) -> None:
400414 :since: 1.0.0
401415 """
402416
417+ cname_object = CName .new_from_release_file (release_file )
418+
419+ if (
420+ cname_object .flavor != self .flavor
421+ or (
422+ self ._commit_id is not None
423+ and self ._commit_id != cname_object .commit_id
424+ )
425+ or (self ._version is not None and self ._version != cname_object .version )
426+ ):
427+ raise RuntimeError (
428+ f"Release metadata file given is invalid: { release_file } failed consistency check - { self .cname } != { cname_object .cname } "
429+ )
430+
431+ self ._copy_from_cname_object (cname_object )
432+
433+ def save_to_release_file (
434+ self , release_file : PathLike [str ] | str , overwrite : Optional [bool ] = False
435+ ) -> None :
436+ """
437+ Saves the release metadata file.
438+
439+ :param release_file: Release metadata file
440+
441+ :since: 1.0.0
442+ """
443+
444+ if not isinstance (release_file , PathLike ):
445+ release_file = Path (release_file )
446+
447+ if not overwrite and release_file .exists (): # type: ignore[attr-defined]
448+ raise RuntimeError (
449+ f"Refused to overwrite existing release metadata file: { release_file } "
450+ )
451+
452+ with release_file .open ("w" ) as fp : # type: ignore[attr-defined]
453+ fp .write (self .release_metadata_string )
454+
455+ @staticmethod
456+ def new_from_release_file (release_file : PathLike [str ] | str ) -> "CName" :
457+ """
458+ Loads and parses a release metadata file.
459+
460+ :param release_file: Release metadata file
461+
462+ :since: 0.10.10
463+ """
464+
403465 if not isinstance (release_file , PathLike ):
404466 release_file = Path (release_file )
405467
@@ -413,6 +475,7 @@ def load_from_release_file(self, release_file: PathLike[str] | str) -> None:
413475
414476 for release_field in (
415477 "GARDENLINUX_CNAME" ,
478+ "GARDENLINUX_COMMIT_ID_LONG" ,
416479 "GARDENLINUX_FEATURES" ,
417480 "GARDENLINUX_FEATURES_ELEMENTS" ,
418481 "GARDENLINUX_FEATURES_FLAGS" ,
@@ -424,14 +487,6 @@ def load_from_release_file(self, release_file: PathLike[str] | str) -> None:
424487 f"Release metadata file given is invalid: { release_file } misses { release_field } "
425488 )
426489
427- loaded_cname_instance = CName (
428- release_config .get (UNNAMED_SECTION , "GARDENLINUX_CNAME" ).strip ("\" '" )
429- )
430-
431- commit_id = release_config .get (UNNAMED_SECTION , "GARDENLINUX_COMMIT_ID" ).strip (
432- "\" '"
433- )
434-
435490 commit_hash = release_config .get (
436491 UNNAMED_SECTION , "GARDENLINUX_COMMIT_ID_LONG"
437492 ).strip ("\" '" )
@@ -440,68 +495,37 @@ def load_from_release_file(self, release_file: PathLike[str] | str) -> None:
440495 "\" '"
441496 )
442497
443- if (
444- loaded_cname_instance .flavor != self .flavor
445- or loaded_cname_instance .commit_id != commit_id
446- or (self ._commit_id is not None and self ._commit_id != commit_id )
447- or loaded_cname_instance .version != version
448- or (self ._version is not None and self ._version != version )
449- ):
450- raise RuntimeError (
451- f"Release metadata file given is invalid: { release_file } failed consistency check - { self .cname } != { loaded_cname_instance .cname } "
452- )
453-
454- self ._arch = loaded_cname_instance .arch
455- self ._flavor = loaded_cname_instance .flavor
456- self ._commit_hash = commit_hash
457- self ._commit_id = commit_id
458- self ._version = version
498+ cname_object = CName (
499+ release_config .get (UNNAMED_SECTION , "GARDENLINUX_CNAME" ).strip ("\" '" ),
500+ commit_hash = commit_hash ,
501+ version = version ,
502+ )
459503
460- self ._feature_set_cached = release_config .get (
504+ cname_object ._feature_set_cached = release_config .get (
461505 UNNAMED_SECTION , "GARDENLINUX_FEATURES"
462506 ).strip ("\" '" )
463507
464- self ._feature_elements_cached = (
508+ cname_object ._feature_elements_cached = (
465509 release_config .get (UNNAMED_SECTION , "GARDENLINUX_FEATURES_ELEMENTS" )
466510 .strip ("\" '" )
467511 .split ("," )
468512 )
469513
470- self ._feature_flags_cached = (
514+ cname_object ._feature_flags_cached = (
471515 release_config .get (UNNAMED_SECTION , "GARDENLINUX_FEATURES_FLAGS" )
472516 .strip ("\" '" )
473517 .split ("," )
474518 )
475519
476- self ._feature_platforms_cached = (
520+ cname_object ._feature_platforms_cached = (
477521 release_config .get (UNNAMED_SECTION , "GARDENLINUX_FEATURES_PLATFORMS" )
478522 .strip ("\" '" )
479523 .split ("," )
480524 )
481525
482526 if release_config .has_option (UNNAMED_SECTION , "GARDENLINUX_PLATFORM_VARIANT" ):
483- self ._platform_variant_cached = release_config .get (
527+ cname_object ._platform_variant_cached = release_config .get (
484528 UNNAMED_SECTION , "GARDENLINUX_PLATFORM_VARIANT"
485529 ).strip ("\" '" )
486530
487- def save_to_release_file (
488- self , release_file : PathLike [str ] | str , overwrite : Optional [bool ] = False
489- ) -> None :
490- """
491- Saves the release metadata file.
492-
493- :param release_file: Release metadata file
494-
495- :since: 1.0.0
496- """
497-
498- if not isinstance (release_file , PathLike ):
499- release_file = Path (release_file )
500-
501- if not overwrite and release_file .exists (): # type: ignore[attr-defined]
502- raise RuntimeError (
503- f"Refused to overwrite existing release metadata file: { release_file } "
504- )
505-
506- with release_file .open ("w" ) as fp : # type: ignore[attr-defined]
507- fp .write (self .release_metadata_string )
531+ return cname_object
0 commit comments