Skip to content

Commit 5a2204b

Browse files
committed
Add support to read and write metadata for a GL canonical name
Signed-off-by: Tobias Wolf <[email protected]>
1 parent 8d6fb94 commit 5a2204b

File tree

2 files changed

+144
-4
lines changed

2 files changed

+144
-4
lines changed

src/gardenlinux/features/cname.py

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

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

1013
from ..constants import ARCHS
1114
from .parser import Parser
@@ -37,9 +40,11 @@ def __init__(self, cname, arch=None, commit_id=None, version=None):
3740
"""
3841

3942
self._arch = None
40-
self._flavor = None
4143
self._commit_id = None
44+
self._feature_set_cached = None
45+
self._flavor = None
4246
self._version = None
47+
self._platforms_cached = None
4348

4449
re_match = re.match(
4550
"([a-zA-Z0-9]+([\\_\\-][a-zA-Z0-9]+)*?)(-([a-z0-9]+)(-([a-z0-9.]+)-([a-z0-9]+))*)?$",
@@ -81,6 +86,7 @@ def arch(self) -> Optional[str]:
8186
Returns the architecture for the cname parsed.
8287
8388
:return: (str) CName architecture
89+
:since: 0.7.0
8490
"""
8591

8692
return self._arch
@@ -91,6 +97,7 @@ def cname(self) -> str:
9197
Returns the cname parsed.
9298
9399
:return: (str) CName
100+
:since: 0.7.0
94101
"""
95102

96103
cname = self._flavor
@@ -109,6 +116,7 @@ def commit_id(self) -> Optional[str]:
109116
Returns the commit ID if part of the cname parsed.
110117
111118
:return: (str) Commit ID
119+
:since: 0.7.0
112120
"""
113121

114122
return self._commit_id
@@ -119,6 +127,7 @@ def flavor(self) -> str:
119127
Returns the flavor for the cname parsed.
120128
121129
:return: (str) Flavor
130+
:since: 0.7.0
122131
"""
123132

124133
return self._flavor
@@ -129,8 +138,12 @@ def feature_set(self) -> str:
129138
Returns the feature set for the cname parsed.
130139
131140
:return: (str) Feature set of the cname
141+
:since: 0.7.0
132142
"""
133143

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

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

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

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

154186
return self._version
@@ -159,9 +191,117 @@ def version_and_commit_id(self) -> Optional[str]:
159191
Returns the version and commit ID if part of the cname parsed.
160192
161193
:return: (str) Version and commit ID
194+
:since: 0.7.0
162195
"""
163196

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

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

tests/s3/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class S3Env:
2222

2323

2424
def make_cname(
25-
flavor: str = "testcname",
25+
flavor: str = "container",
2626
arch: str = "amd64",
2727
version: str = "1234.1",
2828
commit: str = "abc123",

0 commit comments

Comments
 (0)