]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
manifest: add support for deb distros 841/head
authorLuca Boccassi <luca.boccassi@microsoft.com>
Sat, 16 Oct 2021 20:39:41 +0000 (21:39 +0100)
committerLuca Boccassi <luca.boccassi@microsoft.com>
Fri, 29 Oct 2021 14:37:12 +0000 (15:37 +0100)
Use 'dpkg-query' and 'apt-get changelog' to get metadata and changelogs

mkosi/manifest.py

index 76f71c70028b400c2e54e11e045a8d8b88ce83bc..69154fef1a518816920ac6a096173da6f515a769 100644 (file)
@@ -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