from .backend import (
ARG_DEBUG,
- CommandLineArguments,
Distribution,
ManifestFormat,
+ MkosiArgs,
MkosiException,
MkosiPrinter,
OutputFormat,
@complete_step("Detaching namespace")
-def init_namespace(args: CommandLineArguments) -> None:
+def init_namespace(args: MkosiArgs) -> None:
unshare(CLONE_NEWNS)
run(["mount", "--make-rslave", "/"])
-def setup_workspace(args: CommandLineArguments) -> TempDir:
+def setup_workspace(args: MkosiArgs) -> TempDir:
with complete_step("Setting up temporary workspace.", "Temporary workspace set up in {.name}") as output:
if args.workspace_dir is not None:
d = tempfile.TemporaryDirectory(dir=args.workspace_dir, prefix="")
@contextlib.contextmanager
-def btrfs_forget_stale_devices(args: CommandLineArguments) -> Iterator[None]:
+def btrfs_forget_stale_devices(args: MkosiArgs) -> Iterator[None]:
# When using cached images (-i), mounting btrfs images would sometimes fail
# with EEXIST. This is likely because a stale device is leftover somewhere
# from the previous run. To fix this, we make sure to always clean up stale
run(["btrfs", "device", "scan", "-u"])
-def is_generated_root(args: Union[argparse.Namespace, CommandLineArguments]) -> bool:
+def is_generated_root(args: Union[argparse.Namespace, MkosiArgs]) -> bool:
"""Returns whether this configuration means we need to generate a file system from a prepared tree
This is needed for anything squashfs and when root minimization is required."""
def root_partition_description(
- args: Optional[CommandLineArguments],
+ args: Optional[MkosiArgs],
suffix: Optional[str] = None,
image_id: Optional[str] = None,
image_version: Optional[str] = None,
usr_only: Optional[bool] = False,
) -> str:
- # Support invocation with "args" or with separate parameters (which is useful when invoking it before we allocated a CommandLineArguments object)
+ # Support invocation with "args" or with separate parameters (which is useful when invoking it before we allocated a MkosiArgs object)
if args is not None:
image_id = args.image_id
image_version = args.image_version
return prefix + ' ' + (suffix if suffix is not None else 'Partition')
-def initialize_partition_table(args: CommandLineArguments) -> None:
+def initialize_partition_table(args: MkosiArgs) -> None:
if args.partition_table is not None:
return
args.partition_table = table
-def create_image(args: CommandLineArguments, for_cache: bool) -> Optional[BinaryIO]:
+def create_image(args: MkosiArgs, for_cache: bool) -> Optional[BinaryIO]:
initialize_partition_table(args)
if args.partition_table is None:
return None
return f
-def refresh_partition_table(args: CommandLineArguments, f: BinaryIO) -> None:
+def refresh_partition_table(args: MkosiArgs, f: BinaryIO) -> None:
initialize_partition_table(args)
if args.partition_table is None:
return
args.partition_table.run_sfdisk(f.name, quiet=True)
-def refresh_file_system(args: CommandLineArguments, dev: Optional[Path], cached: bool) -> None:
+def refresh_file_system(args: MkosiArgs, dev: Optional[Path], cached: bool) -> None:
if dev is None:
return
def reuse_cache_image(
- args: CommandLineArguments, do_run_build_script: bool, for_cache: bool
+ args: MkosiArgs, do_run_build_script: bool, for_cache: bool
) -> Tuple[Optional[BinaryIO], bool]:
if not args.incremental:
return None, False
yield loopdev
-def prepare_swap(args: CommandLineArguments, loopdev: Optional[Path], cached: bool) -> None:
+def prepare_swap(args: MkosiArgs, loopdev: Optional[Path], cached: bool) -> None:
if loopdev is None:
return
if cached:
run(["mkswap", "-Lswap", part.blockdev(loopdev)])
-def prepare_esp(args: CommandLineArguments, loopdev: Optional[Path], cached: bool) -> None:
+def prepare_esp(args: MkosiArgs, loopdev: Optional[Path], cached: bool) -> None:
if loopdev is None:
return
if cached:
run(["mkfs.fat", "-nEFI", "-F32", part.blockdev(loopdev)])
-def prepare_xbootldr(args: CommandLineArguments, loopdev: Optional[Path], cached: bool) -> None:
+def prepare_xbootldr(args: MkosiArgs, loopdev: Optional[Path], cached: bool) -> None:
if loopdev is None:
return
if cached:
return ["mkfs.btrfs", "-L", label, "-d", "single", "-m", "single"]
-def mkfs_generic(args: CommandLineArguments, label: str, mount: PathString, dev: Path) -> None:
+def mkfs_generic(args: MkosiArgs, label: str, mount: PathString, dev: Path) -> None:
cmdline: Sequence[PathString]
if args.output_format == OutputFormat.gpt_btrfs:
def luks_format_root(
- args: CommandLineArguments,
+ args: MkosiArgs,
loopdev: Path,
do_run_build_script: bool,
cached: bool,
luks_format(part.blockdev(loopdev), args.passphrase)
-def luks_format_home(args: CommandLineArguments, loopdev: Path, do_run_build_script: bool, cached: bool) -> None:
+def luks_format_home(args: MkosiArgs, loopdev: Path, do_run_build_script: bool, cached: bool) -> None:
if args.encrypt is None:
return
part = args.get_partition(PartitionIdentifier.home)
luks_format(part.blockdev(loopdev), args.passphrase)
-def luks_format_srv(args: CommandLineArguments, loopdev: Path, do_run_build_script: bool, cached: bool) -> None:
+def luks_format_srv(args: MkosiArgs, loopdev: Path, do_run_build_script: bool, cached: bool) -> None:
if args.encrypt is None:
return
part = args.get_partition(PartitionIdentifier.srv)
luks_format(part.blockdev(loopdev), args.passphrase)
-def luks_format_var(args: CommandLineArguments, loopdev: Path, do_run_build_script: bool, cached: bool) -> None:
+def luks_format_var(args: MkosiArgs, loopdev: Path, do_run_build_script: bool, cached: bool) -> None:
if args.encrypt is None:
return
part = args.get_partition(PartitionIdentifier.var)
luks_format(part.blockdev(loopdev), args.passphrase)
-def luks_format_tmp(args: CommandLineArguments, loopdev: Path, do_run_build_script: bool, cached: bool) -> None:
+def luks_format_tmp(args: MkosiArgs, loopdev: Path, do_run_build_script: bool, cached: bool) -> None:
if args.encrypt is None:
return
part = args.get_partition(PartitionIdentifier.tmp)
def luks_setup_root(
- args: CommandLineArguments, loopdev: Path, do_run_build_script: bool, inserting_generated_root: bool = False
+ args: MkosiArgs, loopdev: Path, do_run_build_script: bool, inserting_generated_root: bool = False
) -> ContextManager[Optional[Path]]:
if args.encrypt != "all":
return contextlib.nullcontext()
def luks_setup_home(
- args: CommandLineArguments, loopdev: Path, do_run_build_script: bool
+ args: MkosiArgs, loopdev: Path, do_run_build_script: bool
) -> ContextManager[Optional[Path]]:
if args.encrypt is None:
return contextlib.nullcontext()
def luks_setup_srv(
- args: CommandLineArguments, loopdev: Path, do_run_build_script: bool
+ args: MkosiArgs, loopdev: Path, do_run_build_script: bool
) -> ContextManager[Optional[Path]]:
if args.encrypt is None:
return contextlib.nullcontext()
def luks_setup_var(
- args: CommandLineArguments, loopdev: Path, do_run_build_script: bool
+ args: MkosiArgs, loopdev: Path, do_run_build_script: bool
) -> ContextManager[Optional[Path]]:
if args.encrypt is None:
return contextlib.nullcontext()
def luks_setup_tmp(
- args: CommandLineArguments, loopdev: Path, do_run_build_script: bool
+ args: MkosiArgs, loopdev: Path, do_run_build_script: bool
) -> ContextManager[Optional[Path]]:
if args.encrypt is None:
return contextlib.nullcontext()
def empty(cls) -> LuksSetupOutput:
return cls(None, None, None, None, None)
- def without_generated_root(self, args: CommandLineArguments) -> LuksSetupOutput:
+ def without_generated_root(self, args: MkosiArgs) -> LuksSetupOutput:
"A copy of self with .root optionally supressed"
return LuksSetupOutput(
None if is_generated_root(args) else self.root,
@contextlib.contextmanager
def luks_setup_all(
- args: CommandLineArguments, loopdev: Optional[Path], do_run_build_script: bool
+ args: MkosiArgs, loopdev: Optional[Path], do_run_build_script: bool
) -> Iterator[LuksSetupOutput]:
if not args.output_format.is_disk():
yield LuksSetupOutput.empty()
tmp or args.partition_table.partition_path(PartitionIdentifier.tmp, loopdev))
-def prepare_root(args: CommandLineArguments, dev: Optional[Path], cached: bool) -> None:
+def prepare_root(args: MkosiArgs, dev: Optional[Path], cached: bool) -> None:
if dev is None:
return
if is_generated_root(args):
mkfs_generic(args, label, path, dev)
-def prepare_home(args: CommandLineArguments, dev: Optional[Path], cached: bool) -> None:
+def prepare_home(args: MkosiArgs, dev: Optional[Path], cached: bool) -> None:
if dev is None:
return
if cached:
mkfs_generic(args, "home", "/home", dev)
-def prepare_srv(args: CommandLineArguments, dev: Optional[Path], cached: bool) -> None:
+def prepare_srv(args: MkosiArgs, dev: Optional[Path], cached: bool) -> None:
if dev is None:
return
if cached:
mkfs_generic(args, "srv", "/srv", dev)
-def prepare_var(args: CommandLineArguments, dev: Optional[Path], cached: bool) -> None:
+def prepare_var(args: MkosiArgs, dev: Optional[Path], cached: bool) -> None:
if dev is None:
return
if cached:
mkfs_generic(args, "var", "/var", dev)
-def prepare_tmp(args: CommandLineArguments, dev: Optional[Path], cached: bool) -> None:
+def prepare_tmp(args: MkosiArgs, dev: Optional[Path], cached: bool) -> None:
if dev is None:
return
if cached:
run(cmd)
-def mount_loop(args: CommandLineArguments, dev: Path, where: Path, read_only: bool = False) -> None:
+def mount_loop(args: MkosiArgs, dev: Path, where: Path, read_only: bool = False) -> None:
options = []
if not args.output_format.is_squashfs():
options += ["discard"]
def mount_overlay(
- args: CommandLineArguments,
+ args: MkosiArgs,
base_image: Path, # the path to the mounted base image root
root: Path, # the path to the destination image root
read_only: bool = False,
@contextlib.contextmanager
def mount_image(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
base_image: Optional[Path], # the path to the mounted base image root
loopdev: Optional[Path],
umount(root)
-def install_etc_hostname(args: CommandLineArguments, root: Path, cached: bool) -> None:
+def install_etc_hostname(args: MkosiArgs, root: Path, cached: bool) -> None:
if cached:
return
@contextlib.contextmanager
-def mount_api_vfs(args: CommandLineArguments, root: Path) -> Iterator[None]:
+def mount_api_vfs(args: MkosiArgs, root: Path) -> Iterator[None]:
subdirs = ("proc", "dev", "sys")
with complete_step("Mounting API VFS"):
@contextlib.contextmanager
-def mount_cache(args: CommandLineArguments, root: Path) -> Iterator[None]:
+def mount_cache(args: MkosiArgs, root: Path) -> Iterator[None]:
if args.cache_path is None:
yield
return
run(["umount", "--recursive", "-n", where])
-def configure_dracut(args: CommandLineArguments, packages: Set[str], root: Path) -> None:
+def configure_dracut(args: MkosiArgs, packages: Set[str], root: Path) -> None:
if "dracut" not in packages:
return
)
-def prepare_tree_root(args: CommandLineArguments, root: Path) -> None:
+def prepare_tree_root(args: MkosiArgs, root: Path) -> None:
if args.output_format == OutputFormat.subvolume and not is_generated_root(args):
with complete_step("Setting up OS tree root…"):
btrfs_subvol_create(root)
-def root_home(args: CommandLineArguments, root: Path) -> Path:
+def root_home(args: MkosiArgs, root: Path) -> Path:
# If UsrOnly= is turned on the /root/ directory (i.e. the root
# user's home directory) is not persistent (after all everything
return root / "root"
-def prepare_tree(args: CommandLineArguments, root: Path, do_run_build_script: bool, cached: bool) -> None:
+def prepare_tree(args: MkosiArgs, root: Path, do_run_build_script: bool, cached: bool) -> None:
if cached:
return
os.chmod(path, st.st_mode | stat.S_IEXEC)
-def disable_kernel_install(args: CommandLineArguments, root: Path) -> None:
+def disable_kernel_install(args: MkosiArgs, root: Path) -> None:
# Let's disable the automatic kernel installation done by the kernel RPMs. After all, we want to built
# our own unified kernels that include the root hash in the kernel command line and can be signed as a
# single EFI executable. Since the root hash is only known when the root file system is finalized we turn
root.joinpath("etc/kernel/install.d", f).symlink_to("/dev/null")
-def reenable_kernel_install(args: CommandLineArguments, root: Path) -> None:
+def reenable_kernel_install(args: MkosiArgs, root: Path) -> None:
if not args.bootable or args.get_partition(PartitionIdentifier.bios) or not args.with_unified_kernel_images:
return
def add_packages(
- args: CommandLineArguments, packages: Set[str], *names: str, conditional: Optional[str] = None
+ args: MkosiArgs, packages: Set[str], *names: str, conditional: Optional[str] = None
) -> None:
"""Add packages in @names to @packages, if enabled by --base-packages.
return sorted(packages, key=sort)
-def make_rpm_list(args: CommandLineArguments, packages: Set[str], do_run_build_script: bool) -> Set[str]:
+def make_rpm_list(args: MkosiArgs, packages: Set[str], do_run_build_script: bool) -> Set[str]:
packages = packages.copy()
if args.bootable:
unlink_try_hard(path)
-def clean_package_manager_metadata(args: CommandLineArguments, root: Path) -> None:
+def clean_package_manager_metadata(args: MkosiArgs, root: Path) -> None:
"""Remove package manager metadata
Try them all regardless of the distro: metadata is only removed if the
# FIXME: implement cleanup for other package managers: swupd, pacman
-def remove_files(args: CommandLineArguments, root: Path) -> None:
+def remove_files(args: MkosiArgs, root: Path) -> None:
"""Remove files based on user-specified patterns"""
if not args.remove_files:
def invoke_dnf(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
command: str,
packages: Iterable[str],
def install_packages_dnf(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
packages: Set[str],
do_run_build_script: bool,
def invoke_tdnf(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
command: str,
packages: Set[str],
def install_packages_tdnf(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
packages: Set[str],
gpgcheck: bool,
gpgurl: Optional[str] = None
-def setup_dnf(args: CommandLineArguments, root: Path, repos: Sequence[Repo] = ()) -> None:
+def setup_dnf(args: MkosiArgs, root: Path, repos: Sequence[Repo] = ()) -> None:
gpgcheck = True
repo_file = workspace(root) / "mkosi.repo"
@complete_step("Installing Photon…")
-def install_photon(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_photon(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
release_url = "baseurl=https://packages.vmware.com/photon/$releasever/photon_release_$releasever_$basearch"
updates_url = "baseurl=https://packages.vmware.com/photon/$releasever/photon_updates_$releasever_$basearch"
gpgpath = Path("/etc/pki/rpm-gpg/VMWARE-RPM-GPG-KEY")
@complete_step("Installing Clear Linux…")
-def install_clear(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_clear(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
if args.release == "latest":
release = "clear"
else:
@complete_step("Installing Fedora Linux…")
-def install_fedora(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_fedora(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
if args.release == "rawhide":
last = list(FEDORA_KEYS_MAP)[-1]
warn(f"Assuming rawhide is version {last} — " + "You may specify otherwise with --release=rawhide-<version>")
@complete_step("Installing Mageia…")
-def install_mageia(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_mageia(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
if args.mirror:
baseurl = f"{args.mirror}/distrib/{args.release}/x86_64/media/core/"
release_url = f"baseurl={baseurl}/release/"
@complete_step("Installing OpenMandriva…")
-def install_openmandriva(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_openmandriva(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
release = args.release.strip("'")
arch = args.architecture or platform.machine()
disable_pam_securetty(root)
-def install_centos_repos_old(args: CommandLineArguments, root: Path, epel_release: int) -> None:
+def install_centos_repos_old(args: MkosiArgs, root: Path, epel_release: int) -> None:
# Repos for CentOS 7 and earlier
gpgpath = Path(f"/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-{args.release}")
setup_dnf(args, root, repos)
-def install_centos_repos_new(args: CommandLineArguments, root: Path, epel_release: int) -> None:
+def install_centos_repos_new(args: MkosiArgs, root: Path, epel_release: int) -> None:
# Repos for CentOS 8 and later
gpgpath = Path("/etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial")
setup_dnf(args, root, repos)
-def install_rocky_repos(args: CommandLineArguments, root: Path, epel_release: int) -> None:
+def install_rocky_repos(args: MkosiArgs, root: Path, epel_release: int) -> None:
# Repos for Rocky Linux 8 and later
gpgpath = Path("/etc/pki/rpm-gpg/RPM-GPG-KEY-rockyofficial")
gpgurl = "https://download.rockylinux.org/pub/rocky/RPM-GPG-KEY-rockyofficial"
setup_dnf(args, root, repos)
-def install_alma_repos(args: CommandLineArguments, root: Path, epel_release: int) -> None:
+def install_alma_repos(args: MkosiArgs, root: Path, epel_release: int) -> None:
# Repos for Alma Linux 8 and later
gpgpath = Path("/etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux")
gpgurl = "https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux"
@complete_step("Installing CentOS…")
-def install_centos(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_centos(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
old = is_older_than_centos8(args.release)
epel_release = int(args.release.split(".")[0])
@complete_step("Installing Rocky Linux…")
-def install_rocky(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_rocky(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
epel_release = int(args.release.split(".")[0])
install_rocky_repos(args, root, epel_release)
@complete_step("Installing Alma Linux…")
-def install_alma(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_alma(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
epel_release = int(args.release.split(".")[0])
install_alma_repos(args, root, epel_release)
def invoke_apt(
- args: CommandLineArguments,
+ args: MkosiArgs,
do_run_build_script: bool,
root: Path,
command: str,
run_workspace_command(args, root, cmdline, network=True, env=env)
-def install_debian_or_ubuntu(args: CommandLineArguments, root: Path, *, do_run_build_script: bool) -> None:
+def install_debian_or_ubuntu(args: MkosiArgs, root: Path, *, do_run_build_script: bool) -> None:
# Either the image builds or it fails and we restart, we don't need safety fsyncs when bootstrapping
# Add it before debootstrap, as the second stage already uses dpkg from the chroot
dpkg_io_conf = root / "etc/dpkg/dpkg.cfg.d/unsafe_io"
@complete_step("Installing Debian…")
-def install_debian(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_debian(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
install_debian_or_ubuntu(args, root, do_run_build_script=do_run_build_script)
@complete_step("Installing Ubuntu…")
-def install_ubuntu(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_ubuntu(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
install_debian_or_ubuntu(args, root, do_run_build_script=do_run_build_script)
run(["gpgconf", "--homedir", root / "etc/pacman.d/gnupg", "--kill", "all"])
-def patch_locale_gen(args: CommandLineArguments, root: Path) -> None:
+def patch_locale_gen(args: MkosiArgs, root: Path) -> None:
# If /etc/locale.gen exists, uncomment the desired locale and leave the rest of the file untouched.
# If it doesn’t exist, just write the desired locale in it.
try:
@complete_step("Installing Arch Linux…")
-def install_arch(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_arch(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
if args.release is not None:
MkosiPrinter.info("Distribution release specification is not supported for Arch Linux, ignoring.")
@complete_step("Installing openSUSE…")
-def install_opensuse(args: CommandLineArguments, root: Path, do_run_build_script: bool) -> None:
+def install_opensuse(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
release = args.release.strip('"')
# If the release looks like a timestamp, it's Tumbleweed. 13.x is legacy (14.x won't ever appear). For
@complete_step("Installing Gentoo…")
def install_gentoo(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
do_run_build_script: bool
) -> None:
gentoo.invoke_emerge(args, root, pkgs=args.build_packages)
-def install_distribution(args: CommandLineArguments, root: Path, do_run_build_script: bool, cached: bool) -> None:
+def install_distribution(args: MkosiArgs, root: Path, do_run_build_script: bool, cached: bool) -> None:
if cached:
return
- install: Dict[Distribution, Callable[[CommandLineArguments, Path, bool], None]] = {
+ install: Dict[Distribution, Callable[[MkosiArgs, Path, bool], None]] = {
Distribution.fedora: install_fedora,
Distribution.centos: install_centos,
Distribution.centos_epel: install_centos,
reenable_kernel_install(args, root)
-def remove_packages(args: CommandLineArguments, root: Path) -> None:
+def remove_packages(args: MkosiArgs, root: Path) -> None:
"""Remove packages listed in args.remove_packages"""
remove: Callable[[List[str]], None]
remove(args.remove_packages)
-def reset_machine_id(args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
+def reset_machine_id(args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
"""Make /etc/machine-id an empty file.
This way, on the next boot is either initialized and committed (if /etc is
dbus_machine_id.symlink_to("../../../etc/machine-id")
-def reset_random_seed(args: CommandLineArguments, root: Path) -> None:
+def reset_random_seed(args: MkosiArgs, root: Path) -> None:
"""Remove random seed file, so that it is initialized on first boot"""
random_seed = root / "var/lib/systemd/random-seed"
if not random_seed.exists():
random_seed.unlink()
-def set_root_password(args: CommandLineArguments, root: Path, do_run_build_script: bool, cached: bool) -> None:
+def set_root_password(args: MkosiArgs, root: Path, do_run_build_script: bool, cached: bool) -> None:
"Set the root account password, or just delete it so it's easy to log in"
if do_run_build_script:
patch_file(root / "etc/shadow", set_root_pw)
-def invoke_fstrim(args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
+def invoke_fstrim(args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
if do_run_build_script:
return
f.write(original)
-def set_autologin(args: CommandLineArguments, root: Path, do_run_build_script: bool, cached: bool) -> None:
+def set_autologin(args: MkosiArgs, root: Path, do_run_build_script: bool, cached: bool) -> None:
if do_run_build_script or cached or not args.autologin:
return
pam_add_autologin(root, ttys)
-def set_serial_terminal(args: CommandLineArguments, root: Path, do_run_build_script: bool, cached: bool) -> None:
+def set_serial_terminal(args: MkosiArgs, root: Path, do_run_build_script: bool, cached: bool) -> None:
"""Override TERM for the serial console with the terminal type from the host."""
if do_run_build_script or cached or not args.qemu_headless:
""")
-def nspawn_params_for_build_sources(args: CommandLineArguments, sft: SourceFileTransfer) -> List[str]:
+def nspawn_params_for_build_sources(args: MkosiArgs, sft: SourceFileTransfer) -> List[str]:
params = []
if args.build_sources is not None:
return params
-def run_prepare_script(args: CommandLineArguments, root: Path, do_run_build_script: bool, cached: bool) -> None:
+def run_prepare_script(args: MkosiArgs, root: Path, do_run_build_script: bool, cached: bool) -> None:
if args.prepare_script is None:
return
if cached:
def run_postinst_script(
- args: CommandLineArguments, root: Path, loopdev: Optional[Path], do_run_build_script: bool, for_cache: bool
+ args: MkosiArgs, root: Path, loopdev: Optional[Path], do_run_build_script: bool, for_cache: bool
) -> None:
if args.postinst_script is None:
return
root_home(args, root).joinpath("postinst").unlink()
-def output_dir(args: CommandLineArguments) -> Path:
+def output_dir(args: MkosiArgs) -> Path:
return args.output_dir or Path(os.getcwd())
-def run_finalize_script(args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
+def run_finalize_script(args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
if args.finalize_script is None:
return
if for_cache:
run([args.finalize_script, verb], env=env)
-def install_boot_loader_clear(args: CommandLineArguments, root: Path, loopdev: Path) -> None:
+def install_boot_loader_clear(args: MkosiArgs, root: Path, loopdev: Path) -> None:
# clr-boot-manager uses blkid in the device backing "/" to
# figure out uuid and related parameters.
nspawn_params = nspawn_params_for_blockdev_access(args, loopdev)
run_workspace_command(args, root, cmdline, nspawn_params=nspawn_params)
-def install_boot_loader_centos_old_efi(args: CommandLineArguments, root: Path, loopdev: Path) -> None:
+def install_boot_loader_centos_old_efi(args: MkosiArgs, root: Path, loopdev: Path) -> None:
nspawn_params = nspawn_params_for_blockdev_access(args, loopdev)
# prepare EFI directory on ESP
def install_boot_loader(
- args: CommandLineArguments, root: Path, loopdev: Optional[Path], do_run_build_script: bool, cached: bool
+ args: MkosiArgs, root: Path, loopdev: Optional[Path], do_run_build_script: bool, cached: bool
) -> None:
if not args.bootable or do_run_build_script:
return
install_boot_loader_clear(args, root, loopdev)
-def install_extra_trees(args: CommandLineArguments, root: Path, for_cache: bool) -> None:
+def install_extra_trees(args: MkosiArgs, root: Path, for_cache: bool) -> None:
if not args.extra_trees:
return
shutil.unpack_archive(cast(str, tree), root)
-def install_skeleton_trees(args: CommandLineArguments, root: Path, cached: bool) -> None:
+def install_skeleton_trees(args: MkosiArgs, root: Path, cached: bool) -> None:
if not args.skeleton_trees:
return
copy_file(src_path, dest_path)
-def install_build_src(args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
+def install_build_src(args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
if for_cache:
return
shutil.copytree(args.build_sources, target, symlinks=not resolve_symlinks, ignore=ignore)
-def install_build_dest(args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
+def install_build_dest(args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool) -> None:
if do_run_build_script:
return
if for_cache:
copy_path(install_dir(args, root), root)
-def make_read_only(args: CommandLineArguments, root: Path, for_cache: bool, b: bool = True) -> None:
+def make_read_only(args: MkosiArgs, root: Path, for_cache: bool, b: bool = True) -> None:
if not args.read_only:
return
if for_cache:
return "gtar" if shutil.which("gtar") else "tar"
-def make_tar(args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool) -> Optional[BinaryIO]:
+def make_tar(args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool) -> Optional[BinaryIO]:
if do_run_build_script:
return None
if args.output_format != OutputFormat.tar:
def make_cpio(
- args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool
+ args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool
) -> Optional[BinaryIO]:
if do_run_build_script:
return None
return f
-def generate_squashfs(args: CommandLineArguments, root: Path, for_cache: bool) -> Optional[BinaryIO]:
+def generate_squashfs(args: MkosiArgs, root: Path, for_cache: bool) -> Optional[BinaryIO]:
if not args.output_format.is_squashfs():
return None
if for_cache:
return f
-def generate_ext4(args: CommandLineArguments, root: Path, label: str, for_cache: bool) -> Optional[BinaryIO]:
+def generate_ext4(args: MkosiArgs, root: Path, label: str, for_cache: bool) -> Optional[BinaryIO]:
if args.output_format != OutputFormat.gpt_ext4:
return None
if for_cache:
return f
-def generate_btrfs(args: CommandLineArguments, root: Path, label: str, for_cache: bool) -> Optional[BinaryIO]:
+def generate_btrfs(args: MkosiArgs, root: Path, label: str, for_cache: bool) -> Optional[BinaryIO]:
if args.output_format != OutputFormat.gpt_btrfs:
return None
if for_cache:
return f
-def make_generated_root(args: CommandLineArguments, root: Path, for_cache: bool) -> Optional[BinaryIO]:
+def make_generated_root(args: MkosiArgs, root: Path, for_cache: bool) -> Optional[BinaryIO]:
if not is_generated_root(args):
return None
def insert_partition(
- args: CommandLineArguments,
+ args: MkosiArgs,
raw: BinaryIO,
loopdev: Path,
blob: BinaryIO,
def insert_generated_root(
- args: CommandLineArguments,
+ args: MkosiArgs,
raw: Optional[BinaryIO],
loopdev: Optional[Path],
image: Optional[BinaryIO],
def make_verity(
- args: CommandLineArguments, dev: Optional[Path], do_run_build_script: bool, for_cache: bool
+ args: MkosiArgs, dev: Optional[Path], do_run_build_script: bool, for_cache: bool
) -> Tuple[Optional[BinaryIO], Optional[str]]:
if do_run_build_script or args.verity is False:
return None, None
def insert_verity(
- args: CommandLineArguments,
+ args: MkosiArgs,
raw: Optional[BinaryIO],
loopdev: Optional[Path],
verity: Optional[BinaryIO],
def make_verity_sig(
- args: CommandLineArguments, root_hash: Optional[str], do_run_build_script: bool, for_cache: bool
+ args: MkosiArgs, root_hash: Optional[str], do_run_build_script: bool, for_cache: bool
) -> Tuple[Optional[BinaryIO], Optional[bytes], Optional[str]]:
if do_run_build_script or args.verity != "signed":
def insert_verity_sig(
- args: CommandLineArguments,
+ args: MkosiArgs,
raw: Optional[BinaryIO],
loopdev: Optional[Path],
verity_sig: Optional[BinaryIO],
def patch_root_uuid(
- args: CommandLineArguments, loopdev: Optional[Path], root_hash: Optional[str], for_cache: bool
+ args: MkosiArgs, loopdev: Optional[Path], root_hash: Optional[str], for_cache: bool
) -> None:
if root_hash is None:
return
def extract_partition(
- args: CommandLineArguments, dev: Optional[Path], do_run_build_script: bool, for_cache: bool
+ args: MkosiArgs, dev: Optional[Path], do_run_build_script: bool, for_cache: bool
) -> Optional[BinaryIO]:
if do_run_build_script or for_cache or not args.split_artifacts:
def install_unified_kernel(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
root_hash: Optional[str],
do_run_build_script: bool,
def secure_boot_sign(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
do_run_build_script: bool,
for_cache: bool,
def extract_unified_kernel(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
do_run_build_script: bool,
for_cache: bool,
def compress_output(
- args: CommandLineArguments, data: Optional[BinaryIO], suffix: Optional[str] = None
+ args: MkosiArgs, data: Optional[BinaryIO], suffix: Optional[str] = None
) -> Optional[BinaryIO]:
if data is None:
return f
-def qcow2_output(args: CommandLineArguments, raw: Optional[BinaryIO]) -> Optional[BinaryIO]:
+def qcow2_output(args: MkosiArgs, raw: Optional[BinaryIO]) -> Optional[BinaryIO]:
if not args.output_format.is_disk():
return raw
assert raw is not None
return f
-def write_root_hash_file(args: CommandLineArguments, root_hash: Optional[str]) -> Optional[BinaryIO]:
+def write_root_hash_file(args: MkosiArgs, root_hash: Optional[str]) -> Optional[BinaryIO]:
if root_hash is None:
return None
return f
-def write_root_hash_p7s_file(args: CommandLineArguments, root_hash_p7s: Optional[bytes]) -> Optional[BinaryIO]:
+def write_root_hash_p7s_file(args: MkosiArgs, root_hash_p7s: Optional[bytes]) -> Optional[BinaryIO]:
if root_hash_p7s is None:
return None
return f
-def copy_nspawn_settings(args: CommandLineArguments) -> Optional[BinaryIO]:
+def copy_nspawn_settings(args: MkosiArgs) -> Optional[BinaryIO]:
if args.nspawn_settings is None:
return None
def calculate_sha256sum(
- args: CommandLineArguments,
+ args: MkosiArgs,
raw: Optional[BinaryIO],
archive: Optional[BinaryIO],
root_hash_file: Optional[BinaryIO],
return f
-def calculate_signature(args: CommandLineArguments, checksum: Optional[IO[Any]]) -> Optional[BinaryIO]:
+def calculate_signature(args: MkosiArgs, checksum: Optional[IO[Any]]) -> Optional[BinaryIO]:
if not args.sign:
return None
return f
-def calculate_bmap(args: CommandLineArguments, raw: Optional[BinaryIO]) -> Optional[TextIO]:
+def calculate_bmap(args: MkosiArgs, raw: Optional[BinaryIO]) -> Optional[TextIO]:
if not args.bmap:
return None
return f
-def save_cache(args: CommandLineArguments, root: Path, raw: Optional[str], cache_path: Optional[Path]) -> None:
+def save_cache(args: MkosiArgs, root: Path, raw: Optional[str], cache_path: Optional[Path]) -> None:
disk_rw = args.output_format.is_disk_rw()
if disk_rw:
if raw is None or cache_path is None:
def _link_output(
- args: CommandLineArguments,
+ args: MkosiArgs,
oldpath: PathString,
newpath: PathString,
mode: int = 0o666,
os.chown(newpath, int(sudo_uid), int(sudo_gid))
-def link_output(args: CommandLineArguments, root: Path, artifact: Optional[BinaryIO]) -> None:
+def link_output(args: MkosiArgs, root: Path, artifact: Optional[BinaryIO]) -> None:
with complete_step("Linking image file…", f"Linked {path_relative_to_cwd(args.output)}"):
if args.output_format in (OutputFormat.directory, OutputFormat.subvolume):
assert artifact is None
_link_output(args, artifact.name, args.output)
-def link_output_nspawn_settings(args: CommandLineArguments, path: Optional[SomeIO]) -> None:
+def link_output_nspawn_settings(args: MkosiArgs, path: Optional[SomeIO]) -> None:
if path:
assert args.output_nspawn_settings
with complete_step(
_link_output(args, path.name, args.output_nspawn_settings)
-def link_output_checksum(args: CommandLineArguments, checksum: Optional[SomeIO]) -> None:
+def link_output_checksum(args: MkosiArgs, checksum: Optional[SomeIO]) -> None:
if checksum:
assert args.output_checksum
with complete_step("Linking SHA256SUMS file…", f"Linked {path_relative_to_cwd(args.output_checksum)}"):
_link_output(args, checksum.name, args.output_checksum)
-def link_output_root_hash_file(args: CommandLineArguments, root_hash_file: Optional[SomeIO]) -> None:
+def link_output_root_hash_file(args: MkosiArgs, root_hash_file: Optional[SomeIO]) -> None:
if root_hash_file:
assert args.output_root_hash_file
suffix = roothash_suffix(args.usr_only)
_link_output(args, root_hash_file.name, args.output_root_hash_file)
-def link_output_root_hash_p7s_file(args: CommandLineArguments, root_hash_p7s_file: Optional[SomeIO]) -> None:
+def link_output_root_hash_p7s_file(args: MkosiArgs, root_hash_p7s_file: Optional[SomeIO]) -> None:
if root_hash_p7s_file:
assert args.output_root_hash_p7s_file
suffix = roothash_p7s_suffix(args.usr_only)
_link_output(args, root_hash_p7s_file.name, args.output_root_hash_p7s_file)
-def link_output_signature(args: CommandLineArguments, signature: Optional[SomeIO]) -> None:
+def link_output_signature(args: MkosiArgs, signature: Optional[SomeIO]) -> None:
if signature:
assert args.output_signature is not None
with complete_step("Linking SHA256SUMS.gpg file…", f"Linked {path_relative_to_cwd(args.output_signature)}"):
_link_output(args, signature.name, args.output_signature)
-def link_output_bmap(args: CommandLineArguments, bmap: Optional[SomeIO]) -> None:
+def link_output_bmap(args: MkosiArgs, bmap: Optional[SomeIO]) -> None:
if bmap:
assert args.output_bmap
with complete_step("Linking .bmap file…", f"Linked {path_relative_to_cwd(args.output_bmap)}"):
_link_output(args, bmap.name, args.output_bmap)
-def link_output_sshkey(args: CommandLineArguments, sshkey: Optional[SomeIO]) -> None:
+def link_output_sshkey(args: MkosiArgs, sshkey: Optional[SomeIO]) -> None:
if sshkey:
assert args.output_sshkey
with complete_step("Linking private ssh key file…", f"Linked {path_relative_to_cwd(args.output_sshkey)}"):
_link_output(args, sshkey.name, args.output_sshkey, mode=0o600)
-def link_output_split_root(args: CommandLineArguments, split_root: Optional[SomeIO]) -> None:
+def link_output_split_root(args: MkosiArgs, split_root: Optional[SomeIO]) -> None:
if split_root:
assert args.output_split_root
with complete_step(
_link_output(args, split_root.name, args.output_split_root)
-def link_output_split_verity(args: CommandLineArguments, split_verity: Optional[SomeIO]) -> None:
+def link_output_split_verity(args: MkosiArgs, split_verity: Optional[SomeIO]) -> None:
if split_verity:
assert args.output_split_verity
with complete_step("Linking split Verity data…", f"Linked {path_relative_to_cwd(args.output_split_verity)}"):
_link_output(args, split_verity.name, args.output_split_verity)
-def link_output_split_verity_sig(args: CommandLineArguments, split_verity_sig: Optional[SomeIO]) -> None:
+def link_output_split_verity_sig(args: MkosiArgs, split_verity_sig: Optional[SomeIO]) -> None:
if split_verity_sig:
assert args.output_split_verity_sig
with complete_step(
_link_output(args, split_verity_sig.name, args.output_split_verity_sig)
-def link_output_split_kernel(args: CommandLineArguments, split_kernel: Optional[SomeIO]) -> None:
+def link_output_split_kernel(args: MkosiArgs, split_kernel: Optional[SomeIO]) -> None:
if split_kernel:
assert args.output_split_kernel
with complete_step("Linking split kernel image…", f"Linked {path_relative_to_cwd(args.output_split_kernel)}"):
return dir_sum
-def save_manifest(args: CommandLineArguments, manifest: Manifest) -> None:
+def save_manifest(args: MkosiArgs, manifest: Manifest) -> None:
if manifest.has_data():
relpath = path_relative_to_cwd(args.output)
_link_output(args, g.name, f"{relpath}.changelog")
-def print_output_size(args: CommandLineArguments) -> None:
+def print_output_size(args: MkosiArgs) -> None:
if args.output_format in (OutputFormat.directory, OutputFormat.subvolume):
MkosiPrinter.print_step("Resulting image size is " + format_bytes(dir_size(args.output)) + ".")
else:
MkosiPrinter.print_step(f"Resulting image size is {size}, consumes {space}.")
-def setup_package_cache(args: CommandLineArguments) -> Optional[TempDir]:
+def setup_package_cache(args: MkosiArgs) -> Optional[TempDir]:
if args.cache_path and args.cache_path.exists():
return None
"""Load default values from files and parse command line arguments
Do all about default files and command line arguments parsing. If --all argument is passed
- more than one job needs to be processed. The returned tuple contains CommandLineArguments
+ more than one job needs to be processed. The returned tuple contains MkosiArgs
valid for all jobs as well as a dict containing the arguments per job.
"""
parser = create_parser()
pass
-def unlink_output(args: CommandLineArguments) -> None:
+def unlink_output(args: MkosiArgs) -> None:
if not args.force and args.verb != "clean":
return
return path
-def load_args(args: argparse.Namespace) -> CommandLineArguments:
+def load_args(args: argparse.Namespace) -> MkosiArgs:
global ARG_DEBUG
ARG_DEBUG.update(args.debug)
if args.base_image is not None:
args.base_packages = False
- return CommandLineArguments(**vars(args))
+ return MkosiArgs(**vars(args))
-def check_output(args: CommandLineArguments) -> None:
+def check_output(args: MkosiArgs) -> None:
if args.skip_final_phase:
return
return "\n ".join(str(item) for item in array)
-def print_summary(args: CommandLineArguments) -> None:
+def print_summary(args: MkosiArgs) -> None:
# FIXME: normal print
MkosiPrinter.info("COMMANDS:")
MkosiPrinter.info(" verb: " + args.verb)
def reuse_cache_tree(
- args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool, cached: bool
+ args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool, cached: bool
) -> bool:
"""If there's a cached version of this tree around, use it and
initialize our new root directly from it. Returns a boolean indicating
return True
-def make_output_dir(args: CommandLineArguments) -> None:
+def make_output_dir(args: MkosiArgs) -> None:
"""Create the output directory if set and not existing yet"""
if args.output_dir is None:
return
args.output_dir.mkdir(mode=0o755, exist_ok=True)
-def make_build_dir(args: CommandLineArguments) -> None:
+def make_build_dir(args: MkosiArgs) -> None:
"""Create the build directory if set and not existing yet"""
if args.build_dir is None:
return
def setup_ssh(
- args: CommandLineArguments, root: Path, do_run_build_script: bool, for_cache: bool, cached: bool
+ args: MkosiArgs, root: Path, do_run_build_script: bool, for_cache: bool, cached: bool
) -> Optional[TextIO]:
if do_run_build_script or not args.ssh:
return None
return f
-def setup_network_veth(args: CommandLineArguments, root: Path, do_run_build_script: bool, cached: bool) -> None:
+def setup_network_veth(args: MkosiArgs, root: Path, do_run_build_script: bool, cached: bool) -> None:
if do_run_build_script or cached or not args.network_veth:
return
def build_image(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
*,
manifest: Optional[Manifest] = None,
return "1" if b else "0"
-def install_dir(args: CommandLineArguments, root: Path) -> Path:
+def install_dir(args: MkosiArgs, root: Path) -> Path:
return args.install_dir or workspace(root).joinpath("dest")
return bytes("unrecognized option", "UTF-8") not in run(["systemd-nspawn", arg], stderr=PIPE, check=False).stderr
-def run_build_script(args: CommandLineArguments, root: Path, raw: Optional[BinaryIO]) -> None:
+def run_build_script(args: MkosiArgs, root: Path, raw: Optional[BinaryIO]) -> None:
if args.build_script is None:
return
die(f"Build script returned non-zero exit code {result.returncode}.")
-def need_cache_images(args: CommandLineArguments) -> bool:
+def need_cache_images(args: MkosiArgs) -> bool:
if not args.incremental:
return False
def remove_artifacts(
- args: CommandLineArguments,
+ args: MkosiArgs,
root: Path,
raw: Optional[BinaryIO],
archive: Optional[BinaryIO],
unlink_try_hard(root_home(args, root))
-def build_stuff(args: CommandLineArguments) -> Manifest:
+def build_stuff(args: MkosiArgs) -> Manifest:
make_output_dir(args)
setup_package_cache(args)
workspace = setup_workspace(args)
die("Must be invoked as root.")
-def check_native(args: CommandLineArguments) -> None:
+def check_native(args: MkosiArgs) -> None:
if args.architecture is not None and args.architecture != platform.machine() and args.build_script:
die("Cannot (currently) override the architecture and run build commands")
raise MkosiException(e)
-def virt_name(args: CommandLineArguments) -> str:
+def virt_name(args: MkosiArgs) -> str:
name = args.hostname or args.image_id or args.output.with_suffix("").name.partition("_")[0]
# Shorten to 13 characters so we can prefix with ve- or vt- for the network veth ifname which is limited
)
-def ensure_networkd(args: CommandLineArguments) -> bool:
+def ensure_networkd(args: MkosiArgs) -> bool:
networkd_is_running = run(["systemctl", "is-active", "--quiet", "systemd-networkd"], check=False).returncode == 0
if not networkd_is_running:
if args.verb != "ssh":
return True
-def run_shell(args: CommandLineArguments) -> None:
+def run_shell(args: MkosiArgs) -> None:
if args.output_format in (OutputFormat.directory, OutputFormat.subvolume):
target = f"--directory={args.output}"
else:
die("Couldn't find OVMF UEFI variables file.")
-def run_qemu(args: CommandLineArguments) -> None:
+def run_qemu(args: MkosiArgs) -> None:
has_kvm = os.path.exists("/dev/kvm")
accel = "kvm" if has_kvm else "tcg"
return run(["ip", "link", "show", dev], stdout=DEVNULL, stderr=DEVNULL, check=False).returncode == 0
-def find_address(args: CommandLineArguments) -> Tuple[str, str]:
+def find_address(args: MkosiArgs) -> Tuple[str, str]:
if not ensure_networkd(args) and args.ssh_port != 22:
return "", "127.0.0.1"
die("Container/VM address not found")
-def run_ssh(args: CommandLineArguments) -> None:
+def run_ssh(args: MkosiArgs) -> None:
cmd = [
"ssh",
# Silence known hosts file errors/warnings.
run(cmd, stdout=sys.stdout, stderr=sys.stderr)
-def run_serve(args: CommandLineArguments) -> None:
+def run_serve(args: MkosiArgs) -> None:
"""Serve the output directory via a tiny embedded HTTP server"""
port = 8081
httpd.serve_forever()
-def generate_secure_boot_key(args: CommandLineArguments) -> NoReturn:
+def generate_secure_boot_key(args: MkosiArgs) -> NoReturn:
"""Generate secure boot keys using openssl"""
args.secure_boot_key = args.secure_boot_key or Path("./mkosi.secure-boot.key")
args.secure_boot_certificate = args.secure_boot_certificate or Path("./mkosi.secure-boot.crt")
os.execvp(cmd[0], cmd)
-def bump_image_version(args: CommandLineArguments) -> None:
+def bump_image_version(args: MkosiArgs) -> None:
"""Write current image version plus one to mkosi.version"""
if args.image_version is None or args.image_version == "":
return s.replace("%u", user)
-def needs_build(args: Union[argparse.Namespace, CommandLineArguments]) -> bool:
+def needs_build(args: Union[argparse.Namespace, MkosiArgs]) -> bool:
return args.verb == "build" or (not args.output.exists() and args.verb in MKOSI_COMMANDS_NEED_BUILD)