From ed76b3ef7f6c2ac3c918923d97c86a145fefb295 Mon Sep 17 00:00:00 2001 From: Valentin Haudiquet Date: Wed, 30 Sep 2026 14:18:45 +0200 Subject: [PATCH] deb,build: export ddebs from binary builds dh_strip registers debug-symbol packages in debian/files under their renamed .ddeb name; they are deliverables of the build just like the regular .debs. Both artifact-type filters, the one collecting the build's artifacts and the one feeding the .buildinfo/.changes checksum sections, accepted only deb and udeb, so every ddeb a build produced was silently discarded: nothing exported next to the .debs, nothing in the upload metadata. The filter is now a shared FilesEntry::is_binary_artifact() predicate (plus unit tests) used by both call sites, so the two cannot drift apart again. One dpkg distinction has to be copied rather than shared: dpkg-genchanges lists only deb/udeb packages in the changes' Binary: and Description (a ddeb travels in Files and the checksum sections but is not a listed binary of the upload), while dpkg-genbuildinfo lists every binary artifact's package, ddebs included. The package list is therefore accumulated twice, once per consumer. The binary-metadata differential fixture gains a Package-Type: ddeb package, so the native .changes/.buildinfo generation is compared against real dpkg with a ddeb present. Without the fix the comparison fails on the checksum sections (golden distributes the ddeb, ours dropped it); with it every field matches. --- src/build/binary.rs | 24 ++++++++++++++++++------ src/build/mod.rs | 9 ++++++--- src/deb/local.rs | 2 +- src/debian/files.rs | 30 ++++++++++++++++++++++++++++++ 4 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/build/binary.rs b/src/build/binary.rs index 9830c3b..3d6d570 100644 --- a/src/build/binary.rs +++ b/src/build/binary.rs @@ -92,7 +92,7 @@ pub fn generate_binary_metadata( // ------------------------------------------------------------------ let artifact_names: Vec = files_list .iter() - .filter(|e| matches!(e.package_type.as_deref(), Some("deb") | Some("udeb"))) + .filter(|e| e.is_binary_artifact()) .map(|e| e.filename.clone()) .collect(); @@ -159,16 +159,28 @@ pub fn generate_binary_metadata( // ------------------------------------------------------------------ // Binary package names and descriptions // ------------------------------------------------------------------ + // dpkg-genchanges lists only deb/udeb packages in `Binary:` (a ddeb + // is distributed through Files but is not a listed binary of the + // upload), while dpkg-genbuildinfo lists every binary artifact's + // package, ddebs included. let mut binaries: Vec = Vec::new(); + let mut buildinfo_binaries: Vec = Vec::new(); for name in &artifact_names { - if let Some(e) = files_list.get(name) - && let Some(pkg) = &e.package - && !binaries.contains(pkg) - { + let Some(e) = files_list.get(name) else { + continue; + }; + let Some(pkg) = &e.package else { + continue; + }; + if !buildinfo_binaries.contains(pkg) { + buildinfo_binaries.push(pkg.clone()); + } + if e.package_type.as_deref() != Some("ddeb") && !binaries.contains(pkg) { binaries.push(pkg.clone()); } } binaries.sort(); + buildinfo_binaries.sort(); // Description lines: first line of each binary stanza's Description, // formatted exactly like dpkg-genchanges, sorted. @@ -238,7 +250,7 @@ pub fn generate_binary_metadata( let buildinfo_doc = crate::build::buildinfo::render_buildinfo(&crate::build::buildinfo::BuildInfoInput { source: source_display.clone(), - binaries: binaries.clone(), + binaries: buildinfo_binaries.clone(), architecture: buildinfo_arch_values.join(" "), version: entry.version.full(), binary_only_changes: binary_only_changes.clone(), diff --git a/src/build/mod.rs b/src/build/mod.rs index 983d1fe..0573c43 100644 --- a/src/build/mod.rs +++ b/src/build/mod.rs @@ -1889,19 +1889,22 @@ Provides: virtual-thing (= 2.0), plain-virtual } /// debian/control shared by the binary-metadata differential cases: one - /// arch:any deb and one arch:all udeb. + /// arch:any deb, one arch:all udeb and one arch:all ddeb (the + /// debug-symbol shape dh_strip leaves behind: the package type + /// drives the file name in debian/files). fn binary_test_control(name: &str) -> String { format!( "Source: {name}\nSection: utils\nPriority: optional\nMaintainer: {MAINTAINER}\nBuild-Depends: libc6\n\n\ Package: {name}\nArchitecture: any\nDescription: test package main\n long description\n\n\ - Package: {name}-u\nPackage-Type: udeb\nArchitecture: all\nDescription: test udeb\n short\n" + Package: {name}-u\nPackage-Type: udeb\nArchitecture: all\nDescription: test udeb\n short\n\n\ + Package: {name}-d\nPackage-Type: ddeb\nArchitecture: all\nDescription: test ddeb\n short\n" ) } /// debian/rules driving dpkg-gencontrol/dpkg-deb directly (no debhelper). fn binary_test_rules(name: &str) -> String { format!( - "#!/usr/bin/make -f\nV = $(shell dpkg-parsechangelog -S Version)\nA = $(shell dpkg-architecture -qDEB_HOST_ARCH)\n\nbuild:\n\tmkdir -p debian/tmp/usr/bin\n\tprintf '#!/bin/sh\\necho hi\\n' > debian/tmp/usr/bin/hello\n\tchmod 755 debian/tmp/usr/bin/hello\n\ttouch $@\n\nbinary: build\n\trm -rf debian/{name} debian/{name}-u\n\tmkdir -p debian/{name}/usr/bin debian/{name}/DEBIAN\n\tcp -r debian/tmp/. debian/{name}/\n\tdpkg-gencontrol -p{name} -Pdebian/{name}\n\tdpkg-deb --build debian/{name} ..\n\tmkdir -p debian/{name}-u/usr/share debian/{name}-u/DEBIAN\n\techo data > debian/{name}-u/usr/share/data.txt\n\tdpkg-gencontrol -p{name}-u -Pdebian/{name}-u\n\tdpkg-deb --build debian/{name}-u ..\n\tmv ../{name}-u_$(V)_all.deb ../{name}-u_$(V)_all.udeb\n\nclean:\n\trm -rf debian/tmp debian/{name} debian/{name}-u build-stamp debian/files debian/*.substvars\n\n.PHONY: build binary clean\n" + "#!/usr/bin/make -f\nV = $(shell dpkg-parsechangelog -S Version)\nA = $(shell dpkg-architecture -qDEB_HOST_ARCH)\n\nbuild:\n\tmkdir -p debian/tmp/usr/bin\n\tprintf '#!/bin/sh\\necho hi\\n' > debian/tmp/usr/bin/hello\n\tchmod 755 debian/tmp/usr/bin/hello\n\ttouch $@\n\nbinary: build\n\trm -rf debian/{name} debian/{name}-u debian/{name}-d\n\tmkdir -p debian/{name}/usr/bin debian/{name}/DEBIAN\n\tcp -r debian/tmp/. debian/{name}/\n\tdpkg-gencontrol -p{name} -Pdebian/{name}\n\tdpkg-deb --build debian/{name} ..\n\tmkdir -p debian/{name}-u/usr/share debian/{name}-u/DEBIAN\n\techo data > debian/{name}-u/usr/share/data.txt\n\tdpkg-gencontrol -p{name}-u -Pdebian/{name}-u\n\tdpkg-deb --build debian/{name}-u ..\n\tmv ../{name}-u_$(V)_all.deb ../{name}-u_$(V)_all.udeb\n\tmkdir -p debian/{name}-d/usr/share debian/{name}-d/DEBIAN\n\techo data > debian/{name}-d/usr/share/data.txt\n\tdpkg-gencontrol -p{name}-d -Pdebian/{name}-d\n\tdpkg-deb --build debian/{name}-d ..\n\tmv ../{name}-d_$(V)_all.deb ../{name}-d_$(V)_all.ddeb\n\nclean:\n\trm -rf debian/tmp debian/{name} debian/{name}-u debian/{name}-d build-stamp debian/files debian/*.substvars\n\n.PHONY: build binary clean\n" ) } diff --git a/src/deb/local.rs b/src/deb/local.rs index c28dec3..e728f10 100644 --- a/src/deb/local.rs +++ b/src/deb/local.rs @@ -939,7 +939,7 @@ fn collect_binary_artifacts( let upload_dir = Path::new(build_root); let mut artifacts = Vec::new(); for entry in files_list.iter() { - if matches!(entry.package_type.as_deref(), Some("deb") | Some("udeb")) { + if entry.is_binary_artifact() { artifacts.push(upload_dir.join(&entry.filename)); } } diff --git a/src/debian/files.rs b/src/debian/files.rs index a587712..08dda15 100644 --- a/src/debian/files.rs +++ b/src/debian/files.rs @@ -46,6 +46,21 @@ impl FilesEntry { entry.priority = priority.to_string(); entry } + + /// Whether this entry is a binary-package artifact that must be + /// exported from the build: a `.deb`, a `.udeb`, or a `.ddeb`. + /// + /// Debug-symbol packages are registered in `debian/files` by + /// `dh_strip` under their renamed `.ddeb` name; they are as much + /// a deliverable of the build as the regular `.deb`s (they belong + /// in the upload set), so any filter keyed on artifact type has + /// to accept them. + pub fn is_binary_artifact(&self) -> bool { + matches!( + self.package_type.as_deref(), + Some("deb") | Some("udeb") | Some("ddeb") + ) + } } /// Derive metadata from an artifact file name following the common @@ -243,6 +258,21 @@ mod tests { assert_eq!(e.package_type, None); } + #[test] + fn binary_artifact_filter_accepts_ddebs() { + let deb = parse_filename("hello_2.10-3_amd64.deb").unwrap(); + let udeb = parse_filename("hello_2.10-3_amd64.udeb").unwrap(); + let ddeb = parse_filename("hello-dbgsym_2.10-3_amd64.ddeb").unwrap(); + let buildinfo = parse_filename("hello_2.10-3_amd64.buildinfo").unwrap(); + let changes = parse_filename("hello_2.10-3_amd64.changes").unwrap(); + + assert!(deb.is_binary_artifact()); + assert!(udeb.is_binary_artifact()); + assert!(ddeb.is_binary_artifact(), "ddebs must be exported"); + assert!(!buildinfo.is_binary_artifact()); + assert!(!changes.is_binary_artifact()); + } + #[test] fn load_save_roundtrip() { let dir = tempfile::tempdir().unwrap();