From: Zbigniew Jędrzejewski-Szmek Date: Thu, 9 Sep 2021 11:04:39 +0000 (+0200) Subject: manifest: when recording packages, ignore packages from the base image X-Git-Tag: v11~27^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=147e7a7b3c46ceaba7bb5da4ecb36faf9548e183;p=thirdparty%2Fmkosi.git manifest: when recording packages, ignore packages from the base image This solves the problem that the generated package list included all packages visible in the combined overlay when building something on top of a base image. Instead, we want just the stuff that was added in the overlay. I considered some other approaches: - use 'dnf history info' to query what the last transacation was. The output is human-readable tabular text, and would have to be parsed. This could be done, but there's a bigger problem: we don't necessarilly know that the last transaction is all that matters. And in fact, as raised by mdomonko in #rpm-ecosystem, dnf is not the only way to install rpm packages. Using rpm directly also covers direct rpm invocations, which could be done from the build scripts. - look at rpm transaction id. This still has the problem that we don't know if the last transaction is all that matters. So overall, the simple time-based approach should be no worse than the other ones, and is trivially easy to implement. --- diff --git a/mkosi/manifest.py b/mkosi/manifest.py index aedc7bacd..76f71c700 100644 --- a/mkosi/manifest.py +++ b/mkosi/manifest.py @@ -2,6 +2,7 @@ import dataclasses import json +from datetime import datetime from pathlib import Path from subprocess import DEVNULL, PIPE from textwrap import dedent @@ -61,6 +62,8 @@ class Manifest: packages: List[PackageManifest] = dataclasses.field(default_factory=list) source_packages: Dict[str, SourcePackageManifest] = dataclasses.field(default_factory=dict) + _init_timestamp: datetime = dataclasses.field(init=False, default_factory=datetime.now) + def need_source_info(self) -> bool: return ManifestFormat.changelog in self.args.manifest_format @@ -71,7 +74,8 @@ class Manifest: def record_rpm_packages(self, root: Path) -> None: c = run( - ["rpm", f"--root={root}", "-qa", "--qf", r"%{NEVRA}\t%{SOURCERPM}\t%{NAME}\t%{SIZE}\n"], + ["rpm", f"--root={root}", "-qa", "--qf", + r"%{NEVRA}\t%{SOURCERPM}\t%{NAME}\t%{SIZE}\t%{INSTALLTIME}\n"], stdout=PIPE, stderr=DEVNULL, text=True, @@ -80,12 +84,19 @@ class Manifest: packages = sorted(c.stdout.splitlines()) for package in packages: - nevra, srpm, name, size = package.split("\t") + nevra, srpm, name, size, installtime = package.split("\t") assert nevra.startswith(f"{name}-") evra = nevra[len(name) + 1 :] size = int(size) + installtime = datetime.fromtimestamp(int(installtime)) + + # If we are creating a layer based on a BaseImage=, e.g. a sysext, filter by + # packages that were installed in this execution of mkosi. We assume that the + # upper layer is put together in one go, which currently is always true. + if self.args.base_image and installtime < self._init_timestamp: + continue package = PackageManifest("rpm", name, evra, size) self.packages.append(package)