deb,cli,test,docs: record and show dep-install and build durations
Every binary build measures its dependency installation (apt-get
update, the essential and injected packages, each build-dependency
pass) and its package build (debian/rules build plus binary) into a
timings accumulator; the record manifest stores both as an optional
`timings` field when the run ends, whatever the outcome — a failed
build keeps its partial durations, and a run that died before any
timed command records nothing.
`pkh deb list` shows the two durations as DEPS and BUILD columns,
formatted like the age ("45s", "2m41s", "1h02m"); records predating
the field show dashes. The field is serde-optional, so the manifest
schema stays at 1 and existing records remain discoverable and
forkable.
This commit is contained in:
+20
-1
@@ -15,6 +15,7 @@ use crate::deb::cross;
|
||||
use crate::deb::session;
|
||||
use crate::debian::control::ControlInfo;
|
||||
use crate::debian::deps::{Deps, Facts, ParseOpts, PkgRelation};
|
||||
use std::time::Instant;
|
||||
|
||||
/// Attach the capture sink to a command when the live UI is active
|
||||
fn cap<'a>(
|
||||
@@ -106,6 +107,9 @@ pub async fn build(
|
||||
session: Option<&session::Session>,
|
||||
build_resume: bool,
|
||||
ccache: bool,
|
||||
// Accumulator of the measured dependency-installation and build
|
||||
// durations; the caller records it on the build record.
|
||||
timings: &mut session::BuildTimings,
|
||||
) -> Result<Vec<PathBuf>, Box<dyn Error>> {
|
||||
let sink: Option<Arc<dyn LineSink>> = view.sink();
|
||||
|
||||
@@ -261,6 +265,7 @@ pub async fn build(
|
||||
// Update package lists
|
||||
log::debug!("Updating package lists for local build...");
|
||||
enter_phase(view, Phase::UpdatingPackageLists);
|
||||
let started = Instant::now();
|
||||
let status = cap(
|
||||
ctx.command("apt-get").envs(env.clone()).arg("update"),
|
||||
&sink,
|
||||
@@ -274,6 +279,7 @@ pub async fn build(
|
||||
e
|
||||
)
|
||||
})?;
|
||||
timings.add_deps(started.elapsed());
|
||||
if !status.success() {
|
||||
return Err("apt-get update failed inside the build context. \
|
||||
If this is a local build, try executing with sudo, \
|
||||
@@ -305,7 +311,9 @@ pub async fn build(
|
||||
cmd.arg(format!("libc6-dev:{arch}"));
|
||||
}
|
||||
enter_phase(view, Phase::InstallingEssentials);
|
||||
let started = Instant::now();
|
||||
let status = cap(&mut cmd, &sink).status()?;
|
||||
timings.add_deps(started.elapsed());
|
||||
if !status.success() {
|
||||
return Err("Could not install essential packages for the build".into());
|
||||
}
|
||||
@@ -348,7 +356,7 @@ pub async fn build(
|
||||
|
||||
// Install injected packages if specified
|
||||
if !inject_packages.is_empty() {
|
||||
install_injected_packages(inject_packages, &env, ctx.clone(), view, &sink)?;
|
||||
install_injected_packages(inject_packages, &env, ctx.clone(), view, &sink, timings)?;
|
||||
}
|
||||
|
||||
// Resolve and install the Build-* dependencies with dpkg's cross
|
||||
@@ -367,6 +375,7 @@ pub async fn build(
|
||||
ctx.clone(),
|
||||
view,
|
||||
&sink,
|
||||
timings,
|
||||
)?;
|
||||
// (The build-dependency phase reruns in every fresh chroot: nothing
|
||||
// to journal.)
|
||||
@@ -400,6 +409,7 @@ pub async fn build(
|
||||
// Run the build step
|
||||
log::debug!("Building (debian/rules build) package...");
|
||||
enter_phase(view, Phase::Building);
|
||||
let started = Instant::now();
|
||||
let status = cap(
|
||||
ctx.command("debian/rules")
|
||||
.current_dir(package_dir_str)
|
||||
@@ -408,6 +418,7 @@ pub async fn build(
|
||||
&sink,
|
||||
)
|
||||
.status()?;
|
||||
timings.add_build(started.elapsed());
|
||||
if !status.success() {
|
||||
return Err("Error while building the package".into());
|
||||
}
|
||||
@@ -428,6 +439,7 @@ pub async fn build(
|
||||
|
||||
// Run the 'binary' step to produce deb
|
||||
enter_phase(view, Phase::ProducingBinaries);
|
||||
let started = Instant::now();
|
||||
let status = cap(
|
||||
ctx.command("fakeroot")
|
||||
.current_dir(package_dir_str)
|
||||
@@ -437,6 +449,7 @@ pub async fn build(
|
||||
&sink,
|
||||
)
|
||||
.status()?;
|
||||
timings.add_build(started.elapsed());
|
||||
if !status.success() {
|
||||
return Err(
|
||||
"Error while building the binary artifacts (.deb) from the built package".into(),
|
||||
@@ -730,6 +743,7 @@ fn install_build_dependencies(
|
||||
ctx: Arc<Context>,
|
||||
view: &dyn BuildView,
|
||||
sink: &Option<Arc<dyn LineSink>>,
|
||||
timings: &mut session::BuildTimings,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
enter_phase(view, Phase::InstallingBuildDeps);
|
||||
|
||||
@@ -878,7 +892,9 @@ fn install_build_dependencies(
|
||||
for spec in &specs {
|
||||
cmd.arg(spec);
|
||||
}
|
||||
let started = Instant::now();
|
||||
let status = cap(&mut cmd, sink).status()?;
|
||||
timings.add_deps(started.elapsed());
|
||||
if !status.success() {
|
||||
view.suspend();
|
||||
// Diagnosing a dependency failure the user interrupted themselves
|
||||
@@ -1210,6 +1226,7 @@ pub(crate) fn install_injected_packages(
|
||||
ctx: Arc<Context>,
|
||||
view: &dyn BuildView,
|
||||
sink: &Option<Arc<dyn LineSink>>,
|
||||
timings: &mut session::BuildTimings,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
log::info!("Installing injected packages: {:?}", packages);
|
||||
|
||||
@@ -1252,7 +1269,9 @@ pub(crate) fn install_injected_packages(
|
||||
if !package_names.is_empty() {
|
||||
cmd.args(&package_names);
|
||||
}
|
||||
let started = Instant::now();
|
||||
let status = cap(&mut cmd, sink).status()?;
|
||||
timings.add_deps(started.elapsed());
|
||||
if !status.success() {
|
||||
return Err(format!("Could not install injected packages: {:?}", deb_files).into());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user