feat: add support for delegating live root filesystem installations to child processes
This commit is contained in:
@@ -29,6 +29,10 @@ fn should_reexec_with_sudo(cli: &Cli) -> bool {
|
|||||||
&& command_requires_live_root(&cli.command)
|
&& 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> {
|
fn maybe_reexec_with_sudo(cli: &Cli) -> Result<bool> {
|
||||||
if !should_reexec_with_sudo(cli) {
|
if !should_reexec_with_sudo(cli) {
|
||||||
return Ok(false);
|
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> {
|
fn parse_licenses_from_toml(metadata: &toml::Value) -> Vec<String> {
|
||||||
if let Some(s) = metadata.get("license").and_then(|v| v.as_str()) {
|
if let Some(s) = metadata.get("license").and_then(|v| v.as_str()) {
|
||||||
return vec![s.to_string()];
|
return vec![s.to_string()];
|
||||||
@@ -1112,6 +1154,7 @@ fn print_plan_summary(plan: &planner::ExecutionPlan) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
struct InstallPlanExecutionOptions<'a> {
|
struct InstallPlanExecutionOptions<'a> {
|
||||||
no_flags: bool,
|
no_flags: bool,
|
||||||
cross_prefix: Option<&'a str>,
|
cross_prefix: Option<&'a str>,
|
||||||
@@ -1160,6 +1203,31 @@ fn execute_install_plan_with_child_commands(
|
|||||||
return Ok(());
|
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();
|
let mut binary_phase_items = Vec::new();
|
||||||
for step in &actionable_steps {
|
for step in &actionable_steps {
|
||||||
if let planner::PlanOrigin::Binary { repo_name, record } = &step.origin {
|
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 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();
|
let mut transaction_plans = Vec::new();
|
||||||
if !cli.lib32_only {
|
if !cli.lib32_only {
|
||||||
let output_plans =
|
let output_plans =
|
||||||
@@ -2842,4 +2930,15 @@ mod tests {
|
|||||||
files: false,
|
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"
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user