From: Luca Boccassi Date: Sat, 16 Oct 2021 20:39:41 +0000 (+0100) Subject: manifest: add support for deb distros X-Git-Tag: v11~13^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F841%2Fhead;p=thirdparty%2Fmkosi.git manifest: add support for deb distros Use 'dpkg-query' and 'apt-get changelog' to get metadata and changelogs --- diff --git a/mkosi/manifest.py b/mkosi/manifest.py index 76f71c700..69154fef1 100644 --- a/mkosi/manifest.py +++ b/mkosi/manifest.py @@ -8,7 +8,14 @@ from subprocess import DEVNULL, PIPE from textwrap import dedent from typing import IO, Any, Dict, List, Optional, cast -from .backend import CommandLineArguments, ManifestFormat, PackageType, run +from .backend import ( + CommandLineArguments, + Distribution, + ManifestFormat, + PackageType, + run, + run_workspace_command, +) @dataclasses.dataclass @@ -70,6 +77,8 @@ class Manifest: def record_packages(self, root: Path) -> None: if cast(Any, self.args.distribution).package_type == PackageType.rpm: self.record_rpm_packages(root) + if cast(Any, self.args.distribution).package_type == PackageType.deb: + self.record_deb_packages(root) # TODO: add implementations for other package managers def record_rpm_packages(self, root: Path) -> None: @@ -116,6 +125,67 @@ class Manifest: source.add(package) + def record_deb_packages(self, root: Path) -> None: + c = run( + ["dpkg-query", f"--admindir={root}/var/lib/dpkg", "--show", "--showformat", + r'${Package}\t${source:Package}\t${Version}_${Architecture}\t${Installed-Size}\t${db-fsys:Last-Modified}\n'], + stdout=PIPE, + stderr=DEVNULL, + text=True, + ) + + packages = sorted(c.stdout.splitlines()) + + for package in packages: + name, source, version, size, installtime = package.split("\t") + + # dpkg records the size in KBs + size = int(size) * 1024 + 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("deb", name, version, size) + self.packages.append(package) + + if not self.need_source_info(): + continue + + source_package = self.source_packages.get(source) + if source_package is None: + # Yes, --quiet is specified twice, to avoid output about download stats. + # Note that the argument of the 'changelog' verb is the binary package name, + # not the source package name. + cmd = ["apt-get", "--quiet", "--quiet", "changelog", name] + + # If we are building with docs then it's easy, as the changelogs are saved + # in the image, just fetch them. Otherwise they will be downloaded from the network. + if self.args.with_docs: + # By default apt drops privileges and runs as the 'apt' user, but that means it + # loses access to the build directory, which is 700. + cmd += ["--option", "Acquire::Changelogs::AlwaysOnline=false", + "--option", "Debug::NoDropPrivs=true"] + else: + # Override the URL to avoid HTTPS, so that we don't need to install + # ca-certificates to make it work. + if self.args.distribution == Distribution.ubuntu: + cmd += ["--option", "Acquire::Changelogs::URI::Override::Origin::Ubuntu=http://changelogs.ubuntu.com/changelogs/pool/@CHANGEPATH@/changelog"] + else: + cmd += ["--option", "Acquire::Changelogs::URI::Override::Origin::Debian=http://metadata.ftp-master.debian.org/changelogs/@CHANGEPATH@_changelog"] + + # We have to run from the root, because if we use the RootDir option to make + # apt from the host look at the repositories in the image, it will also pick + # the 'methods' executables from there, but the ABI might not be compatible. + changelog = run_workspace_command(self.args, root, cmd, network=not self.args.with_docs, capture_stdout=True) + source_package = SourcePackageManifest(source, changelog) + self.source_packages[source] = source_package + + source_package.add(package) + def has_data(self) -> bool: # We might add more data in the future return len(self.packages) > 0