build: record the actual build environment in .buildinfo

The binary build exported DEB_BUILD_OPTIONS='parallel=<context nproc>
nocheck' (or the -j override) but the generated .buildinfo recomputed
the environment from host state: host core count, no nocheck, and
vendor profiles that ignored DEB_BUILD_PROFILES (a cross build recorded
no 'cross' profile). generate_binary_metadata now records the exact env
map that was exported to the build steps, and the recorded profiles
come from the exported DEB_BUILD_PROFILES when set.

Also unifies vendor parsing on one helper (the context-side copy lacked
the Origin: fallback of the source-build path).
This commit is contained in:
2026-09-16 04:22:43 +02:00
parent 50ae12cafe
commit 3a454b0811
4 changed files with 98 additions and 54 deletions
+23 -24
View File
@@ -5,7 +5,7 @@ use crate::deb::find_dsc_file;
use crate::ui::deb::{DebUi, Phase};
use crate::ui::logfmt::QuiltClassifier;
use log::warn;
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
use std::error::Error;
use std::path::{Path, PathBuf};
use std::sync::Arc;
@@ -420,10 +420,6 @@ fn generate_upload_metadata(
env: &HashMap<String, String>,
ctx: &Arc<Context>,
) -> Result<(PathBuf, PathBuf), Box<dyn Error>> {
let changelog_path = Path::new(package_dir).join("debian/changelog");
let changelog_content = ctx.read_file(&changelog_path)?;
let entry = crate::debian::parse_changelog_entry_from_str(&changelog_content)?;
// Build architecture: the machine inside the build context.
let build_arch = ctx
.command("dpkg")
@@ -440,34 +436,37 @@ fn generate_upload_metadata(
build_arch.clone()
};
// Vendor resolution inside the context (falls back to the host view).
// Vendor resolution inside the context (falls back to the host view);
// shared `Vendor:`/`Origin:` parsing with the source-build path.
let vendor = ctx
.read_file(Path::new("/etc/dpkg/origins/default"))
.ok()
.and_then(|content| {
for line in content.lines() {
if let Some(v) = line.strip_prefix("Vendor:") {
let v = v.trim();
if !v.is_empty() {
return Some(v.to_string());
}
}
}
None
})
.and_then(|content| crate::build::env::vendor_from_origins_content(&content))
.unwrap_or_else(crate::build::env::current_vendor);
let profiles = crate::build::env::resolve_build_profiles(&[], &vendor);
let source_date_epoch = env
.get("SOURCE_DATE_EPOCH")
.and_then(|v| v.parse::<i64>().ok())
.unwrap_or(entry.timestamp);
// The recorded profiles must describe what the build actually ran with:
// the DEB_BUILD_PROFILES exported to the build steps ('cross' for cross
// builds), else the vendor defaults.
let profiles = match env.get("DEB_BUILD_PROFILES") {
Some(value) => value
.split(',')
.map(|p| p.trim().to_string())
.filter(|p| !p.is_empty())
.collect(),
None => crate::build::env::resolve_build_profiles(&[], &vendor),
};
// Record exactly the environment exported to the build steps
// (DEB_BUILD_OPTIONS with the real parallel count and 'nocheck', LANG=C,
// SOURCE_DATE_EPOCH, cross DEB_* variables, ...), not values recomputed
// from host state; buildinfo_environment filters out non-dpkg variables.
let exported_env: BTreeMap<String, String> =
env.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
let opts = crate::build::binary::BinaryMetadataOptions {
profiles,
vendor,
parallel: crate::build::env::num_parallel(),
source_date_epoch,
exported_env,
build_arch,
host_arch,
};