]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Ensure output is compatible with systemd-sysupdate 1386/head
authorMichael A Cassaniti <michael@cassaniti.id.au>
Mon, 1 May 2023 04:36:16 +0000 (14:36 +1000)
committerZbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>
Thu, 4 May 2023 10:18:45 +0000 (12:18 +0200)
When using `systemd-sysupdate` it is wise to use split artifacts and to
compress artifacts. These changes ensure that split artifacts are compressed
and the file paths are stored in the checksum.

Please note that `systemd-sysupdate` expects a checksum name of `SHA256SUMS`
and uses the contained file names to determine which files to download. The
compression suffix is also used to determine how to decompress files.

Additional CI checks have been added to make sure no regressions in output
format occur.

.github/workflows/ci.yml
man/mkosi.1
mkosi.md
mkosi/__init__.py
mkosi/config.py

index 6be8bf09c9587a3a28dede0a84c70a6cf4a5466c..d2162e96cf8ccb5fef144ea5c34605081195341d 100644 (file)
@@ -178,6 +178,19 @@ jobs:
         Format=${{ matrix.format }}
         EOF
 
+    # Make sure systemd-repart and split artifacts generates a usable output for systemd-sysupdate
+    - name: Configure ${{ matrix.distro }}/${{ matrix.format }} repart
+      if: matrix.format == 'disk'
+      run: |
+        tee mkosi.conf.d/01-repart.conf <<- EOF
+        [Output]
+        SplitArtifacts=yes
+        CompressOutput=xz
+
+        [Validation]
+        Checksum=yes
+        EOF
+
     - name: Resolve Arch geo mirror location
       if: matrix.distro == 'arch'
       run: curl -I geo.mirror.pkgbuild.com
@@ -185,6 +198,18 @@ jobs:
     - name: Build ${{ matrix.distro }}/${{ matrix.format }}
       run: python3 -m mkosi build
 
+    - name: Confirm ${{ matrix.distro }}/${{ matrix.format }} repart output
+      if: matrix.format == 'disk'
+      run: |
+        # Check for SHA256SUMS file. It cannot have a prefix.
+        [ -f SHA256SUMS ]
+
+        # Check for a compressed raw disk image
+        grep -q image.raw.xz SHA256SUMS
+
+        # Check for a compressed root split image
+        grep -q image.root-x86-64.raw.xz SHA256SUMS
+
     # systemd-resolved is enabled by default in Arch/Debian/Ubuntu (systemd default preset) but fails to
     # start in a systemd-nspawn container with --private-users so we mask it out here to avoid CI failures.
     # FIXME: Remove when Arch/Debian/Ubuntu ship systemd v253
@@ -192,6 +217,19 @@ jobs:
       if: matrix.format == 'directory'
       run: sudo systemctl --root image mask systemd-resolved
 
+    # The systemd-repart test **needs** compressed artifacts to confirm proper hash output.
+    # Those compressed artifacts are useless for booting. Only decompress what we need.
+    - name: Decompress ${{ matrix.distro }}/${{ matrix.format }} artifacts
+      if: matrix.format == 'disk' || matrix.format == 'directory'
+      run: |
+        if [ -f mkosi.conf.d/01-repart.conf ] ; then rm mkosi.conf.d/01-repart.conf ; fi
+
+        if [ -f mkosi.output/image.efi.xz  ] ; then xz --decompress mkosi.output/image.efi.xz  ; fi
+        if [ -f mkosi.output/image.efi.zst ] ; then zst -d --rm     mkosi.output/image.efi.zst ; fi
+
+        if [ -f mkosi.output/image.raw.xz  ] ; then xz --decompress mkosi.output/image.raw.xz  ; fi
+        if [ -f mkosi.output/image.raw.zst ] ; then zst -d --rm     mkosi.output/image.raw.zst ; fi
+
     - name: Boot ${{ matrix.distro }}/${{ matrix.format }} systemd-nspawn
       if: matrix.format == 'disk' || matrix.format == 'directory'
       run: sudo python3 -m mkosi boot
index 70b7d414a66666091eaecc2ec4ac948ac750bc13..0d584cf242536613552b8e89722ac37f10367a7a 100644 (file)
@@ -118,10 +118,8 @@ images, for example via \f[V]machinectl pull-raw \&...\f[R] and
 \f[V]machinectl   pull-tar \&...\f[R].
 .TP
 \f[V]bump\f[R]
