feat: add support for delegating live root filesystem installations to child processes

This commit is contained in:
2026-03-09 00:45:33 -05:00
parent e984ee282f
commit b50745a67a
+99
View File
@@ -29,6 +29,10 @@ fn should_reexec_with_sudo(cli: &Cli) -> bool {
&& command_requires_live_root(&cli.command)
}
fn should_delegate_live_rootfs_installs(rootfs: &Path) -> bool {
!crate::fakeroot::is_root() && rootfs_is_system_root(rootfs)
}
fn maybe_reexec_with_sudo(cli: &Cli) -> Result<bool> {
if !should_reexec_with_sudo(cli) {
return Ok(false);
@@ -49,6 +53,44 @@ fn maybe_reexec_with_sudo(cli: &Cli) -> Result<bool> {
}
}
fn run_child_install_command(
install_request: &Path,
rootfs: &Path,
options: InstallPlanExecutionOptions<'_>,
) -> Result<()> {
let exe = std::env::current_exe().context("Failed to locate depot executable")?;
let mut cmd = std::process::Command::new(&exe);
cmd.arg("-r").arg(rootfs);
cmd.arg("--no-deps");
cmd.arg("--yes");
if options.no_flags {
cmd.arg("--no-flags");
}
if let Some(p) = options.cross_prefix {
cmd.arg("--cross-prefix").arg(p);
}
if options.clean {
cmd.arg("--clean");
}
cmd.arg("install").arg(install_request);
let status = cmd.status().with_context(|| {
format!(
"Failed to spawn child install for {}",
install_request.display()
)
})?;
if status.success() {
Ok(())
} else {
anyhow::bail!(
"Child install failed for {} with status {}",
install_request.display(),
status
);
}
}
fn parse_licenses_from_toml(metadata: &toml::Value) -> Vec<String> {
if let Some(s) = metadata.get("license").and_then(|v| v.as_str()) {
return vec![s.to_string()];
@@ -1112,6 +1154,7 @@ fn print_plan_summary(plan: &planner::ExecutionPlan) {
}
}
#[derive(Clone, Copy)]
struct InstallPlanExecutionOptions<'a> {
no_flags: bool,
cross_prefix: Option<&'a str>,
@@ -1160,6 +1203,31 @@ fn execute_install_plan_with_child_commands(
return Ok(());
}
if should_delegate_live_rootfs_installs(rootfs) {
for step in actionable_steps {
match &step.origin {
planner::PlanOrigin::Source { path, .. } => {
run_child_install_command(path, rootfs, options)?;
}
planner::PlanOrigin::Binary { repo_name, record } => {
let repo_cfg = config.binary_repos.get(repo_name).with_context(|| {
format!("Binary repo '{}' not found in config", repo_name)
})?;
let archive_path = db::repo::fetch_binary_package_archive(
repo_name,
repo_cfg,
rootfs,
record,
&config.package_cache_dir,
)?;
run_child_install_command(&archive_path, rootfs, options)?;
}
planner::PlanOrigin::Installed => {}
}
}
return Ok(());
}
let mut binary_phase_items = Vec::new();
for step in &actionable_steps {
if let planner::PlanOrigin::Binary { repo_name, record } = &step.origin {
@@ -2090,6 +2158,26 @@ pub fn run(cli: Cli) -> Result<()> {
));
}
if ui::prompt_package_action("installation", &install_targets, false)? {
if should_delegate_live_rootfs_installs(&cli.rootfs) {
for archive in &created_files {
run_child_install_command(
archive,
&cli.rootfs,
InstallPlanExecutionOptions {
no_flags: cli.no_flags,
cross_prefix: cli.cross_prefix.as_deref(),
clean: cli.clean,
dry_run: cli.dry_run,
confirm_installation: false,
},
)?;
}
if cli.clean {
clean_build_workspace(&config)?;
}
return Ok(());
}
let mut transaction_plans = Vec::new();
if !cli.lib32_only {
let output_plans =
@@ -2842,4 +2930,15 @@ mod tests {
files: false,
}));
}
#[test]
fn should_delegate_live_rootfs_installs_only_for_live_root_when_non_root() {
assert_eq!(
should_delegate_live_rootfs_installs(Path::new("/")),
!crate::fakeroot::is_root()
);
assert!(!should_delegate_live_rootfs_installs(Path::new(
"/tmp/depot-test-rootfs"
)));
}
}