]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Rename Presets to Images 2007/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Sun, 22 Oct 2023 18:26:12 +0000 (20:26 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 23 Oct 2023 09:28:21 +0000 (11:28 +0200)
Presets doesn't really have any meaning without searching up its
definition. By just using mkosi.images/, it's much clearer that the
directory contains image definitions compared to mkosi.presets/.

The old names are kept intact for backwards compatibility.

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

diff --git a/NEWS.md b/NEWS.md
index aabe8b62e343427dd07413fd6ce68b70e0f0bf85..bdcebc7ace6ec1aa6c5999974bb42030e8ddd81b 100644 (file)
--- a/NEWS.md
+++ b/NEWS.md
 - We now make sure git can be executed from mkosi scripts without
   running into permission errors
 - `WithDocs=` is now enabled by default.
+- `Presets` were renamed to `Images`. `mkosi.images/` is now used
+  instead of `mkosi.presets/`,  the `Presets=` setting was renamed
+  to `Images=` and the `Presets` section was merged into the `Config`
+  section. The old names can still be used for backwards
+  compatibility.
 
 ## v18
 
index 7989e46c4ed39c5a12d0832110f725d7a773cf8b..9c9be89420f19fedc1251b459d31b37c96ec4e18 100644 (file)
@@ -1573,8 +1573,8 @@ def cache_tree_paths(config: MkosiConfig) -> tuple[Path, Path, Path]:
 
 def check_inputs(config: MkosiConfig) -> None:
     """
-    Make sure all the inputs that aren't checked during config parsing because they might be created by an
-    earlier preset exist.
+    Make sure all the inputs exist that aren't checked during config parsing because they might be created by an
+    earlier build.
     """
     for base in config.base_trees:
         if not base.exists():
@@ -2239,7 +2239,7 @@ def run_shell(args: MkosiArgs, config: MkosiConfig) -> None:
         ]
 
     # Underscores are not allowed in machine names so replace them with hyphens.
-    cmdline += ["--machine", (config.image_id or config.preset or config.output).replace("_", "-")]
+    cmdline += ["--machine", (config.image_id or config.image or config.output).replace("_", "-")]
 
     for k, v in config.credentials.items():
         cmdline += [f"--set-credential={k}:{v}"]
@@ -2424,10 +2424,10 @@ def prepend_to_environ_path(config: MkosiConfig) -> Iterator[None]:
             os.environ["PATH"] = ":".join(olds)
 
 