-Determines the current image version string (as configured with
-\f[V]ImageVersion=\f[R]/\f[V]--image-version=\f[R]), increases its last
-dot-separated component by one and writes the resulting version string
-to \f[V]mkosi.version\f[R].
+Bumps the image version from \f[V]mkosi.version\f[R] and writes the
+resulting version string to \f[V]mkosi.version\f[R].
 This is useful for implementing a simple versioning scheme: each time
 this verb is called the version is bumped in preparation for the
 subsequent build.
@@ -259,16 +257,116 @@ either \[lq]1\[rq], \[lq]yes\[rq], or \[lq]true\[rq] to enable, or
 .TP
 \f[V]Distribution=\f[R]
 Matches against the configured distribution.
+Multiple distributions may be specified, separated by spaces.
+If multiple distributions are specified, the condition is satisfied if
+the current distribution equals any of the specified distributions.
 .TP
 \f[V]Release=\f[R]
 Matches against the configured distribution release.
 If this condition is used and no distribution has been explicitly
 configured yet, the host distribution and release are used.
+Multiple releases may be specified, separated by spaces.
+If multiple releases are specified, the condition is satisfied if the
+current release equals any of the specified releases.
 .TP
 \f[V]PathExists=\f[R]
 This condition is satisfied if the given path exists.
 Relative paths are interpreted relative to the parent directory of the
 config file that the condition is read from.
+.TP
+\f[V]ImageId=\f[R]
+Matches against the configured image ID, supporting globs.
+If this condition is used and no image ID has been explicitly configured
+yet, this condition fails.
+Multiple image IDs may be specified, separated by spaces.
+If multiple image IDs are specified, the condition is satisfied if the
+configured image ID equals any of the specified image IDs.
+.TP
+\f[V]ImageVersion=\f[R]
+Matches against the configured image version.
+Image versions can be prepended by the operators \f[V]==\f[R],
+\f[V]!=\f[R], \f[V]>=\f[R], \f[V]<=\f[R], \f[V]<\f[R], \f[V]>\f[R] for
+rich version comparisons according to the UAPI group version format
+specification.
+If no operator is prepended, the equality operator is assumed by default
+If this condition is used and no image Version has be explicitly
+configured yet, this condition fails.
+Multiple image version constraints can be specified as a space-separated
+list.
+If multiple image version constraints are specified, all must be
+satisfied for the match to succeed.
+.PP
+.TS
+tab(@);
+lw(14.2n) lw(14.2n) lw(5.8n) lw(15.0n) lw(20.8n).
+T{
+Matcher
+T}@T{
+Multiple Values
+T}@T{
+Globs
+T}@T{
+Rich Comparisons
+T}@T{
+Default
+T}
+_
+T{
+\f[V]Distribution=\f[R]
+T}@T{
+yes
+T}@T{
+no
+T}@T{
+no
+T}@T{
+match host distribution
+T}
+T{
+\f[V]Release=\f[R]
+T}@T{
+yes
+T}@T{
+no
+T}@T{
+no
+T}@T{
+match host release
+T}
+T{
+\f[V]PathExists=\f[R]
+T}@T{
+no
+T}@T{
+no
+T}@T{
+no
+T}@T{
+match fails
+T}
+T{
+\f[V]ImageId=\f[R]
+T}@T{
+yes
+T}@T{
+yes
+T}@T{
+no
+T}@T{
+match fails
+T}
+T{
+\f[V]ImageVersion=\f[R]
+T}@T{
+yes
+T}@T{
+no
+T}@T{
+yes
+T}@T{
+match fails
+T}
+.TE
 .SS [Distribution] Section
 .TP
 \f[V]Distribution=\f[R], \f[V]--distribution=\f[R], \f[V]-d\f[R]
