deb,report,ui: report the staged-tree copy while a record forks
Forking an incremental base copies its whole staged tree — bounded, and without reflinks a matter of minutes — but the copy emitted no build events: the live view showed the target line with nothing below it, and an interrupt there printed raw cp errors with no hint of what was running (the fork happens before the first bootstrap phase owns the view). Announce the copy through a new BuildView::byte_progress port. The fork sizes the source up front (the copy's total), re-measures the growing destination from a scoped thread while cp runs (cp has no progress output to tap), and reports the completed copy when it returns; unmeasurable or empty sources copy unreported. The terminal view renders it like the other determinate bars, with byte-unit counters.
This commit is contained in:
+47
-1
@@ -296,6 +296,10 @@ impl BuildView for RecordLogView<'_> {
|
||||
self.inner.progress(label, pos, total);
|
||||
}
|
||||
|
||||
fn byte_progress(&self, label: &str, pos: u64, total: u64) {
|
||||
self.inner.byte_progress(label, pos, total);
|
||||
}
|
||||
|
||||
fn sink(&self) -> Option<Arc<dyn crate::context::LineSink>> {
|
||||
Some(self.log.clone())
|
||||
}
|
||||
@@ -506,6 +510,7 @@ async fn build_binary_package_impl(
|
||||
series,
|
||||
chroot_arch,
|
||||
mirror.as_deref(),
|
||||
view,
|
||||
) {
|
||||
Ok((record, keep)) => {
|
||||
keep_upper = keep;
|
||||
@@ -795,9 +800,32 @@ async fn build_binary_package_impl(
|
||||
result
|
||||
}
|
||||
|
||||
/// The staged-tree copy of a fork is bounded (the base's whole tree)
|
||||
/// and, without reflinks, takes minutes: announce it on the view, then
|
||||
/// feed byte progress once the fork's watcher has measured the total.
|
||||
/// Callers hand [`session::CopyProgress`] the box through `as_deref()`.
|
||||
fn copy_report<'a>(
|
||||
view: Option<&'a dyn BuildView>,
|
||||
base_id: &str,
|
||||
) -> Option<Box<dyn Fn(u64, u64) + Sync + 'a>> {
|
||||
view.map(|view| {
|
||||
let label = format!("Copying the staged tree of record {base_id}");
|
||||
view.message(&label);
|
||||
Box::new(move |pos: u64, total: u64| {
|
||||
let size = crate::utils::size::format_bytes;
|
||||
view.byte_progress(
|
||||
&format!("{label} ({}/{})", size(pos), size(total)),
|
||||
pos,
|
||||
total,
|
||||
)
|
||||
}) as Box<dyn Fn(u64, u64) + Sync + 'a>
|
||||
})
|
||||
}
|
||||
|
||||
/// Resolve the record a build runs in, per the `--incremental` request,
|
||||
/// against the real sessions root and the chroot tarball the bootstrap
|
||||
/// would use today. See [`resolve_record_in`].
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn resolve_record(
|
||||
incremental: &Incremental,
|
||||
host_tree: &Path,
|
||||
@@ -806,6 +834,7 @@ fn resolve_record(
|
||||
series: &str,
|
||||
chroot_arch: Option<&str>,
|
||||
mirror: Option<&str>,
|
||||
view: &dyn BuildView,
|
||||
) -> Result<(session::Session, bool), Box<dyn Error>> {
|
||||
resolve_record_in(
|
||||
&session::sessions_root(),
|
||||
@@ -814,11 +843,14 @@ fn resolve_record(
|
||||
host_tree,
|
||||
identity,
|
||||
version,
|
||||
Some(view),
|
||||
)
|
||||
}
|
||||
|
||||
/// The testable core of [`resolve_record`] over an explicit sessions root
|
||||
/// and cached-tarball digest (the fork gate's reference).
|
||||
/// and cached-tarball digest (the fork gate's reference). `view` is the
|
||||
/// live build view when there is one; the fork reports its staged-tree
|
||||
/// copy through it.
|
||||
///
|
||||
/// Every local build runs in its own record: [`Incremental::Off`] gets a
|
||||
/// brand-new one, [`Incremental::Auto`] and [`Incremental::Id`] fork the
|
||||
@@ -833,6 +865,7 @@ fn resolve_record_in(
|
||||
host_tree: &Path,
|
||||
identity: &session::SessionIdentity,
|
||||
version: &str,
|
||||
view: Option<&dyn BuildView>,
|
||||
) -> Result<(session::Session, bool), Box<dyn Error>> {
|
||||
match incremental {
|
||||
Incremental::Off => Ok((
|
||||
@@ -854,6 +887,7 @@ fn resolve_record_in(
|
||||
} else {
|
||||
"no successful record among the last usable ones; the newest record"
|
||||
};
|
||||
let report = copy_report(view, &base.manifest().id);
|
||||
match session::fork_record_in(
|
||||
records_root,
|
||||
&base,
|
||||
@@ -861,6 +895,7 @@ fn resolve_record_in(
|
||||
identity,
|
||||
version,
|
||||
cache_tarball_sha256,
|
||||
report.as_deref(),
|
||||
) {
|
||||
Ok(record) => {
|
||||
log::info!(
|
||||
@@ -901,6 +936,7 @@ fn resolve_record_in(
|
||||
"Base of the incremental build: record {} (pinned by id)",
|
||||
base.manifest().id
|
||||
);
|
||||
let report = copy_report(view, &base.manifest().id);
|
||||
Ok((
|
||||
session::fork_record_in(
|
||||
records_root,
|
||||
@@ -909,6 +945,7 @@ fn resolve_record_in(
|
||||
identity,
|
||||
version,
|
||||
cache_tarball_sha256,
|
||||
report.as_deref(),
|
||||
)?,
|
||||
true,
|
||||
))
|
||||
@@ -1767,6 +1804,7 @@ mod tests {
|
||||
&host_tree,
|
||||
&identity,
|
||||
"1.0",
|
||||
None,
|
||||
)
|
||||
.expect("a plain run always resolves to a fresh record");
|
||||
assert!(!keep_upper, "a plain run drops its staged tree");
|
||||
@@ -1798,6 +1836,7 @@ mod tests {
|
||||
&identity,
|
||||
"1.0",
|
||||
&cache_sha(&tarball),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let b_id = b.manifest().id;
|
||||
@@ -1811,6 +1850,7 @@ mod tests {
|
||||
&host_tree,
|
||||
&identity,
|
||||
"1.0",
|
||||
None,
|
||||
)
|
||||
.expect("the auto selection must fork a candidate record");
|
||||
assert!(keep_upper);
|
||||
@@ -1836,6 +1876,7 @@ mod tests {
|
||||
&host_tree,
|
||||
&identity,
|
||||
"1.0",
|
||||
None,
|
||||
)
|
||||
.expect("no candidates must degrade to a fresh build");
|
||||
assert!(keep_upper, "the first record becomes a base");
|
||||
@@ -1877,6 +1918,7 @@ mod tests {
|
||||
&host_tree,
|
||||
&identity,
|
||||
"1.0",
|
||||
None,
|
||||
)
|
||||
.expect("the record carrying a staged tree is still the base");
|
||||
assert_eq!(record.manifest().base.as_deref(), Some(carrier_id.as_str()));
|
||||
@@ -1907,6 +1949,7 @@ mod tests {
|
||||
&host_tree,
|
||||
&identity,
|
||||
"1.0",
|
||||
None,
|
||||
)
|
||||
.expect("a pinned failed record is a valid base");
|
||||
assert!(keep_upper);
|
||||
@@ -1940,6 +1983,7 @@ mod tests {
|
||||
&host_tree,
|
||||
&identity,
|
||||
"1.0",
|
||||
None,
|
||||
)
|
||||
.expect_err("records of other trees must not be forked by id");
|
||||
assert!(
|
||||
@@ -1981,6 +2025,7 @@ mod tests {
|
||||
&host_tree,
|
||||
&identity,
|
||||
"1.0",
|
||||
None,
|
||||
)
|
||||
.expect_err("an ambiguous prefix must be refused");
|
||||
assert!(
|
||||
@@ -2029,6 +2074,7 @@ mod tests {
|
||||
&host_tree,
|
||||
&identity,
|
||||
"1.0",
|
||||
None,
|
||||
)
|
||||
.expect_err("a foreign-identity record must not be forked");
|
||||
assert!(
|
||||
|
||||
Reference in New Issue
Block a user