-def finalize_tools(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> Sequence[MkosiConfig]:
+def finalize_tools(args: MkosiArgs, images: Sequence[MkosiConfig]) -> Sequence[MkosiConfig]:
     new = []
 
-    for p in presets:
+    for p in images:
         if not p.tools_tree or p.tools_tree.name != "default":
             new.append(p)
             continue
@@ -2468,7 +2468,7 @@ def finalize_tools(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> Sequence[
         ]
 
         _, [config] = parse_config(cmdline)
-        config = dataclasses.replace(config, preset=f"{distribution}-tools")
+        config = dataclasses.replace(config, image=f"{distribution}-tools")
 
         if config not in new:
             new.append(config)
@@ -2508,7 +2508,7 @@ def mount_tools(tree: Optional[Path]) -> Iterator[None]:
         yield
 
 
-def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
+def run_verb(args: MkosiArgs, images: Sequence[MkosiConfig]) -> None:
     if args.verb.needs_root() and os.getuid() != 0:
         die(f"Must be root to run the {args.verb} command")
 
@@ -2518,7 +2518,7 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
     if args.verb == Verb.genkey:
         return generate_key_cert_pair(args)
 
-    if all(p == MkosiConfig.default() for p in presets):
+    if all(config == MkosiConfig.default() for config in images):
         die("No configuration found",
             hint="Make sure you're running mkosi from a directory with configuration files")
 
@@ -2528,19 +2528,19 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
     if args.verb == Verb.summary:
         if args.json:
             text = json.dumps(
-                {"Presets": [p.to_dict() for p in presets]},
+                {"Images": [config.to_dict() for config in images]},
                 cls=MkosiJsonEncoder,
                 indent=4,
                 sort_keys=True
             )
         else:
-            text = "\n".join(summary(p) for p in presets)
+            text = "\n".join(summary(config) for config in images)
 
         page(text, args.pager)
         return
 
-    presets = finalize_tools(args, presets)
-    last = presets[-1]
+    images = finalize_tools(args, images)
+    last = images[-1]
 
     if args.verb in (Verb.shell, Verb.boot):
         opname = "acquire shell in" if args.verb == Verb.shell else "boot"
@@ -2549,7 +2549,7 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
         if last.compress_output:
             die(f"Sorry, can't {opname} a compressed image.")
 
-    for config in presets:
+    for config in images:
         if args.verb == Verb.build and not args.force:
             check_outputs(config)
 
@@ -2558,7 +2558,7 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
     # execution are forcibly loaded early here.
     try_import("importlib.readers")
     try_import("importlib.resources.readers")
-    for config in presets:
+    for config in images:
         try_import(f"mkosi.distributions.{config.distribution}")
 
     # After we unshare the user namespace, we might not have access to /dev/kvm or related device nodes anymore as
@@ -2581,10 +2581,10 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
         if Path(d).exists():
             run(["mount", "--rbind", d, d, "--options", "ro"])
 
-    # First, process all directory removals because otherwise if different presets share directories a later
-    # preset could end up output generated by an earlier preset.
+    # First, process all directory removals because otherwise if different images share directories a later
+    # image build could end up deleting the output generated by an earlier image build.
 
-    for config in presets:
+    for config in images:
         if not needs_build(args, config) and args.verb != Verb.clean:
             continue
 
@@ -2595,14 +2595,14 @@ def run_verb(args: MkosiArgs, presets: Sequence[MkosiConfig]) -> None:
 
     build = False
 
-    for config in presets:
+    for config in images:
         check_inputs(config)
 
         if not needs_build(args, config):
             continue
 
         with (
-            complete_step(f"Building {config.preset or 'default'} image"),\
+            complete_step(f"Building {config.image or 'default'} image"),\
             mount_tools(config.tools_tree),\
             mount_passwd(),\
             prepend_to_environ_path(config)\
index 79e8926a7c103fe70d0c2e89ded7fed3d727b901..2572bf4243acd99536ae4bf964c6ce5ffd3ae072 100644 (file)
@@ -43,13 +43,13 @@ def propagate_failed_return() -> Iterator[None]:
 @propagate_failed_return()
 def main() -> None:
     log_setup()
-    args, presets = parse_config(sys.argv[1:])
+    args, images = parse_config(sys.argv[1:])
 
     if args.debug:
         faulthandler.enable()
 
     try:
-        run_verb(args, presets)
+        run_verb(args, images)
     finally:
         if sys.stderr.isatty() and shutil.which("tput"):
             run(["tput", "cnorm"], check=False)
index 2e0508b975b1aeb6c6dc796085d06ad75aa06a24..9bdb87c399ef4b9080350d21eb9a47acd1bc64a6 100644 (file)
@@ -717,7 +717,7 @@ class MkosiConfig:
 
     profile: Optional[str]
     include: tuple[str, ...]
-    presets: tuple[str, ...]
+    images: tuple[str, ...]
     dependencies: tuple[str, ...]
 
     distribution: Distribution
@@ -834,7 +834,7 @@ class MkosiConfig:
     qemu_kernel: Optional[Path]
     qemu_args: list[str]
 
-    preset: Optional[str]
+    image: Optional[str]
 
     def output_dir_or_cwd(self) -> Path:
         return self.output_dir or Path.cwd()
@@ -1058,18 +1058,19 @@ SETTINGS = (
         match=config_make_string_matcher(),
     ),
     MkosiConfigSetting(
-        dest="presets",
-        long="--preset",
-        section="Preset",
+        dest="images",
+        compat_names=("Presets",),
+        long="--image",
+        section="Config",
         parse=config_make_list_parser(delimiter=","),
-        help="Specify which presets to build",
+        help="Specify which images to build",
     ),
     MkosiConfigSetting(
         dest="dependencies",
         long="--dependency",
-        section="Preset",
+        section="Config",
         parse=config_make_list_parser(delimiter=","),
-        help="Specify other presets that this preset depends on",
+        help="Specify other images that this image depends on",
     ),
     MkosiConfigSetting(
         dest="distribution",
@@ -2092,31 +2093,31 @@ def create_argument_parser(action: type[argparse.Action]) -> argparse.ArgumentPa
     return parser
 
 
-def resolve_deps(presets: Sequence[MkosiConfig], include: Sequence[str]) -> list[MkosiConfig]:
-    graph = {p.preset: p.dependencies for p in presets}
+def resolve_deps(images: Sequence[MkosiConfig], include: Sequence[str]) -> list[MkosiConfig]:
+    graph = {config.image: config.dependencies for config in images}
 
     if include:
-        if any((missing := p) not in graph for p in include):
-            die(f"No preset found with name {missing}")
+        if any((missing := i) not in graph for i in include):
+            die(f"No image found with name {missing}")
 
         deps = set()
         queue = [*include]
 
         while queue:
-            if (preset := queue.pop(0)) not in deps:
-                deps.add(preset)
-                queue.extend(graph[preset])
+            if (image := queue.pop(0)) not in deps:
+                deps.add(image)
+                queue.extend(graph[image])
 
-        presets = [p for p in presets if p.preset in deps]
+        images = [config for config in images if config.image in deps]
 
-    graph = {p.preset: p.dependencies for p in presets}
+    graph = {config.image: config.dependencies for config in images}
 
     try:
         order = list(graphlib.TopologicalSorter(graph).static_order())
     except graphlib.CycleError as e:
-        die(f"Preset dependency cycle detected: {' => '.join(e.args[1])}")
+        die(f"Image dependency cycle detected: {' => '.join(e.args[1])}")
 
-    return sorted(presets, key=lambda p: order.index(p.preset))
+    return sorted(images, key=lambda i: order.index(i.image))
 
 
 def parse_config(argv: Sequence[str] = ()) -> tuple[MkosiArgs, tuple[MkosiConfig, ...]]:
@@ -2309,7 +2310,7 @@ def parse_config(argv: Sequence[str] = ()) -> tuple[MkosiArgs, tuple[MkosiConfig
         if path.exists():
             logging.debug(f"Including configuration file {Path.cwd() / path}")
 
-            for section, k, v in parse_ini(path, only_sections={s.section for s in SETTINGS}):
+            for section, k, v in parse_ini(path, only_sections={s.section for s in SETTINGS} | {"Preset"}):
                 name = k.removeprefix("@")
                 ns = namespace if k == name else defaults
 
@@ -2360,7 +2361,7 @@ def parse_config(argv: Sequence[str] = ()) -> tuple[MkosiArgs, tuple[MkosiConfig
         for s in SETTINGS:
             finalize_default(s, namespace, defaults)
 
-    presets = []
+    images = []
     namespace = argparse.Namespace()
     defaults = argparse.Namespace()
 
@@ -2398,43 +2399,50 @@ def parse_config(argv: Sequence[str] = ()) -> tuple[MkosiArgs, tuple[MkosiConfig
     if args.directory is not None:
         parse_config(Path("."), namespace, defaults, profiles=True)
 
-        finalize_default(SETTINGS_LOOKUP_BY_DEST["presets"], namespace, defaults)
-        include = getattr(namespace, "presets")
-        immutable_settings.add("Presets")
+        finalize_default(SETTINGS_LOOKUP_BY_DEST["images"], namespace, defaults)
+        include = getattr(namespace, "images")
+        immutable_settings.add("Images")
 
-        if Path("mkosi.presets").exists():
-            for p in Path("mkosi.presets").iterdir():
+        d: Optional[Path]
+        for d in (Path("mkosi.images"), Path("mkosi.presets")):
+            if Path(d).exists():
+                break
+        else:
+            d = None
+
+        if d:
+            for p in d.iterdir():
                 if not p.is_dir() and not p.suffix == ".conf":
                     continue
 
                 name = p.name.removesuffix(".conf")
                 if not name:
-                    die(f"{p} is not a valid preset name")
+                    die(f"{p} is not a valid image name")
 
                 ns_copy = copy.deepcopy(namespace)
                 defaults_copy = copy.deepcopy(defaults)
 
-                setattr(ns_copy, "preset", name)
+                setattr(ns_copy, "image", name)
 
                 with chdir(p if p.is_dir() else Path.cwd()):
                     if not parse_config(p if p.is_file() else Path("."), ns_copy, defaults_copy):
                         continue
 
                 finalize_defaults(ns_copy, defaults_copy)
-                presets += [ns_copy]
+                images += [ns_copy]
 
-    if not presets:
-        setattr(namespace, "preset", None)
+    if not images:
+        setattr(namespace, "image", None)
         finalize_defaults(namespace, defaults)
-        presets = [namespace]
+        images = [namespace]
 
-    if not presets:
-        die("No presets defined in mkosi.presets/")
+    if not images:
+        die("No images defined in mkosi.images/")
 
-    presets = [load_config(ns) for ns in presets]
-    presets = resolve_deps(presets, include)
+    images = [load_config(ns) for ns in images]
+    images = resolve_deps(images, include)
 
-    return args, tuple(presets)
+    return args, tuple(images)
 
 
 def load_credentials(args: argparse.Namespace) -> dict[str, str]:
@@ -2574,7 +2582,7 @@ def load_config(args: argparse.Namespace) -> MkosiConfig:
         args.checksum = True
 
     if args.output is None:
-        args.output = args.image_id or args.preset or "image"
+        args.output = args.image_id or args.image or "image"
 
     args.credentials = load_credentials(args)
     args.kernel_command_line_extra = load_kernel_command_line_extra(args)
@@ -2683,14 +2691,12 @@ def summary(config: MkosiConfig) -> str:
     env = [f"{k}={v}" for k, v in config.environment.items()]
 
     summary = f"""\
-{bold(f"PRESET: {config.preset or 'default'}")}
+{bold(f"IMAGE: {config.image or 'default'}")}
 
     {bold("CONFIG")}:
                        Profile: {none_to_none(config.profile)}
                        Include: {line_join_list(config.include)}
-
-    {bold("PRESET")}:
-                       Presets: {line_join_list(config.presets)}
+                        Images: {line_join_list(config.images)}
                   Dependencies: {line_join_list(config.dependencies)}
 
     {bold("DISTRIBUTION")}:
index ce3a9f5c93f7d54e22c852c32626b2a3d834adf5..a6a8789fdf0c3ada9a871d39dc5acf740836a6af 100644 (file)
@@ -386,25 +386,23 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
 : Note that each path containing extra configuration is only parsed
   once, even if included more than once with `Include=`.
 
-### [Preset] Section
+`Images=`, `--image=`
 
-`Presets=`, `--preset=`
-
-: If specified, only build the given presets. Can be specified multiple
-  times to build multiple presets. All the given presets and their
-  dependencies are built. If not specified, all presets are built. See
-  the **Presets** section for more information.
+: If specified, only build the given image. Can be specified multiple
+  times to build multiple images. All the given images and their
+  dependencies are built. If not specified, all images are built. See
+  the **Building multiple images** section for more information.
 
 : Note that this section only takes effect when specified in the global
-  configuration files. It has no effect if specified as a preset
+  configuration files. It has no effect if specified as an image
   specific setting.
 
 `Dependencies=`, `--dependency=`
 
-: The presets that this preset depends on specified as a comma-separated
-  list. All presets configured in this option will be built before this
-  preset and will be pulled in as dependencies of this preset when
-  `Presets=` is used.
+: The images that this image depends on specified as a comma-separated
+  list. All images configured in this option will be built before this
+  image and will be pulled in as dependencies of this image when
+  `Images=` is used.
 
 ### [Distribution] Section
 
@@ -1223,7 +1221,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
   given tools tree.
 
 : If set to `default`, mkosi will automatically add an extra tools tree
-  preset and use it as the tools tree. The following table shows for
+  image and use it as the tools tree. The following table shows for
   which distributions default tools tree packages are defined and which
   packages are included in those default tools trees:
 
@@ -1409,7 +1407,7 @@ in consecutive runs with data from the cached one.
    - `/media`
    - `/mnt`
 
-Then, for each preset, we execute the following steps:
+Then, for each image, we execute the following steps:
 
 6. Copy package manager trees into the workspace
 7. Copy base trees (`--base-tree=`) into the image
@@ -1764,26 +1762,26 @@ script. When all three are enabled together turn-around times for
 complete image builds are minimal, as only changed source files need to
 be recompiled.
 
-# PRESETS
+# Building multiple images
 
-Presets allow building more than one image with mkosi. Presets are
-loaded from the `mkosi.presets/` directory. Presets can be either
-directories containing mkosi configuration files or regular files with
-the `.conf` extension.
+If the `mkosi.images/` directory exists, mkosi will load individual
+image configurations from it and build each of them. Image
+configurations can be either directories containing mkosi configuration
+files or regular files with the `.conf` extension.
 
-When presets are found in `mkosi.presets/`, mkosi will build the
-configured preset and its dependencies (or all of them if no presets
-were explicitly configured using `Presets=`). To add dependencies
-between presets, the `Dependencies=` setting can be used.
+When image configurations are found in `mkosi.images/`, mkosi will build
+the configured images and all of their dependencies (or all of them if
+no images were explicitly configured using `Images=`). To add
+dependencies between images, the `Dependencies=` setting can be used.
 
-When presets are defined, mkosi will first read the global configuration
-(configuration outside of the `mkosi.presets/` directory), followed by
-the preset specific configuration. This means that global configuration
-takes precedence over preset specific configuration.
+When images are defined, mkosi will first read the global configuration
+(configuration outside of the `mkosi.images/` directory), followed by
+the image specific configuration. This means that global configuration
+takes precedence over image specific configuration.
 
-Presets can refer to outputs of presets they depend on. Specifically,
+Images can refer to outputs of images they depend on. Specifically,
 for the following options, mkosi will only check whether the inputs
-exist just before building the preset:
+exist just before building the image:
 
 - `BaseTrees=`
 - `PackageManagerTrees=`
@@ -1792,12 +1790,14 @@ exist just before building the preset:
 - `ToolsTree=`
 - `Initrds=`
 
-To refer to outputs of a preset's dependencies, simply configure any of
+To refer to outputs of a image's dependencies, simply configure any of
 these options with a relative path to the output to use in the output
-directory of the dependency.
+directory of the dependency. Or use the `%O` specifier to refer to the
+output directory.
 
-A good example on how to use presets can be found in the [systemd
-repository](https://github.com/systemd/systemd/tree/main/mkosi.presets).
+A good example on how to build multiple images can be found in the
+[systemd](https://github.com/systemd/systemd/tree/main/mkosi.presets)
+repository.
 
 # ENVIRONMENT VARIABLES
 
index 20e7a89c3d9e6dc4174632240568d394b23c6f26..dde6f99952d06f1326df76018ee0c675bb93176b 100644 (file)
@@ -115,8 +115,13 @@ def test_config() -> None:
             "FinalizeScripts": [],
             "Format": "uki",
             "Hostname": null,
+            "Image": "default",
             "ImageId": "myimage",
             "ImageVersion": "5",
+            "Images": [
+                "default",
+                "initrd"
+            ],
             "Include": [],
             "Incremental": false,
             "InitrdPackages": [
@@ -174,11 +179,6 @@ def test_config() -> None:
             "PrepareScripts": [
                 "/run/foo"
             ],
-            "Preset": "default",
-            "Presets": [
-                "default",
-                "initrd"
-            ],
             "Profile": "profile",
             "QemuArgs": [],
             "QemuCdrom": false,
@@ -279,8 +279,10 @@ def test_config() -> None:
         extra_trees = [],
         finalize_scripts = [],
         hostname = None,
+        image = "default",
         image_id = "myimage",
         image_version = "5",
+        images = ("default", "initrd"),
         include = tuple(),
         incremental = False,
         initrd_packages = ["clevis"],
@@ -310,8 +312,6 @@ def test_config() -> None:
         passphrase = None,
         postinst_scripts = [Path("/bar/qux")],
         prepare_scripts = [Path("/run/foo")],
-        preset = "default",
-        presets = ("default", "initrd"),
         profile = "profile",
         qemu_args = [],
         qemu_cdrom = False,