build/binary: native .buildinfo/.changes for binary builds (pkh deb)
Extend the metadata writers to binary-only uploads and wire them into the 'pkh deb' flow: - build/binary.rs generates <pkg>_<ver>_<arch>.buildinfo/.changes through any Context: debian/files consumption, encounter-order Architecture accumulation (sorted in .buildinfo like dpkg-genbuildinfo), sorted Binary lists, dpkg-formatted Description lines with udeb suffixes, Installed-Build-Depends closure over the context status DB, and binNMU handling (Source: pkg (prev), Binary-Only-Changes, previous .dsc redistribution); - artifact digests are computed inside the context via coreutils (md5sum/sha1sum/sha256sum/stat) so chrooted/remote trees work; - deb/local.rs runs the generation after 'rules binary', exports SOURCE_DATE_EPOCH from the changelog (reproducibility), and resolves vendor/profiles inside the context; deb/mod.rs retrieves the new artifacts alongside the debs; - reusable helpers added: FilesList::parse/render, parse_changelog_entry_from_str, parse_previous_version_from_str, installed_build_depends_from_content. Differential gate: same tree built with real 'dpkg-buildpackage -b' and with the pkh flow; .changes/.buildinfo compared field-by-field modulo machine-dependent fields, artifact checksums included.
This commit is contained in:
+24
-19
@@ -46,7 +46,15 @@ pub fn parse_changelog_entry(path: &Path) -> Result<ChangelogEntry, Box<dyn std:
|
||||
e
|
||||
)
|
||||
})?;
|
||||
parse_changelog_entry_from_str(&content)
|
||||
}
|
||||
|
||||
/// Parse the most recent changelog entry from its textual content. `origin`
|
||||
/// is used in error messages only.
|
||||
pub fn parse_changelog_entry_from_str(
|
||||
content: &str,
|
||||
) -> Result<ChangelogEntry, Box<dyn std::error::Error>> {
|
||||
let origin = "changelog";
|
||||
let mut lines = content.lines().peekable();
|
||||
|
||||
// --- Header line: `package (version) distributions; urgency=medium[, key=value]`
|
||||
@@ -55,17 +63,13 @@ pub fn parse_changelog_entry(path: &Path) -> Result<ChangelogEntry, Box<dyn std:
|
||||
Some(l) if l.trim().is_empty() => continue,
|
||||
Some(l) => break l.trim_end(),
|
||||
None => {
|
||||
return Err(format!("changelog '{}' is empty", path.display()).into());
|
||||
return Err(format!("changelog '{origin}' is empty").into());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let open = header.find('(').ok_or_else(|| {
|
||||
format!(
|
||||
"invalid changelog header in '{}': {}",
|
||||
path.display(),
|
||||
header
|
||||
)
|
||||
format!("invalid changelog header in '{origin}': {header}")
|
||||
})?;
|
||||
let close = header[open..]
|
||||
.find(')')
|
||||
@@ -123,9 +127,8 @@ pub fn parse_changelog_entry(path: &Path) -> Result<ChangelogEntry, Box<dyn std:
|
||||
|
||||
let trailer_line = trailer.ok_or_else(|| {
|
||||
format!(
|
||||
"no maintainer trailer found in '{}': expected a line of the form \
|
||||
' -- Name <email> Date'",
|
||||
path.display()
|
||||
"no maintainer trailer found in '{origin}': expected a line of the form \
|
||||
' -- Name <email> Date'"
|
||||
)
|
||||
})?;
|
||||
|
||||
@@ -148,12 +151,7 @@ pub fn parse_changelog_entry(path: &Path) -> Result<ChangelogEntry, Box<dyn std:
|
||||
|
||||
let timestamp = DateTime::parse_from_rfc2822(&date_raw)
|
||||
.map_err(|e| {
|
||||
format!(
|
||||
"cannot parse changelog date '{}' in '{}': {}",
|
||||
date_raw,
|
||||
path.display(),
|
||||
e
|
||||
)
|
||||
format!("cannot parse changelog date '{date_raw}' in '{origin}': {e}")
|
||||
})?
|
||||
.timestamp();
|
||||
|
||||
@@ -220,7 +218,14 @@ fn find_closes(body_lines: &[String]) -> Option<String> {
|
||||
pub fn parse_previous_version(path: &Path) -> Result<Option<String>, Box<dyn std::error::Error>> {
|
||||
let content = std::fs::read_to_string(path)
|
||||
.map_err(|e| format!("failed to read changelog '{}': {}", path.display(), e))?;
|
||||
parse_previous_version_from_str(&content)
|
||||
}
|
||||
|
||||
/// Return the version of the *previous* changelog entry from the textual
|
||||
/// content of a changelog file.
|
||||
pub fn parse_previous_version_from_str(
|
||||
content: &str,
|
||||
) -> Result<Option<String>, Box<dyn std::error::Error>> {
|
||||
let mut seen_first = false;
|
||||
for line in content.lines() {
|
||||
let line = line.trim_end();
|
||||
@@ -229,12 +234,12 @@ pub fn parse_previous_version(path: &Path) -> Result<Option<String>, Box<dyn std
|
||||
seen_first = true;
|
||||
continue;
|
||||
}
|
||||
let open = line.find('(').ok_or_else(|| {
|
||||
format!("invalid changelog header in '{}': {}", path.display(), line)
|
||||
})?;
|
||||
let open = line
|
||||
.find('(')
|
||||
.ok_or_else(|| format!("invalid changelog header: {line}"))?;
|
||||
let close = line[open..]
|
||||
.find(')')
|
||||
.ok_or_else(|| format!("unbalanced parenthesis in changelog header '{}'", line))?;
|
||||
.ok_or_else(|| format!("unbalanced parenthesis in changelog header '{line}'"))?;
|
||||
return Ok(Some(line[open + 1..open + close].to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user