]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Allow specifying minimum mkosi version 2153/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 10 Dec 2023 12:17:45 +0000 (13:17 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 10 Dec 2023 12:23:27 +0000 (13:23 +0100)
Currently, users often get a confusing message about some property
not existing when they try to use an older version of mkosi to build
a configuration that requires a newer version. Let's improve on this
by allowing configurations to declare the minimum version required to
build the configuration.

mkosi/__init__.py
mkosi/config.py
mkosi/resources/mkosi.md
tests/test_json.py

index ea5a527d11e373016f4fe3b1507f6cba499985f0..2aa02a26fb8252b2764d5d700838c7ac68f4adc7 100644 (file)
@@ -38,6 +38,7 @@ from mkosi.config import (
     SecureBootSignTool,
     ShimBootloader,
     Verb,
+    __version__,
     format_bytes,
     format_tree,
     parse_config,
@@ -3004,6 +3005,12 @@ def run_verb(args: MkosiArgs, images: Sequence[MkosiConfig]) -> None:
         page(text, args.pager)
         return
 
+    for config in images:
+        if not config.minimum_version or config.minimum_version <= __version__:
+            continue
+
+        die(f"mkosi {config.minimum_version} or newer is required to build this configuration (found {__version__})")
+
     for config in images:
         check_workspace_directory(config)
 
index cbac37842bca5327192f105c9b0f0c6746670573..3882028b3cb65b5b6a9926c47380dc5f4369ff0c 100644 (file)
@@ -671,6 +671,18 @@ def config_parse_vsock_cid(value: Optional[str], old: Optional[int]) -> Optional
     return cid
 
 
+def config_parse_minimum_version(value: Optional[str], old: Optional[GenericVersion]) -> Optional[GenericVersion]:
+    if not value:
+        return old
+
+    new = GenericVersion(value)
+
+    if not old:
+        return new
+
+    return max(old, new)
+
+
 @dataclasses.dataclass(frozen=True)
 class MkosiConfigSetting:
     dest: str
@@ -873,6 +885,7 @@ class MkosiConfig:
     include: tuple[str, ...]
     images: tuple[str, ...]
     dependencies: tuple[str, ...]
+    minimum_version: Optional[GenericVersion]
 
     distribution: Distribution
     release: str
@@ -1245,6 +1258,12 @@ SETTINGS = (
         parse=config_make_list_parser(delimiter=","),
         help="Specify other images that this image depends on",
     ),
+    MkosiConfigSetting(
+        dest="minimum_version",
+        section="Config",
+        parse=config_parse_minimum_version,
+        help="Specify the minimum required mkosi version",
+    ),
     MkosiConfigSetting(
         dest="distribution",
         short="-d",
@@ -2952,6 +2971,7 @@ def summary(config: MkosiConfig) -> str:
                             Include: {line_join_list(config.include)}
                              Images: {line_join_list(config.images)}
                        Dependencies: {line_join_list(config.dependencies)}
+                    Minimum Version: {none_to_none(config.minimum_version)}
 
     {bold("DISTRIBUTION")}:
                        Distribution: {bold(config.distribution)}
@@ -3093,6 +3113,8 @@ class MkosiJsonEncoder(json.JSONEncoder):
     def default(self, o: Any) -> Any:
         if isinstance(o, StrEnum):
             return str(o)
+        elif isinstance(o, GenericVersion):
+            return str(o)
         elif isinstance(o, os.PathLike):
             return os.fspath(o)
         elif isinstance(o, uuid.UUID):
@@ -3172,6 +3194,12 @@ def json_type_transformer(refcls: Union[type[MkosiArgs], type[MkosiConfig]]) ->
             )
         return ret
 
+    def generic_version_transformer(
+        version: Optional[str],
+        fieldtype: type[Optional[GenericVersion]],
+    ) -> Optional[GenericVersion]:
+        return GenericVersion(version) if version is not None else None
+
     transformers = {
         Path: path_transformer,
         Optional[Path]: optional_path_transformer,
@@ -3195,6 +3223,7 @@ def json_type_transformer(refcls: Union[type[MkosiArgs], type[MkosiConfig]]) ->
         Verb: enum_transformer,
         DocFormat: enum_transformer,
         list[QemuDrive]: config_drive_transformer,
+        GenericVersion: generic_version_transformer,
     }
 
     def json_transformer(key: str, val: Any) -> Any:
index 6efc52750c6c8cecf3575d9112a57fc4569c3cd3..6ae670dbc0f0c3679187e0bb049a24d6d7fc2689 100644 (file)
@@ -464,6 +464,11 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
   image and will be pulled in as dependencies of this image when
   `Images=` is used.
 
+`MinimumVersion=`, `--minimum-version=`
+
+: The minimum mkosi version required to build this configuration. If
+  specified multiple times, the highest specified version is used.
+
 ### [Distribution] Section
 
 `Distribution=`, `--distribution=`, `-d`
index 2b13e6a7b04f445345974874c06c16b5ee50d076..a759b31ad87ae4a1990619118a6656d38e60dba6 100644 (file)
@@ -28,6 +28,7 @@ from mkosi.config import (
     Verb,
 )
 from mkosi.distributions import Distribution
+from mkosi.versioncomp import GenericVersion
 
 
 @pytest.mark.parametrize("path", [None, "/baz/qux"])
@@ -169,6 +170,7 @@ def test_config() -> None:
                 "json",
                 "changelog"
             ],
+            "MinimumVersion": "123",
             "Mirror": null,
             "NSpawnSettings": null,
             "Output": "outfile",
@@ -329,6 +331,7 @@ def test_config() -> None:
         locale_messages = "",
         make_initrd = False,
         manifest_format = [ManifestFormat.json, ManifestFormat.changelog],
+        minimum_version = GenericVersion("123"),
         mirror = None,
         nspawn_settings = None,
         output = "outfile",