feat: Implement build state tracking and interactive package specification creation

- Added StateTracker to manage build steps and allow resuming interrupted builds.
- Updated post_extract function to utilize StateTracker for patch and command execution.
- Introduced makefile.rs to handle building and installing packages via Makefile.
- Created interactive.rs for an interactive package specification creator with SHA256 computation for source URLs.
- Enhanced checksum verification to support multiple algorithms (SHA256, SHA512, MD5).
- Added example configuration files in contrib for system-wide and user-level Depot configurations.
- Updated tests to cover new functionality and ensure correctness of state tracking and interactive creation.
This commit is contained in:
2026-02-16 21:38:05 -06:00
parent 00ca2ebac6
commit 9a00608104
30 changed files with 3501 additions and 434 deletions
+94 -53
View File
@@ -54,12 +54,20 @@ pub fn build(
}
env_vars.push(("CC", cc));
// Export rootfs for build scripts
env_vars.push(("DEPOT_ROOTFS", flags.rootfs.clone()));
// Add cross-compilation env
if let Some(cc_cfg) = cross {
env_vars.push(("CXX", cc_cfg.cxx.clone()));
env_vars.push(("AR", cc_cfg.ar.clone()));
}
// CARCH support
if !flags.carch.is_empty() {
env_vars.push(("CARCH", flags.carch.clone()));
}
// Extract prefix from configure flags
let prefix = flags
.configure
@@ -75,65 +83,87 @@ pub fn build(
None
};
use crate::builder::state::{BuildStep, StateTracker};
let mut state = StateTracker::new(src_dir)?;
// Run meson setup
println!("Running meson setup...");
let mut meson_cmd = Command::new("meson");
meson_cmd.current_dir(src_dir);
meson_cmd.arg("setup");
meson_cmd.arg(&build_dir);
meson_cmd.arg(format!("--prefix={}", prefix));
meson_cmd.arg("--buildtype=release");
if !state.is_done(BuildStep::Configured) {
println!("Running meson setup...");
let mut meson_cmd = Command::new("meson");
meson_cmd.current_dir(src_dir);
meson_cmd.arg("setup");
meson_cmd.arg(&build_dir);
meson_cmd.arg(format!("--prefix={}", prefix));
meson_cmd.arg("--buildtype=release");
// Add cross file for cross-compilation
if let Some(ref cf) = cross_file {
meson_cmd.arg(format!("--cross-file={}", cf.display()));
}
crate::builder::prepare_command(&mut meson_cmd, &env_vars);
let status = meson_cmd.status().context("Failed to run meson setup")?;
if !status.success() {
anyhow::bail!("meson setup failed");
}
// Run ninja build
println!("Running ninja...");
let mut ninja_cmd = Command::new("ninja");
ninja_cmd.current_dir(&build_dir);
ninja_cmd.arg("-j").arg(num_cpus().to_string());
crate::builder::prepare_command(&mut ninja_cmd, &env_vars);
let status = ninja_cmd
.status()
.with_context(|| format!("Failed to run ninja for {}", spec.package.name))?;
if !status.success() {
anyhow::bail!("ninja build failed");
}
// Run meson install with fakeroot if not root
println!(
"Running meson install{}...",
if fakeroot::is_root() {
""
} else {
" (with fakeroot)"
// Add cross file for cross-compilation
if let Some(ref cf) = cross_file {
meson_cmd.arg(format!("--cross-file={}", cf.display()));
}
);
let mut install_cmd = fakeroot::wrap_install_command("meson", destdir);
install_cmd.arg("install");
install_cmd.arg("-C").arg(&build_dir);
crate::builder::prepare_command(&mut meson_cmd, &env_vars);
let mut install_env = env_vars.clone();
install_env.push(("DESTDIR", destdir.to_string_lossy().into_owned()));
crate::builder::prepare_command(&mut install_cmd, &install_env);
let status = meson_cmd.status().context("Failed to run meson setup")?;
if !status.success() {
anyhow::bail!("meson setup failed");
}
state.mark_done(BuildStep::Configured)?;
} else {
println!("Skipping meson setup (already done)");
}
let status = install_cmd
.status()
.with_context(|| format!("Failed to run meson install for {}", spec.package.name))?;
if !status.success() {
anyhow::bail!("meson install failed");
if !state.is_done(BuildStep::PostCompileDone) {
// Run ninja build
println!("Running ninja...");
let mut ninja_cmd = Command::new("ninja");
ninja_cmd.current_dir(&build_dir);
ninja_cmd.arg("-j").arg(num_cpus().to_string());
crate::builder::prepare_command(&mut ninja_cmd, &env_vars);
let status = ninja_cmd
.status()
.with_context(|| format!("Failed to run ninja for {}", spec.package.name))?;
if !status.success() {
anyhow::bail!("ninja build failed");
}
crate::source::hooks::run_post_compile_commands(spec, src_dir, destdir)?;
state.mark_done(BuildStep::PostCompileDone)?;
} else {
println!("Skipping ninja build and post-compile hooks (already done)");
}
if !state.is_done(BuildStep::PostInstallDone) {
// Run meson install with fakeroot if not root
println!(
"Running meson install{}...",
if fakeroot::is_root() {
""
} else {
" (with fakeroot)"
}
);
let mut install_cmd = fakeroot::wrap_install_command("meson", destdir);
install_cmd.arg("install");
install_cmd.arg("-C").arg(&build_dir);
let mut install_env = env_vars.clone();
install_env.push(("DESTDIR", destdir.to_string_lossy().into_owned()));
crate::builder::prepare_command(&mut install_cmd, &install_env);
let status = install_cmd
.status()
.with_context(|| format!("Failed to run meson install for {}", spec.package.name))?;
if !status.success() {
anyhow::bail!("meson install failed");
}
crate::source::hooks::run_post_install_commands(spec, src_dir, destdir)?;
state.mark_done(BuildStep::PostInstallDone)?;
} else {
println!("Skipping meson install and post-install hooks (already done)");
}
Ok(())
@@ -144,3 +174,14 @@ fn num_cpus() -> usize {
.map(|n| n.get())
.unwrap_or(1)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_num_cpus_at_least_one() {
let n = num_cpus();
assert!(n >= 1);
}
}