@@ -322,8 +420,8 @@ For Arch Linux, additional repositories must be passed in the form
 \f[V]<name>::<url>\f[R] (e.g.\ \f[V]myrepo::https://myrepo.net\f[R]).
 .TP
 \f[V]RepositoryDirectories\f[R], \f[V]--repo-dir=\f[R]
-This option can (for now) only be used with RPM-based distributions and
-Arch Linux.
+This option can (for now) only be used with RPM-based distributions,
+Debian-based distributions and Arch Linux.
 It takes a comma separated list of directories containing extra
 repository definitions that will be used when installing packages.
 The files are passed directly to the corresponding package manager and
@@ -394,6 +492,42 @@ It\[cq]s safe to manually remove the contents of this directory should
 an \f[V]mkosi\f[R] invocation be aborted abnormally (for example, due to
 reboot/power failure).
 .TP
+\f[V]CacheDirectory=\f[R], \f[V]--cache-dir=\f[R]
+Takes a path to a directory to use as package cache for the distribution
+package manager used.
+If this option is not used, but a \f[V]mkosi.cache/\f[R] directory is
+found in the local directory it is automatically used for this purpose.
+The directory configured this way is mounted into both the development
+and the final image while the package manager is running.
+.TP
+\f[V]BuildDirectory=\f[R], \f[V]--build-dir=\f[R]
+Takes a path of a directory to use as build directory for build systems
+that support out-of-tree builds (such as Meson).
+The directory used this way is shared between repeated builds, and
+allows the build system to reuse artifacts (such as object files,
+executable, \&...)
+generated on previous invocations.
+This directory is mounted into the development image when the build
+script is invoked.
+The build script can find the path to this directory in the
+\f[V]$BUILDDIR\f[R] environment variable.
+If this option is not specified, but a directory
+\f[V]mkosi.builddir/\f[R] exists in the local directory it is
+automatically used for this purpose (also see the \[lq]Files\[rq]
+section below).
+.TP
+\f[V]InstallDirectory=\f[R], \f[V]--install-dir=\f[R]
+Takes a path of a directory to use as the install directory.
+The directory used this way is shared between builds and allows the
+build system to not have to reinstall files that were already installed
+by a previous build and didn\[cq]t change.
+The build script can find the path to this directory in the
+\f[V]$DESTDIR\f[R] environment variable.
+If this option is not specified, but a directory
+\f[V]mkosi.installdir\f[R] exists in the local directory, it is
+automatically used for this purpose (also see the \[lq]Files\[rq]
+section below).
+.TP
 \f[V]Force=\f[R], \f[V]--force\f[R], \f[V]-f\f[R]
 Replace the output file if it already exists, when building an image.
 By default when building an image and an output artifact already exists
@@ -452,17 +586,6 @@ kernel image, if \f[V]SecureBoot=\f[R] is used.
 Path to the X.509 file containing the certificate for the signed UEFI
 kernel image, if \f[V]SecureBoot=\f[R] is used.
 .TP
-\f[V]SecureBootCommonName=\f[R], \f[V]--secure-boot-common-name=\f[R]
-Common name to be used when generating SecureBoot keys via mkosi\[cq]s
-\f[V]genkey\f[R] command.
-Defaults to \f[V]mkosi of %u\f[R], where \f[V]%u\f[R] expands to the
-username of the user invoking mkosi.
-.TP
-\f[V]SecureBootValidDays=\f[R], \f[V]--secure-boot-valid-days=\f[R]
-Number of days that the keys should remain valid when generating
-SecureBoot keys via mkosi\[cq]s \f[V]genkey\f[R] command.
-Defaults to two years (730 days).
-.TP
 \f[V]SignExpectedPCR=\f[R], \f[V]--sign-expected-pcr\f[R]
 Measure the components of the unified kernel image (UKI) using
 \f[V]systemd-measure\f[R] and embed the PCR signature into the unified
@@ -499,13 +622,6 @@ scripts invoked (which may be useful to patch it into
 \f[V]/etc/os-release\f[R] or similar, in particular the
 \f[V]IMAGE_VERSION=\f[R] field of it).
 .TP
-\f[V]AutoBump=\f[R], \f[V]--auto-bump=\f[R], \f[V]-B\f[R]
-If specified, after each successful build the the version is bumped in a
-fashion equivalent to the \f[V]bump\f[R] verb, in preparation for the
-next build.
-This is useful for simple, linear version management: each build in a
-series will have a version number one higher then the previous one.
-.TP
 \f[V]ImageId=\f[R], \f[V]--image-id=\f[R]
 Configure the image identifier.
 This accepts a freeform string that shall be used to identify the image
@@ -520,12 +636,6 @@ scripts invoked (which may be useful to patch it into
 \f[V]/etc/os-release\f[R] or similar, in particular the
 \f[V]IMAGE_ID=\f[R] field of it).
 .TP
-\f[V]CacheInitrd=\f[R], \f[V]--cache-initrd\f[R]
-If specified, and incremental mode is used, mkosi will build the initrd
-in the cache image and reuse it in the final image.
-Note that this means that any changes that are only applied to the final
-image and not the cached image won\[cq]t be included in the initrd.
-.TP
 \f[V]SplitArtifacts=\f[R], \f[V]--split-artifacts\f[R]
 If specified and building a disk image, pass \f[V]--split=yes\f[R] to
 systemd-repart to have it write out split partition files for each
@@ -546,6 +656,25 @@ directory, it will be used instead.
 Note that mkosi invokes repart with \f[V]--root=\f[R] set to the root of
 the image root, so any \f[V]CopyFiles=\f[R] source paths in partition
 definition files will be relative to the image root directory.
+.IP
+:: It is recommended to have the \f[V]SplitName\f[R] parameter either
+end with \f[V]%t\f[R] or \f[V].raw\f[R] if the
+\f[V]SplitArtifacts=yes\f[R] option is set.
+This will make sure that split artifacts are compressed and the
+compressed file name is included in the checksum output if
+\f[V]Checksum=yes\f[R] is also set.
+.TP
+\f[V]Overlay=\f[R], \f[V]--overlay\f[R]
+When used together with \f[V]BaseTrees=\f[R], the output will consist
+only out of changes to the specified base trees.
+Each base tree is attached as a lower layer in an overlayfs structure,
+and the output becomes the upper layer, initially empty.
+Thus files that are not modified compared to the base trees will not be
+present in the final output.
+This option may be used to create systemd \[lq]system extensions\[rq] or
+portable services.
+See https://uapi-group.org/specifications/specs/extension_image for more
+information.
 .TP
 \f[V]TarStripSELinuxContext=\f[R], \f[V]--tar-strip-selinux-context\f[R]
 If running on a SELinux-enabled system (Fedora Linux, CentOS, Rocky
@@ -554,12 +683,6 @@ context extended attributes (\f[V]xattrs\f[R]), which may interfere with
 host SELinux rules in building or further container import stages.
 This option strips SELinux context attributes from the resulting tar
 archive.
-.TP
-\f[V]Initrd=\f[R], \f[V]--initrd\f[R]
-Use user-provided initrd(s).
-Takes a comma separated list of paths to initrd files.
-This option may be used multiple times in which case the initrd lists
-are combined.
 .SS [Content] Section
 .TP
 \f[V]Packages=\f[R], \f[V]--package=\f[R], \f[V]-p\f[R]
@@ -612,15 +735,24 @@ integration tests that are normally run during the source build process.
 Note that this option has no effect unless the \f[V]mkosi.build\f[R]
 build script honors it.
 .TP
-\f[V]CacheDirectory=\f[R], \f[V]--cache-dir=\f[R]
-Takes a path to a directory to use as package cache for the distribution
-package manager used.
-If this option is not used, but a \f[V]mkosi.cache/\f[R] directory is
-found in the local directory it is automatically used for this purpose.
-The directory configured this way is mounted into both the development
-and the final image while the package manager is running.
+\f[V]BaseTrees=\f[R], \f[V]--base-tree=\f[R]
+Takes a colon separated pair of directories to use as base images.
+When used, these base images are each copied into the OS tree and form
+the base distribution instead of installing the distribution from
+scratch.
+Only extra packages are installed on top of the ones already installed
+in the base images.
+Note that for this to work properly, the base image still needs to
+contain the package manager metadata (see
+\f[V]CleanPackageMetadata=\f[R]).
+Instead of a directory, a tar file or a disk image may be provided.
+In this case it is unpacked into the OS tree.
+This mode of operation allows setting permissions and file ownership
+explicitly, in particular for projects stored in a version control
+system such as \f[V]git\f[R] which retain full file ownership and access
+mode metadata for committed files.
 .TP
-\f[V]SkeletonTree=\f[R], \f[V]--skeleton-tree=\f[R]
+\f[V]SkeletonTrees=\f[R], \f[V]--skeleton-tree=\f[R]
 Takes a colon separated pair of paths.
 The first path refers to a directory to copy into the OS tree before
 invoking the package manager.
@@ -633,17 +765,12 @@ If this option is not used, but the \f[V]mkosi.skeleton/\f[R] directory
 is found in the local directory it is automatically used for this
 purpose with the root directory as target (also see the \[lq]Files\[rq]
 section below).
-Instead of a directory, a tar file may be provided.
-In this case it is unpacked into the OS tree before the package manager
-is invoked.
-This mode of operation allows setting permissions and file ownership
-explicitly, in particular for projects stored in a version control
-system such as \f[V]git\f[R] which retain full file ownership and access
-mode metadata for committed files.
-If the tar file \f[V]mkosi.skeleton.tar\f[R] is found in the local
-directory it will be automatically used for this purpose.
+As with the base tree logic above, instead of a directory, a tar file
+may be provided too.
+\f[V]mkosi.skeleton.tar\f[R] will be automatically used if found in the
+local directory.
 .TP
-\f[V]ExtraTree=\f[R], \f[V]--extra-tree=\f[R]
+\f[V]ExtraTrees=\f[R], \f[V]--extra-tree=\f[R]
 Takes a colon separated pair of paths.
 The first path refers to a directory to copy from the host into the
 image.
@@ -656,9 +783,9 @@ If this option is not used, but the \f[V]mkosi.extra/\f[R] directory is
 found in the local directory it is automatically used for this purpose
 with the root directory as target.
 (also see the \[lq]Files\[rq] section below).
-As with the skeleton tree logic above, instead of a directory, a tar
-file may be provided too.
-\f[V]mkosi.skeleton.tar\f[R] will be automatically used if found in the
+As with the base tree logic above, instead of a directory, a tar file
+may be provided too.
+\f[V]mkosi.extra.tar\f[R] will be automatically used if found in the
 local directory.
 .TP
 \f[V]CleanPackageMetadata=\f[R], \f[V]--clean-package-metadata=\f[R]
@@ -698,34 +825,6 @@ earlier one.
 Takes a path to a source tree to mount into the development image, if
 the build script is used.
 .TP
-\f[V]BuildDirectory=\f[R], \f[V]--build-dir=\f[R]
-Takes a path of a directory to use as build directory for build systems
-that support out-of-tree builds (such as Meson).
-The directory used this way is shared between repeated builds, and
-allows the build system to reuse artifacts (such as object files,
-executable, \&...)
-generated on previous invocations.
-This directory is mounted into the development image when the build
-script is invoked.
-The build script can find the path to this directory in the
-\f[V]$BUILDDIR\f[R] environment variable.
-If this option is not specified, but a directory
-\f[V]mkosi.builddir/\f[R] exists in the local directory it is
-automatically used for this purpose (also see the \[lq]Files\[rq]
-section below).
-.TP
-\f[V]InstallDirectory=\f[R], \f[V]--install-dir=\f[R]
-Takes a path of a directory to use as the install directory.
-The directory used this way is shared between builds and allows the
-build system to not have to reinstall files that were already installed
-by a previous build and didn\[cq]t change.
-The build script can find the path to this directory in the
-\f[V]$DESTDIR\f[R] environment variable.
-If this option is not specified, but a directory
-\f[V]mkosi.installdir\f[R] exists in the local directory, it is
-automatically used for this purpose (also see the \[lq]Files\[rq]
-section below).
-.TP
 \f[V]BuildPackages=\f[R], \f[V]--build-package=\f[R]
 Similar to \f[V]Packages=\f[R], but configures packages to install only
 in the first phase of the build, into the development image.
@@ -823,18 +922,15 @@ when the image is run.
 If this setting is not used but an \f[V]mkosi.nspawn\f[R] file found in
 the local directory it is automatically used for this purpose.
 .TP
-\f[V]BaseImage=\f[R], \f[V]--base-image=\f[R]
-Use the specified directory or file system image as the base image, and
-create the output image that consists only of changes from this base.
-The base image is attached as the lower file system in an overlayfs
-structure, and the output filesystem becomes the upper layer, initially
-empty.
-Thus files that are not modified compared to the base image are not
-present in the output image.
-This option may be used to create systemd \[lq]system extensions\[rq] or
-portable services.
-See https://systemd.io/PORTABLE_SERVICES/#extension-images for more
-information.
+\f[V]Initrd=\f[R], \f[V]--initrd\f[R]
+Use user-provided initrd(s).
+Takes a comma separated list of paths to initrd files.
+This option may be used multiple times in which case the initrd lists
+are combined.
+.TP
+\f[V]MakeInitrd=\f[R], \f[V]--make-initrd\f[R]
+Add \f[V]/etc/initrd-release\f[R] and \f[V]/init\f[R] to the image so
+that it can be used as an initramfs.
 .SS [Validation] Section
 .TP
 \f[V]Checksum=\f[R], \f[V]--checksum\f[R]
@@ -967,15 +1063,34 @@ removed and then re-created.
 .TP
 \f[V]--debug=\f[R]
 Enable additional debugging output.
-Takes a comma-separated list of arguments specifying the area of
-interest.
-Pass any invalid value (e.g.\ empty) to list currently accepted values.
+.TP
+\f[V]--debug-shell=\f[R]
+When executing a command in the image fails, mkosi will start an
+interactive shell in the image allowing further debugging.
 .TP
 \f[V]--version\f[R]
 Show package version.
 .TP
 \f[V]--help\f[R], \f[V]-h\f[R]
 Show brief usage information.
+.TP
+\f[V]--secure-boot-common-name=\f[R]
+Common name to be used when generating SecureBoot keys via mkosi\[cq]s
+\f[V]genkey\f[R] command.
+Defaults to \f[V]mkosi of %u\f[R], where \f[V]%u\f[R] expands to the
+username of the user invoking mkosi.
+.TP
+\f[V]--secure-boot-valid-days=\f[R]
+Number of days that the keys should remain valid when generating
+SecureBoot keys via mkosi\[cq]s \f[V]genkey\f[R] command.
+Defaults to two years (730 days).
+.TP
+\f[V]--auto-bump=\f[R], \f[V]-B\f[R]
+If specified, after each successful build the the version is bumped in a
+fashion equivalent to the \f[V]bump\f[R] verb, in preparation for the
+next build.
+This is useful for simple, linear version management: each build in a
+series will have a version number one higher then the previous one.
 .SS Supported distributions
 .PP
 Images may be created containing installations of the following
@@ -1545,4 +1660,6 @@ The mkosi OS generation tool (https://lwn.net/Articles/726655/) story on
 LWN
 .SH SEE ALSO
 .PP
-\f[V]systemd-nspawn(1)\f[R], \f[V]dnf(8)\f[R]
+\f[V]systemd-nspawn(1)\f[R], \f[V]dnf(8)\f[R],
+.SH AUTHORS
+The mkosi Authors.
index 3bbce09fd744a5476d4402f52dd984126a6bb87f..27d8341b46645e15d30eb23bd5066d65829b1d3d 100644 (file)
--- a/mkosi.md
+++ b/mkosi.md
@@ -539,6 +539,11 @@ a boolean argument: either "1", "yes", or "true" to enable, or "0",
   image root, so any `CopyFiles=` source paths in partition definition files will
   be relative to the image root directory.
 
+  It is recommended to have the `SplitName` parameter either end with `%t` or
+  `.raw` if the `SplitArtifacts=yes` option is set. This will make sure that
+  split artifacts are compressed and the compressed file name is included in the
+  checksum output if `Checksum=yes` is also set.
+
 `Overlay=`, `--overlay`
 
 : When used together with `BaseTrees=`, the output will consist only out of
index 636cafb772c3b8c1dc93a3f26c4f3d28d754a69e..10bbd54c2d4ebeeb9cb0874141540859014eeca2 100644 (file)
@@ -835,6 +835,10 @@ def compress_output(config: MkosiConfig, src: Path, uid: int, gid: int) -> None:
             run(["fallocate", "--dig-holes", src], user=uid, group=gid)
     else:
         with complete_step(f"Compressing output file {src}…"):
+            compressed_path = Path(f"{src}.{config.compress_output.value}")
+            if compressed_path.exists():
+                compressed_path.unlink()
+
             run(compressor_command(config.compress_output, src), user=uid, group=gid)
 
 
@@ -865,11 +869,14 @@ def calculate_sha256sum(state: MkosiState) -> None:
         return None
 
     with complete_step("Calculating SHA256SUMS…"):
-        with open(state.workspace / state.config.output_checksum.name, "w") as f:
-            for p in state.staging.iterdir():
-                hash_file(f, p)
+        with open(state.staging / state.config.output_checksum.name, "w") as f:
+            for p in state.config.output.parent.iterdir():
+                # Only hash files that start with the output name prefix
+                if p.name.startswith(state.config.output.with_suffix("").name):
+                    hash_file(f, p)
 
-        os.rename(state.workspace / state.config.output_checksum.name, state.staging / state.config.output_checksum.name)
+        os.rename(state.staging / state.config.output_checksum.name, state.config.output_checksum)
+        os.chown(state.config.output_checksum, uid=state.uid, gid=state.gid)
 
 
 def calculate_signature(state: MkosiState) -> None:
@@ -885,7 +892,7 @@ def calculate_signature(state: MkosiState) -> None:
 
         cmdline += [
             "--output", state.staging / state.config.output_signature.name,
-            state.staging / state.config.output_checksum.name,
+            state.config.output_checksum,
         ]
 
         run(
@@ -904,6 +911,9 @@ def calculate_signature(state: MkosiState) -> None:
             }
         )
 
+        os.rename(state.staging / state.config.output_signature.name, state.config.output_signature)
+        os.chown(state.config.output_signature, uid=state.uid, gid=state.gid)
+
 
 def save_cache(state: MkosiState) -> None:
     final, build = cache_tree_paths(state.config)
@@ -974,6 +984,8 @@ def unlink_output(args: MkosiArgs, config: MkosiConfig) -> None:
                     unlink_try_hard(p)
 
         unlink_try_hard(Path(f"{config.output}.manifest"))
+        if config.compress_output:
+            unlink_try_hard(Path(f"{config.output}.manifest.{config.compress_output.value}"))
         unlink_try_hard(Path(f"{config.output}.changelog"))
 
         if config.output_split_kernel.parent.exists():
@@ -1444,6 +1456,7 @@ def invoke_repart(state: MkosiState, skip: Sequence[str] = [], split: bool = Fal
                         CopyFiles=/boot:/
                         SizeMinBytes=1024M
                         SizeMaxBytes=1024M
+                        SplitName=-
                         """
                     )
                 )
@@ -1671,8 +1684,6 @@ def build_stuff(uid: int, gid: int, args: MkosiArgs, config: MkosiConfig) -> Non
             build_image(state, manifest=manifest, for_cache=False)
 
         copy_nspawn_settings(state)
-        calculate_sha256sum(state)
-        calculate_signature(state)
         save_manifest(state, manifest)
 
         for p in state.config.output_paths():
@@ -1680,14 +1691,20 @@ def build_stuff(uid: int, gid: int, args: MkosiArgs, config: MkosiConfig) -> Non
                 shutil.move(state.staging / p.name, p)
                 if p != state.config.output or state.config.output_format != OutputFormat.directory:
                     os.chown(p, uid, gid)
-                if p == state.config.output:
+                if p == state.config.output or p.suffix in ['.efi', '.manifest', '.raw']:
                     compress_output(state.config, p, uid=uid, gid=gid)
 
+        for p in state.staging.iterdir():
+            if p.suffix in ['.efi', '.manifest', '.raw']:
+                compress_output(state.config, p, uid=0, gid=0)
+
+        # Run again after files are potentally compressed and renamed
         for p in state.staging.iterdir():
             shutil.move(p, state.config.output.parent / p.name)
             os.chown(state.config.output.parent / p.name, uid, gid)
-            if p.name.startswith(state.config.output.name):
-                compress_output(state.config, p, uid=uid, gid=gid)
+
+        calculate_sha256sum(state)
+        calculate_signature(state)
 
     print_output_size(config)
 
index ccbd2c3da8c7ca47887975adc2fc397ab5d6978b..5f7c0ebb314740a0f6fce62294c5a78502de48a3 100644 (file)
@@ -616,11 +616,11 @@ class MkosiConfig:
 
     @property
     def output_checksum(self) -> Path:
-        return build_auxiliary_output_path(self, ".SHA256SUMS")
+        return self.output.parent / "SHA256SUMS"
 
     @property
     def output_signature(self) -> Path:
-        return build_auxiliary_output_path(self, ".SHA256SUMS.gpg")
+        return self.output.parent / "SHA256SUMS.gpg"
 
     @property
     def output_sshkey(self) -> Path:
@@ -1801,6 +1801,7 @@ def strip_suffixes(path: Path) -> Path:
     while path.suffix in {
         ".xz",
         ".zstd",
+        ".zst",
         ".raw",
         ".tar",
         ".cpio",