Skip to content

Commit 79bc336

Browse files
committed
Add support to read and write metadata for a GL canonical name
Signed-off-by: Tobias Wolf <[email protected]>
1 parent 97d6e1c commit 79bc336

File tree

1 file changed

+143
-3
lines changed

1 file changed

+143
-3
lines changed

src/gardenlinux/features/cname.py

Lines changed: 143 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44
Canonical name (cname)
55
"""
66

7-
from typing import Optional
7+
from configparser import ConfigParser, UNNAMED_SECTION
8+
from pathlib import Path
9+
from typing import List, Optional
10+
from os import PathLike
811
import re
912

1013
from ..constants import ARCHS
@@ -38,9 +41,11 @@ def __init__(self, cname, arch=None, commit_id=None, version=None):
3841
"""
3942

4043
self._arch = None
41-
self._flavor = None
4244
self._commit_id = None
45+
self._feature_set_cached = None
46+
self._flavor = None
4347
self._version = None
48+
self._platforms_cached = None
4449

4550
re_match = re.match(
4651
"([a-zA-Z0-9]+([\\_\\-][a-zA-Z0-9]+)*?)(-([a-z0-9]+)(-([a-z0-9.]+)-([a-z0-9]+))*)?$",
@@ -82,6 +87,7 @@ def arch(self) -> Optional[str]:
8287
Returns the architecture for the cname parsed.
8388
8489
:return: (str) CName architecture
90+
:since: 0.7.0
8591
"""
8692

8793
return self._arch
@@ -92,6 +98,7 @@ def cname(self) -> str:
9298
Returns the cname parsed.
9399
94100
:return: (str) CName
101+
:since: 0.7.0
95102
"""
96103

97104
cname = self._flavor
@@ -110,6 +117,7 @@ def commit_id(self) -> Optional[str]:
110117
Returns the commit ID if part of the cname parsed.
111118
112119
:return: (str) Commit ID
120+
:since: 0.7.0
113121
"""
114122

115123
return self._commit_id
@@ -120,6 +128,7 @@ def flavor(self) -> str:
120128
Returns the flavor for the cname parsed.
121129
122130
:return: (str) Flavor
131+
:since: 0.7.0
123132
"""
124133

125134
return self._flavor
@@ -130,8 +139,12 @@ def feature_set(self) -> str:
130139
Returns the feature set for the cname parsed.
131140
132141
:return: (str) Feature set of the cname
142+
:since: 0.7.0
133143
"""
134144

145+
if self._feature_set_cached is not None:
146+
return self._feature_set_cached
147+
135148
return Parser().filter_as_string(self.flavor)
136149

137150
@property
@@ -140,16 +153,35 @@ def platform(self) -> str:
140153
Returns the platform for the cname parsed.
141154
142155
:return: (str) Flavor
156+
:since: 0.7.0
157+
"""
158+
159+
if self._platforms_cached is not None:
160+
return ",".join(self._platforms_cached)
161+
162+
return ",".join(Parser().filter_as_dict(self.flavor)["platform"])
163+
164+
@property
165+
def platforms(self) -> List[str]:
166+
"""
167+
Returns the platforms for the cname parsed.
168+
169+
:return: (str) Flavor
170+
:since: 0.9.1
143171
"""
144172

145-
return re.split("[_-]", self._flavor, maxsplit=1)[0]
173+
if self._platforms_cached is not None:
174+
return self._platforms_cached
175+
176+
return Parser().filter_as_dict(self.flavor)["platform"]
146177

147178
@property
148179
def version(self) -> Optional[str]:
149180
"""
150181
Returns the version if part of the cname parsed.
151182
152183
:return: (str) Version
184+
:since: 0.7.0
153185
"""
154186

155187
return self._version
@@ -160,9 +192,117 @@ def version_and_commit_id(self) -> Optional[str]:
160192
Returns the version and commit ID if part of the cname parsed.
161193
162194
:return: (str) Version and commit ID
195+
:since: 0.7.0
163196
"""
164197

165198
if self._commit_id is None:
166199
return None
167200

168201
return f"{self._version}-{self._commit_id}"
202+
203+
def load_from_metadata_file(self, metadata_file: PathLike | str) -> None:
204+
"""
205+
Loads and parses a metadata file.
206+
207+
:param metadata_file: Metadata file containing information about the CName instance.
208+
209+
:since: 0.9.1
210+
"""
211+
212+
if not isinstance(metadata_file, PathLike):
213+
metadata_file = Path(metadata_file)
214+
215+
if not metadata_file.exists():
216+
raise RuntimeError(f"Metadata file given is invalid: {metadata_file}")
217+
218+
metadata_config = ConfigParser(allow_unnamed_section=True)
219+
metadata_config.read(metadata_file)
220+
221+
for metadata_field in (
222+
"GARDENLINUX_CNAME",
223+
"GARDENLINUX_FEATURES",
224+
"GARDENLINUX_FEATURES_PLATFORMS",
225+
"GARDENLINUX_VERSION",
226+
):
227+
if not metadata_config.has_option(UNNAMED_SECTION, metadata_field):
228+
raise RuntimeError(
229+
f"Metadata file given is invalid: {metadata_file} misses {metadata_field}"
230+
)
231+
232+
loaded_cname_instance = CName(
233+
metadata_config.get(UNNAMED_SECTION, "GARDENLINUX_CNAME")
234+
)
235+
236+
commit_id = metadata_config.get(UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID")
237+
version = metadata_config.get(UNNAMED_SECTION, "GARDENLINUX_VERSION")
238+
239+
if (
240+
loaded_cname_instance.flavor != self.flavor
241+
or loaded_cname_instance.commit_id != commit_id
242+
or (self._commit_id is not None and self._commit_id != commit_id)
243+
or loaded_cname_instance.version != version
244+
or (self._version is not None and self._version != version)
245+
):
246+
raise RuntimeError(
247+
f"Metadata file given is invalid: {metadata_file} failed consistency check - {self.cname} != {loaded_cname_instance.cname}"
248+
)
249+
250+
self._arch = loaded_cname_instance.arch
251+
self._flavor = loaded_cname_instance.flavor
252+
self._commit_id = commit_id
253+
self._version = version
254+
255+
self._feature_set_cached = metadata_config.get(
256+
UNNAMED_SECTION, "GARDENLINUX_FEATURES"
257+
)
258+
259+
self._platforms_cached = metadata_config.get(
260+
UNNAMED_SECTION, "GARDENLINUX_FEATURES_PLATFORMS"
261+
).split(",")
262+
263+
def save_to_metadata_file(
264+
self, metadata_file: PathLike | str, overwrite: Optional[bool] = False
265+
) -> None:
266+
"""
267+
Saves the metadata file.
268+
269+
:param metadata_file: Metadata file containing information about the CName instance.
270+
271+
:since: 0.9.1
272+
"""
273+
274+
if not isinstance(metadata_file, PathLike):
275+
metadata_file = Path(metadata_file)
276+
277+
if not overwrite and metadata_file.exists():
278+
raise RuntimeError(
279+
f"Refused to overwrite existing metadata file: {metadata_file}"
280+
)
281+
282+
features = Parser().filter_as_dict(self.flavor)
283+
284+
elements = ",".join(features["element"])
285+
flags = ",".join(features["flag"])
286+
platforms = ",".join(features["platform"])
287+
288+
metadata = f"""
289+
ID=gardenlinux
290+
NAME="Garden Linux"
291+
PRETTY_NAME="Garden Linux {self.version}"
292+
IMAGE_VERSION={self.version}
293+
VARIANT_ID="{self.flavor}-{self.arch}"
294+
HOME_URL="https://gardenlinux.io"
295+
SUPPORT_URL="https://github.com/gardenlinux/gardenlinux"
296+
BUG_REPORT_URL="https://github.com/gardenlinux/gardenlinux/issues"
297+
GARDENLINUX_CNAME="{self.cname}"
298+
GARDENLINUX_FEATURES="{self.feature_set}"
299+
GARDENLINUX_FEATURES_PLATFORMS="{platforms}"
300+
GARDENLINUX_FEATURES_ELEMENTS="{elements}"
301+
GARDENLINUX_FEATURES_FLAGS="{flags}"
302+
GARDENLINUX_VERSION="{self.version}"
303+
GARDENLINUX_COMMIT_ID="{self.commit_id}"
304+
GARDENLINUX_COMMIT_ID_LONG=$BUILDER_COMMIT
305+
""".strip()
306+
307+
with metadata_file.open("w") as fp:
308+
fp.write(metadata)

0 commit comments

Comments
 (0)