deb: shrink records to upper, journal and log; keep metadata for every build
Records carried a full chroot each, and space turned out to be the hard constraint: five records per target multiplied by a multi-GB chroot does not fit. The chroot is now per-run scratch — every build extracts a fresh one from the sha-verified mmdebstrap tarball cache into its record's chroot/ dir and removes it at the end (success, failure and interrupt included); resume_chroot, the .pkh-ready probe and chroot_is_usable are gone, and crashed-run leftovers are swept when the next run of that identity starts. What a record keeps instead: manifest.json (renamed, now with the tarball sha it used, a kept_upper flag and a tree-only journal — the environment phases rerun in every fresh chroot), a log/build.log full tee of the build output (kept for EVERY build; plain runs become metadata-only records, so keep-iff-incremental now applies to the staged tree alone), and — for --incremental runs — tree-upper/ with its host-files.list. The fork gate carries a base's staged tree only while its recorded tarball sha still matches the cache and the changelog version is unchanged; a fork candidate is any record with a staged tree. The keep-last-5 cap now applies to staged trees: a sixth retention degrades the oldest record to metadata-only instead of deleting it. New `pkh deb log [-f] [<id>]` prints (or follows) a record's build log, and `pkh deb list` shows the staged-tree state and plain-run records too. README rewritten around the shrunk model.
This commit is contained in:
+25
-57
@@ -27,35 +27,12 @@ fn cap<'a>(
|
||||
cmd
|
||||
}
|
||||
|
||||
/// The session journal stamps this build works with: the input stamps of
|
||||
/// the patch and build-dependency phases, computed from the host tree and
|
||||
/// the resolved selectors.
|
||||
struct JournalStamps {
|
||||
patches: Option<String>,
|
||||
control: Option<String>,
|
||||
}
|
||||
|
||||
/// Compute the journal stamps for a session build; `None` without one.
|
||||
fn journal_stamps(
|
||||
session: &session::Session,
|
||||
arch: &str,
|
||||
series: &str,
|
||||
pocket: Option<&str>,
|
||||
cross: bool,
|
||||
ppa: &[String],
|
||||
inject_packages: &[String],
|
||||
) -> JournalStamps {
|
||||
/// The input stamp of the patch phase, computed from the host tree: the
|
||||
/// only tree phase the record journal tracks (the environment phases
|
||||
/// rerun in every fresh chroot and are not recorded).
|
||||
fn patch_stamp(session: &session::Session) -> Option<String> {
|
||||
let host_tree = PathBuf::from(session.manifest().host_tree);
|
||||
let selectors = format!(
|
||||
"{arch}\n{cross}\n{series}\n{}\n{}\n{}",
|
||||
pocket.unwrap_or(""),
|
||||
ppa.join(","),
|
||||
inject_packages.join(",")
|
||||
);
|
||||
JournalStamps {
|
||||
patches: session::patches_stamp(&host_tree),
|
||||
control: session::control_stamp(&host_tree, &selectors),
|
||||
}
|
||||
session::patches_stamp(&host_tree)
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -74,13 +51,12 @@ pub async fn build(
|
||||
view: &dyn BuildView,
|
||||
jobs: Option<usize>,
|
||||
session: Option<&session::Session>,
|
||||
resume: bool,
|
||||
build_resume: bool,
|
||||
) -> Result<Vec<PathBuf>, Box<dyn Error>> {
|
||||
let sink: Option<Arc<dyn LineSink>> = view.sink();
|
||||
|
||||
// Journal stamps for a session build; recording is a no-op without one.
|
||||
let stamps =
|
||||
session.map(|s| journal_stamps(s, arch, series, pocket, cross, ppa, inject_packages));
|
||||
// Journal stamp for a record build; recording is a no-op without one.
|
||||
let stamps = session.and_then(patch_stamp);
|
||||
|
||||
// Environment
|
||||
let mut env = HashMap::<String, String>::new();
|
||||
@@ -245,9 +221,6 @@ pub async fn build(
|
||||
or re-run with RUST_LOG=debug for more details."
|
||||
.into());
|
||||
}
|
||||
if let Some(s) = session {
|
||||
s.record_phase("apt_update", None);
|
||||
}
|
||||
|
||||
// Install essential packages
|
||||
log::debug!("Installing essential packages for local build...");
|
||||
@@ -272,9 +245,6 @@ pub async fn build(
|
||||
if !status.success() {
|
||||
return Err("Could not install essential packages for the build".into());
|
||||
}
|
||||
if let Some(s) = session {
|
||||
s.record_phase("essentials", None);
|
||||
}
|
||||
|
||||
// The package directory was resolved by the caller (the staged copy of
|
||||
// the tree the user pointed at, or the name-pattern search fallback)
|
||||
@@ -294,10 +264,11 @@ pub async fn build(
|
||||
}
|
||||
|
||||
// Apply quilt patches if the package provides a patch series. On a
|
||||
// resumed session the previous attempt's patches may still be applied:
|
||||
// pop them first when the patch tree changed since.
|
||||
let patch_stamp = stamps.as_ref().and_then(|s| s.patches.clone());
|
||||
let pop_patches = resume && {
|
||||
// build resuming over a carried upperdir the previous attempt's
|
||||
// patches may still be applied: pop them first when the patch tree
|
||||
// changed since.
|
||||
let patch_stamp = stamps.clone();
|
||||
let pop_patches = build_resume && {
|
||||
let previous = session
|
||||
.and_then(|s| s.manifest().phases.get("patches").map(|p| p.stamp.clone()))
|
||||
.unwrap_or(None);
|
||||
@@ -333,20 +304,17 @@ pub async fn build(
|
||||
view,
|
||||
&sink,
|
||||
)?;
|
||||
if let Some(s) = session {
|
||||
s.record_phase(
|
||||
"build_deps",
|
||||
stamps.as_ref().and_then(|st| st.control.clone()),
|
||||
);
|
||||
}
|
||||
// (The build-dependency phase reruns in every fresh chroot: nothing
|
||||
// to journal.)
|
||||
|
||||
// A resumed build continues in the previous attempt's tree. Packages
|
||||
// whose debian/rules keeps an input-untracked stamp cache (quirk:
|
||||
// `resume_clear`, e.g. the kernels' `debian/stamps`, whose flavour
|
||||
// config rule exports .config with no config prerequisite) would build
|
||||
// from the previous attempt's configuration: drop the listed caches so
|
||||
// the wrapper steps re-run over the incremental inner builds.
|
||||
if resume {
|
||||
// A build resuming over a carried upperdir continues in the previous
|
||||
// attempt's tree. Packages whose `debian/rules` keeps an
|
||||
// input-untracked stamp cache (quirk: `resume_clear`, e.g. the
|
||||
// kernels' `debian/stamps`, whose flavour config rule exports .config
|
||||
// with no config prerequisite) would build from the previous
|
||||
// attempt's configuration: drop the listed caches so the wrapper
|
||||
// steps re-run over the incremental inner builds.
|
||||
if build_resume {
|
||||
for rel in crate::quirks::get_resume_clear_paths(package, series) {
|
||||
let path = Path::new(package_dir_str).join(&rel);
|
||||
if !ctx.exists(&path).unwrap_or(false) {
|
||||
@@ -383,10 +351,10 @@ pub async fn build(
|
||||
s.record_phase("build", None);
|
||||
}
|
||||
|
||||
// On a resumed session the previous attempt's debian/files would make
|
||||
// On a resumed build the previous attempt's debian/files would make
|
||||
// the artifact collection below surface its outputs: only the new
|
||||
// attempt's registration may remain.
|
||||
if resume {
|
||||
if build_resume {
|
||||
let _ = ctx
|
||||
.command("rm")
|
||||
.arg("-f")
|
||||
|
||||
Reference in New Issue
Block a user