deb: change ui/ux of pkh deb
This commit is contained in:
+125
-40
@@ -3,6 +3,7 @@ mod ephemeral;
|
||||
mod local;
|
||||
|
||||
use crate::context::{self, Context};
|
||||
use crate::ui::deb::{DebUi, Phase};
|
||||
use std::error::Error;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
@@ -15,6 +16,11 @@ pub enum BuildMode {
|
||||
}
|
||||
|
||||
/// Build package in 'cwd' to a .deb
|
||||
///
|
||||
/// Returns the list of produced .deb files retrieved locally. When `ui` is
|
||||
/// set, a live view (status bar + rolling log pane) is displayed and all
|
||||
/// subprocess output is captured through it; on failure the widget is cleared
|
||||
/// and a summary of captured errors is printed.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn build_binary_package(
|
||||
arch: Option<&str>,
|
||||
@@ -26,7 +32,43 @@ pub async fn build_binary_package(
|
||||
ppa: Option<&[&str]>,
|
||||
inject_packages: Option<&[&str]>,
|
||||
ctx: Option<Arc<Context>>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
ui: Option<Arc<DebUi>>,
|
||||
) -> Result<Vec<PathBuf>, Box<dyn Error>> {
|
||||
let result = build_binary_package_impl(
|
||||
arch,
|
||||
series,
|
||||
pocket,
|
||||
cwd,
|
||||
cross,
|
||||
mode,
|
||||
ppa,
|
||||
inject_packages,
|
||||
ctx,
|
||||
&ui,
|
||||
)
|
||||
.await;
|
||||
|
||||
if let (Some(u), Err(_)) = (&ui, &result) {
|
||||
u.finish_failure();
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
/// Implementation of [`build_binary_package`], without failure handling
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn build_binary_package_impl(
|
||||
arch: Option<&str>,
|
||||
series: Option<&str>,
|
||||
pocket: Option<&str>,
|
||||
cwd: Option<&Path>,
|
||||
cross: bool,
|
||||
mode: Option<BuildMode>,
|
||||
ppa: Option<&[&str]>,
|
||||
inject_packages: Option<&[&str]>,
|
||||
ctx: Option<Arc<Context>>,
|
||||
ui: &Option<Arc<DebUi>>,
|
||||
) -> Result<Vec<PathBuf>, Box<dyn Error>> {
|
||||
let cwd = cwd.unwrap_or_else(|| Path::new("."));
|
||||
|
||||
// Parse changelog to get package name, version and series
|
||||
@@ -61,12 +103,22 @@ pub async fn build_binary_package(
|
||||
// Use provided context or get current
|
||||
let base_ctx = ctx.unwrap_or_else(context::current);
|
||||
|
||||
// Identify the target in the live UI once the changelog is parsed, so
|
||||
// even the chroot download output is attributed and tee'd
|
||||
if let Some(u) = ui {
|
||||
u.set_target(&package, &version, series, arch);
|
||||
}
|
||||
|
||||
// Create an ephemeral unshare context for all Local builds. It is kept in
|
||||
// this scope so it outlives the guarded section below and is only dropped
|
||||
// once the live view has been cleared.
|
||||
let mut guard = if mode == BuildMode::Local {
|
||||
Some(
|
||||
ephemeral::EphemeralContextGuard::new_with_context(
|
||||
series,
|
||||
chroot_arch,
|
||||
base_ctx.clone(),
|
||||
ui.clone(),
|
||||
)
|
||||
.await?,
|
||||
)
|
||||
@@ -74,59 +126,91 @@ pub async fn build_binary_package(
|
||||
None
|
||||
};
|
||||
|
||||
// Get the build context - either the ephemeral context or the base context
|
||||
let build_ctx = if mode == BuildMode::Local {
|
||||
context::current()
|
||||
} else {
|
||||
base_ctx.clone()
|
||||
};
|
||||
let result = async {
|
||||
// Get the build context - either the ephemeral context or the base context
|
||||
let build_ctx = if mode == BuildMode::Local {
|
||||
context::current()
|
||||
} else {
|
||||
base_ctx.clone()
|
||||
};
|
||||
|
||||
// Prepare build directory
|
||||
let build_root = build_ctx.create_temp_dir()?;
|
||||
// Prepare build directory
|
||||
let build_root = build_ctx.create_temp_dir()?;
|
||||
|
||||
// Ensure availability of all needed files for the build
|
||||
let parent_dir = cwd.parent().ok_or("Cannot find parent directory")?;
|
||||
build_ctx.ensure_available(parent_dir, &build_root)?;
|
||||
let parent_dir_name = parent_dir
|
||||
.file_name()
|
||||
.ok_or("Cannot find parent directory name")?;
|
||||
let build_root = format!("{}/{}", build_root, parent_dir_name.to_str().unwrap());
|
||||
// Ensure availability of all needed files for the build
|
||||
let parent_dir = cwd.parent().ok_or("Cannot find parent directory")?;
|
||||
build_ctx.ensure_available(parent_dir, &build_root)?;
|
||||
let parent_dir_name = parent_dir
|
||||
.file_name()
|
||||
.ok_or("Cannot find parent directory name")?;
|
||||
let build_root = format!("{}/{}", build_root, parent_dir_name.to_str().unwrap());
|
||||
|
||||
// Run the build using target build mode
|
||||
match mode {
|
||||
BuildMode::Local => {
|
||||
local::build(
|
||||
&package,
|
||||
&version,
|
||||
arch,
|
||||
series,
|
||||
pocket,
|
||||
&build_root,
|
||||
cross,
|
||||
ppa,
|
||||
inject_packages,
|
||||
build_ctx.clone(),
|
||||
)
|
||||
.await?
|
||||
// Run the build using target build mode
|
||||
match mode {
|
||||
BuildMode::Local => {
|
||||
local::build(
|
||||
&package,
|
||||
&version,
|
||||
arch,
|
||||
series,
|
||||
pocket,
|
||||
&build_root,
|
||||
cross,
|
||||
ppa,
|
||||
inject_packages,
|
||||
build_ctx.clone(),
|
||||
ui.clone(),
|
||||
)
|
||||
.await?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve produced .deb files
|
||||
let remote_files = build_ctx.list_files(Path::new(&build_root))?;
|
||||
for remote_file in remote_files {
|
||||
if remote_file.extension().is_some_and(|ext| ext == "deb") {
|
||||
// Retrieve produced .deb files
|
||||
if let Some(u) = ui {
|
||||
u.phase(Phase::RetrievingArtifacts);
|
||||
}
|
||||
let remote_files = build_ctx.list_files(Path::new(&build_root))?;
|
||||
let deb_files: Vec<PathBuf> = remote_files
|
||||
.into_iter()
|
||||
.filter(|f| f.extension().is_some_and(|ext| ext == "deb"))
|
||||
.collect();
|
||||
let total_debs = deb_files.len();
|
||||
|
||||
let mut artifacts = Vec::with_capacity(total_debs);
|
||||
for (idx, remote_file) in deb_files.iter().enumerate() {
|
||||
let file_name = remote_file.file_name().ok_or("Invalid remote filename")?;
|
||||
let local_dest = parent_dir.join(file_name);
|
||||
build_ctx.retrieve_path(&remote_file, &local_dest)?;
|
||||
build_ctx.retrieve_path(remote_file, &local_dest)?;
|
||||
artifacts.push(local_dest);
|
||||
|
||||
if let Some(u) = ui {
|
||||
u.count_progress("Retrieving artifacts", idx + 1, total_debs);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(u) = ui {
|
||||
u.finish_success(&artifacts, u.elapsed());
|
||||
}
|
||||
|
||||
Ok(artifacts)
|
||||
}
|
||||
.await;
|
||||
|
||||
// Clear the live view before returning: the ephemeral guard is dropped at
|
||||
// the end of this function and its cleanup commands (umount, rm -rf of
|
||||
// the chroot) inherit the terminal, so they must not fight the widget.
|
||||
if let Some(u) = ui {
|
||||
u.suspend();
|
||||
}
|
||||
|
||||
// Mark build as successful to trigger chroot cleanup
|
||||
if let Some(ref mut g) = guard {
|
||||
if result.is_ok()
|
||||
&& let Some(ref mut g) = guard
|
||||
{
|
||||
g.mark_build_successful();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
result
|
||||
}
|
||||
|
||||
/// Find the current package directory by trying both patterns:
|
||||
@@ -321,6 +405,7 @@ mod tests {
|
||||
None,
|
||||
None,
|
||||
Some(ctx),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.expect("Cannot build binary package (deb)");
|
||||
|
||||
Reference in New Issue
Block a user