feat: update depot version to 0.17.1 and enhance command execution with improved error handling and environment variable management
This commit is contained in:
Generated
+1
-1
@@ -418,7 +418,7 @@ checksum = "807800ff3288b621186fe0a8f3392c4652068257302709c24efd918c3dffcdc2"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "depot"
|
name = "depot"
|
||||||
version = "0.17.0"
|
version = "0.17.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"ar",
|
"ar",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "depot"
|
name = "depot"
|
||||||
version = "0.17.0"
|
version = "0.17.1"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[lints.rust]
|
[lints.rust]
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'depot',
|
'depot',
|
||||||
version: '0.17.0',
|
version: '0.17.1',
|
||||||
meson_version: '>=0.60.0',
|
meson_version: '>=0.60.0',
|
||||||
default_options: ['buildtype=release'],
|
default_options: ['buildtype=release'],
|
||||||
)
|
)
|
||||||
|
|||||||
+298
-30
@@ -165,7 +165,10 @@ fn command_status_with_sh_fallback(
|
|||||||
) -> std::io::Result<std::process::ExitStatus> {
|
) -> std::io::Result<std::process::ExitStatus> {
|
||||||
match cmd.status() {
|
match cmd.status() {
|
||||||
Ok(status) => Ok(status),
|
Ok(status) => Ok(status),
|
||||||
Err(err) if err.kind() == std::io::ErrorKind::PermissionDenied => {
|
Err(err)
|
||||||
|
if err.kind() == std::io::ErrorKind::PermissionDenied
|
||||||
|
|| err.raw_os_error() == Some(26) =>
|
||||||
|
{
|
||||||
let program = cmd.get_program();
|
let program = cmd.get_program();
|
||||||
let contents = fs::read(program);
|
let contents = fs::read(program);
|
||||||
let is_script = contents.ok().is_some_and(|bytes| bytes.starts_with(b"#!"));
|
let is_script = contents.ok().is_some_and(|bytes| bytes.starts_with(b"#!"));
|
||||||
@@ -261,7 +264,43 @@ fn parse_keep_list(metadata: &toml::Value) -> Vec<String> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn current_process_env_vars() -> Vec<(String, String)> {
|
fn current_process_env_vars() -> Vec<(String, String)> {
|
||||||
std::env::vars().collect()
|
const ALLOWED_ENV_VARS: &[&str] = &[
|
||||||
|
"AR",
|
||||||
|
"CARCH",
|
||||||
|
"CBUILD",
|
||||||
|
"CC",
|
||||||
|
"CHOST",
|
||||||
|
"CPP",
|
||||||
|
"CROSS_COMPILE",
|
||||||
|
"CROSS_PREFIX",
|
||||||
|
"CFLAGS",
|
||||||
|
"CXX",
|
||||||
|
"CXXFLAGS",
|
||||||
|
"DEPOT_ROOTFS",
|
||||||
|
"DEPOT_SPECDIR",
|
||||||
|
"DESTDIR",
|
||||||
|
"LD",
|
||||||
|
"LDFLAGS",
|
||||||
|
"LTOFLAGS",
|
||||||
|
"MAKEFLAGS",
|
||||||
|
"NM",
|
||||||
|
"PREFIX",
|
||||||
|
"PYTHONDONTWRITEBYTECODE",
|
||||||
|
"PYTHONNOUSERSITE",
|
||||||
|
"RANLIB",
|
||||||
|
"RUSTFLAGS",
|
||||||
|
"SETUPTOOLS_USE_DISTUTILS",
|
||||||
|
"STRIP",
|
||||||
|
];
|
||||||
|
|
||||||
|
ALLOWED_ENV_VARS
|
||||||
|
.iter()
|
||||||
|
.filter_map(|key| {
|
||||||
|
std::env::var(key)
|
||||||
|
.ok()
|
||||||
|
.map(|value| ((*key).to_string(), value))
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_internal_command(command: InternalCommands) -> Result<()> {
|
fn run_internal_command(command: InternalCommands) -> Result<()> {
|
||||||
@@ -594,6 +633,28 @@ fn maybe_disable_tests_for_missing_deps(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
pkg_spec: &mut package::PackageSpec,
|
||||||
|
missing_test: &[String],
|
||||||
|
reason: &str,
|
||||||
|
) -> Result<bool> {
|
||||||
|
if pkg_spec.build.flags.skip_tests
|
||||||
|
|| !build_type_runs_automatic_tests(pkg_spec)
|
||||||
|
|| missing_test.is_empty()
|
||||||
|
{
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui::warn(format!("{reason}: {}", missing_test.join(", ")));
|
||||||
|
if ui::prompt_yes_no("Continue without tests?", false)? {
|
||||||
|
pkg_spec.build.flags.skip_tests = true;
|
||||||
|
ui::warn("Tests will be skipped for this build.");
|
||||||
|
return Ok(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
|
|
||||||
fn should_install_test_deps(pkg_spec: &package::PackageSpec, install_test_deps: bool) -> bool {
|
fn should_install_test_deps(pkg_spec: &package::PackageSpec, install_test_deps: bool) -> bool {
|
||||||
install_test_deps && !pkg_spec.build.flags.skip_tests && !pkg_spec.dependencies.test.is_empty()
|
install_test_deps && !pkg_spec.build.flags.skip_tests && !pkg_spec.dependencies.test.is_empty()
|
||||||
}
|
}
|
||||||
@@ -3380,27 +3441,33 @@ fn run_direct_install_request(
|
|||||||
})?;
|
})?;
|
||||||
let db_path = config.installed_db_path(options.rootfs);
|
let db_path = config.installed_db_path(options.rootfs);
|
||||||
|
|
||||||
if staging_dir.is_none()
|
if staging_dir.is_none() {
|
||||||
&& (options.no_deps || !should_install_test_deps(&pkg_spec, options.install_test_deps))
|
if options.no_deps && should_install_test_deps(&pkg_spec, options.install_test_deps) {
|
||||||
{
|
let missing_test = deps::check_test_deps(&pkg_spec, &db_path)?;
|
||||||
maybe_disable_tests_for_missing_deps(&mut pkg_spec, &db_path)?;
|
if !missing_test.is_empty()
|
||||||
|
&& !maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut pkg_spec,
|
||||||
|
&missing_test,
|
||||||
|
"Requested test dependencies are missing",
|
||||||
|
)?
|
||||||
|
{
|
||||||
|
anyhow::bail!("Missing test dependencies: {}", missing_test.join(", "));
|
||||||
|
}
|
||||||
|
} else if options.no_deps || !should_install_test_deps(&pkg_spec, options.install_test_deps)
|
||||||
|
{
|
||||||
|
maybe_disable_tests_for_missing_deps(&mut pkg_spec, &db_path)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check dependencies and prompt for auto-install if needed
|
// Check dependencies and prompt for auto-install if needed
|
||||||
if !options.no_deps {
|
if !options.no_deps {
|
||||||
deps::print_dep_status(&pkg_spec, &db_path)?;
|
deps::print_dep_status(&pkg_spec, &db_path)?;
|
||||||
|
|
||||||
// Collect all missing dependencies (build + runtime)
|
let missing_required = merge_missing_dependencies(
|
||||||
let missing = merge_missing_dependencies(
|
|
||||||
deps::check_build_deps(&pkg_spec, &db_path)?,
|
deps::check_build_deps(&pkg_spec, &db_path)?,
|
||||||
deps::check_runtime_deps(&pkg_spec, &db_path)?,
|
deps::check_runtime_deps(&pkg_spec, &db_path)?,
|
||||||
);
|
);
|
||||||
let missing = if should_install_test_deps(&pkg_spec, options.install_test_deps) {
|
if !missing_required.is_empty() {
|
||||||
merge_missing_dependencies(missing, deps::check_test_deps(&pkg_spec, &db_path)?)
|
|
||||||
} else {
|
|
||||||
missing
|
|
||||||
};
|
|
||||||
if !missing.is_empty() {
|
|
||||||
// Check for dependency cycles via DEPOT_DEPCHAIN env var
|
// Check for dependency cycles via DEPOT_DEPCHAIN env var
|
||||||
let dep_chain = std::env::var("DEPOT_DEPCHAIN").unwrap_or_default();
|
let dep_chain = std::env::var("DEPOT_DEPCHAIN").unwrap_or_default();
|
||||||
let chain_set: std::collections::HashSet<&str> =
|
let chain_set: std::collections::HashSet<&str> =
|
||||||
@@ -3414,8 +3481,11 @@ fn run_direct_install_request(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ui::warn(format!("Missing dependencies: {}", missing.join(", ")));
|
ui::warn(format!(
|
||||||
if ui::prompt_package_action("dependency installation", &missing, true)? {
|
"Missing dependencies: {}",
|
||||||
|
missing_required.join(", ")
|
||||||
|
));
|
||||||
|
if ui::prompt_package_action("dependency installation", &missing_required, true)? {
|
||||||
// Build package index for fast lookups
|
// Build package index for fast lookups
|
||||||
let pkg_index =
|
let pkg_index =
|
||||||
index::PackageIndex::build_with_repo_dir(Some(config.repo_clone_dir.clone()));
|
index::PackageIndex::build_with_repo_dir(Some(config.repo_clone_dir.clone()));
|
||||||
@@ -3428,7 +3498,7 @@ fn run_direct_install_request(
|
|||||||
};
|
};
|
||||||
|
|
||||||
let mut dep_spec_paths = Vec::new();
|
let mut dep_spec_paths = Vec::new();
|
||||||
for dep in missing {
|
for dep in missing_required {
|
||||||
// Use package index for O(1) lookup
|
// Use package index for O(1) lookup
|
||||||
let candidate = pkg_index.find(&dep);
|
let candidate = pkg_index.find(&dep);
|
||||||
|
|
||||||
@@ -3465,7 +3535,79 @@ fn run_direct_install_request(
|
|||||||
deps::require_build_deps(&pkg_spec, &db_path)?;
|
deps::require_build_deps(&pkg_spec, &db_path)?;
|
||||||
deps::require_runtime_deps(&pkg_spec, &db_path)?;
|
deps::require_runtime_deps(&pkg_spec, &db_path)?;
|
||||||
if should_install_test_deps(&pkg_spec, options.install_test_deps) {
|
if should_install_test_deps(&pkg_spec, options.install_test_deps) {
|
||||||
deps::require_test_deps(&pkg_spec, &db_path)?;
|
let missing_test = deps::check_test_deps(&pkg_spec, &db_path)?;
|
||||||
|
if !missing_test.is_empty() {
|
||||||
|
let pkg_index =
|
||||||
|
index::PackageIndex::build_with_repo_dir(Some(config.repo_clone_dir.clone()));
|
||||||
|
let mut dep_spec_paths = Vec::new();
|
||||||
|
let mut unavailable_test = Vec::new();
|
||||||
|
for dep in &missing_test {
|
||||||
|
if let Some(dep_spec_path) = pkg_index.find(dep) {
|
||||||
|
dep_spec_paths.push(dep_spec_path);
|
||||||
|
} else {
|
||||||
|
unavailable_test.push(dep.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !unavailable_test.is_empty()
|
||||||
|
&& !maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut pkg_spec,
|
||||||
|
&unavailable_test,
|
||||||
|
"Requested test dependencies could not be resolved",
|
||||||
|
)?
|
||||||
|
{
|
||||||
|
anyhow::bail!("Missing test dependencies: {}", unavailable_test.join(", "));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !pkg_spec.build.flags.skip_tests && !dep_spec_paths.is_empty() {
|
||||||
|
ui::warn(format!(
|
||||||
|
"Missing test dependencies: {}",
|
||||||
|
missing_test.join(", ")
|
||||||
|
));
|
||||||
|
if ui::prompt_package_action("dependency installation", &missing_test, true)? {
|
||||||
|
ui::info(format!(
|
||||||
|
"Installing test dependencies: {}",
|
||||||
|
install_request_display(&dep_spec_paths)
|
||||||
|
));
|
||||||
|
let exe =
|
||||||
|
std::env::current_exe().context("Failed to locate depot executable")?;
|
||||||
|
run_install_command_with_program(
|
||||||
|
&exe,
|
||||||
|
&dep_spec_paths,
|
||||||
|
options.rootfs,
|
||||||
|
ChildInstallCommandOptions {
|
||||||
|
no_deps: options.no_deps,
|
||||||
|
assume_yes: false,
|
||||||
|
no_flags: options.no_flags,
|
||||||
|
cross_prefix: options.cross_prefix,
|
||||||
|
clean: options.clean,
|
||||||
|
install_test_deps: options.install_test_deps,
|
||||||
|
install_context: None,
|
||||||
|
dep_chain: None,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
} else if !maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut pkg_spec,
|
||||||
|
&missing_test,
|
||||||
|
"Requested test dependencies were not installed",
|
||||||
|
)? {
|
||||||
|
anyhow::bail!("Aborted");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if should_install_test_deps(&pkg_spec, options.install_test_deps) {
|
||||||
|
let missing_test = deps::check_test_deps(&pkg_spec, &db_path)?;
|
||||||
|
if !missing_test.is_empty()
|
||||||
|
&& !maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut pkg_spec,
|
||||||
|
&missing_test,
|
||||||
|
"Requested test dependencies are still missing",
|
||||||
|
)?
|
||||||
|
{
|
||||||
|
deps::require_test_deps(&pkg_spec, &db_path)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3717,24 +3859,33 @@ pub fn run(cli: Cli) -> Result<()> {
|
|||||||
})?;
|
})?;
|
||||||
let db_path = config.installed_db_path(&cli.rootfs);
|
let db_path = config.installed_db_path(&cli.rootfs);
|
||||||
|
|
||||||
if cli.no_deps || !should_install_test_deps(&pkg_spec, install_test_deps) {
|
if cli.no_deps && should_install_test_deps(&pkg_spec, install_test_deps) {
|
||||||
|
let missing_test = deps::check_test_deps(&pkg_spec, &db_path)?;
|
||||||
|
if !missing_test.is_empty()
|
||||||
|
&& !maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut pkg_spec,
|
||||||
|
&missing_test,
|
||||||
|
"Requested test dependencies are missing",
|
||||||
|
)?
|
||||||
|
{
|
||||||
|
anyhow::bail!("Missing test dependencies: {}", missing_test.join(", "));
|
||||||
|
}
|
||||||
|
} else if cli.no_deps || !should_install_test_deps(&pkg_spec, install_test_deps) {
|
||||||
maybe_disable_tests_for_missing_deps(&mut pkg_spec, &db_path)?;
|
maybe_disable_tests_for_missing_deps(&mut pkg_spec, &db_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check build dependencies
|
// Check build dependencies
|
||||||
if !cli.no_deps {
|
if !cli.no_deps {
|
||||||
deps::print_dep_status(&pkg_spec, &db_path)?;
|
deps::print_dep_status(&pkg_spec, &db_path)?;
|
||||||
let missing = merge_missing_dependencies(
|
let missing_required = merge_missing_dependencies(
|
||||||
deps::check_build_deps(&pkg_spec, &db_path)?,
|
deps::check_build_deps(&pkg_spec, &db_path)?,
|
||||||
deps::check_runtime_deps(&pkg_spec, &db_path)?,
|
deps::check_runtime_deps(&pkg_spec, &db_path)?,
|
||||||
);
|
);
|
||||||
let missing = if should_install_test_deps(&pkg_spec, install_test_deps) {
|
if !missing_required.is_empty() {
|
||||||
merge_missing_dependencies(missing, deps::check_test_deps(&pkg_spec, &db_path)?)
|
ui::warn(format!(
|
||||||
} else {
|
"Missing dependencies: {}",
|
||||||
missing
|
missing_required.join(", ")
|
||||||
};
|
));
|
||||||
if !missing.is_empty() {
|
|
||||||
ui::warn(format!("Missing dependencies: {}", missing.join(", ")));
|
|
||||||
let local_sibling_root = spec_path
|
let local_sibling_root = spec_path
|
||||||
.parent()
|
.parent()
|
||||||
.and_then(|p| p.parent())
|
.and_then(|p| p.parent())
|
||||||
@@ -3742,7 +3893,7 @@ pub fn run(cli: Cli) -> Result<()> {
|
|||||||
let dep_plan = planner::build_dependency_install_plan(
|
let dep_plan = planner::build_dependency_install_plan(
|
||||||
&config,
|
&config,
|
||||||
&cli.rootfs,
|
&cli.rootfs,
|
||||||
&missing,
|
&missing_required,
|
||||||
planner::PlannerOptions {
|
planner::PlannerOptions {
|
||||||
assume_yes: cli.yes,
|
assume_yes: cli.yes,
|
||||||
prefer_binary: config.repo_settings.prefer_binary,
|
prefer_binary: config.repo_settings.prefer_binary,
|
||||||
@@ -3751,7 +3902,11 @@ pub fn run(cli: Cli) -> Result<()> {
|
|||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
print_plan_summary(&dep_plan);
|
print_plan_summary(&dep_plan);
|
||||||
if !ui::prompt_package_action("dependency installation", &missing, true)? {
|
if !ui::prompt_package_action(
|
||||||
|
"dependency installation",
|
||||||
|
&missing_required,
|
||||||
|
true,
|
||||||
|
)? {
|
||||||
anyhow::bail!("Aborted");
|
anyhow::bail!("Aborted");
|
||||||
}
|
}
|
||||||
if cli.dry_run {
|
if cli.dry_run {
|
||||||
@@ -3775,7 +3930,84 @@ pub fn run(cli: Cli) -> Result<()> {
|
|||||||
deps::require_build_deps(&pkg_spec, &db_path)?;
|
deps::require_build_deps(&pkg_spec, &db_path)?;
|
||||||
deps::require_runtime_deps(&pkg_spec, &db_path)?;
|
deps::require_runtime_deps(&pkg_spec, &db_path)?;
|
||||||
if should_install_test_deps(&pkg_spec, install_test_deps) {
|
if should_install_test_deps(&pkg_spec, install_test_deps) {
|
||||||
deps::require_test_deps(&pkg_spec, &db_path)?;
|
let missing_test = deps::check_test_deps(&pkg_spec, &db_path)?;
|
||||||
|
if !missing_test.is_empty() {
|
||||||
|
let local_sibling_root = spec_path
|
||||||
|
.parent()
|
||||||
|
.and_then(|p| p.parent())
|
||||||
|
.map(Path::to_path_buf);
|
||||||
|
let dep_plan = match planner::build_dependency_install_plan(
|
||||||
|
&config,
|
||||||
|
&cli.rootfs,
|
||||||
|
&missing_test,
|
||||||
|
planner::PlannerOptions {
|
||||||
|
assume_yes: cli.yes,
|
||||||
|
prefer_binary: config.repo_settings.prefer_binary,
|
||||||
|
local_sibling_root,
|
||||||
|
include_test_deps: install_test_deps,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
Ok(plan) => plan,
|
||||||
|
Err(err)
|
||||||
|
if maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut pkg_spec,
|
||||||
|
&missing_test,
|
||||||
|
"Requested test dependencies could not be resolved",
|
||||||
|
)? =>
|
||||||
|
{
|
||||||
|
planner::ExecutionPlan { steps: Vec::new() }
|
||||||
|
}
|
||||||
|
Err(err) => return Err(err),
|
||||||
|
};
|
||||||
|
|
||||||
|
if !pkg_spec.build.flags.skip_tests && !dep_plan.steps.is_empty() {
|
||||||
|
ui::warn(format!(
|
||||||
|
"Missing test dependencies: {}",
|
||||||
|
missing_test.join(", ")
|
||||||
|
));
|
||||||
|
print_plan_summary(&dep_plan);
|
||||||
|
if !ui::prompt_package_action(
|
||||||
|
"dependency installation",
|
||||||
|
&missing_test,
|
||||||
|
true,
|
||||||
|
)? {
|
||||||
|
if !maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut pkg_spec,
|
||||||
|
&missing_test,
|
||||||
|
"Requested test dependencies were not installed",
|
||||||
|
)? {
|
||||||
|
anyhow::bail!("Aborted");
|
||||||
|
}
|
||||||
|
} else if !cli.dry_run {
|
||||||
|
execute_install_plan_with_child_commands(
|
||||||
|
&dep_plan,
|
||||||
|
&cli.rootfs,
|
||||||
|
&config,
|
||||||
|
InstallPlanExecutionOptions {
|
||||||
|
no_flags: cli.no_flags,
|
||||||
|
cross_prefix: cli.cross_prefix.as_deref(),
|
||||||
|
clean: cli.clean,
|
||||||
|
dry_run: cli.dry_run,
|
||||||
|
confirm_installation: false,
|
||||||
|
install_test_deps,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if should_install_test_deps(&pkg_spec, install_test_deps) {
|
||||||
|
let missing_test = deps::check_test_deps(&pkg_spec, &db_path)?;
|
||||||
|
if !missing_test.is_empty()
|
||||||
|
&& !maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut pkg_spec,
|
||||||
|
&missing_test,
|
||||||
|
"Requested test dependencies are still missing",
|
||||||
|
)?
|
||||||
|
{
|
||||||
|
deps::require_test_deps(&pkg_spec, &db_path)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if cli.dry_run {
|
} else if cli.dry_run {
|
||||||
ui::info("Dry run enabled, stopping before build.");
|
ui::info("Dry run enabled, stopping before build.");
|
||||||
@@ -5594,6 +5826,42 @@ optional = []
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn requested_test_deps_prompt_can_disable_tests() -> Result<()> {
|
||||||
|
let mut spec = test_package_spec(package::BuildType::Meson, None, &[]);
|
||||||
|
spec.dependencies.test = vec!["pytest".into()];
|
||||||
|
|
||||||
|
ui::set_assume_yes(true);
|
||||||
|
let prompted = maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut spec,
|
||||||
|
&["pytest".into()],
|
||||||
|
"Requested test dependencies are missing",
|
||||||
|
)?;
|
||||||
|
ui::set_assume_yes(false);
|
||||||
|
|
||||||
|
assert!(prompted);
|
||||||
|
assert!(spec.build.flags.skip_tests);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn requested_test_deps_prompt_is_ignored_for_non_automatic_test_builders() -> Result<()> {
|
||||||
|
let mut spec = test_package_spec(package::BuildType::Custom, None, &[]);
|
||||||
|
spec.dependencies.test = vec!["pytest".into()];
|
||||||
|
|
||||||
|
ui::set_assume_yes(true);
|
||||||
|
let prompted = maybe_prompt_to_skip_tests_for_missing_requested_deps(
|
||||||
|
&mut spec,
|
||||||
|
&["pytest".into()],
|
||||||
|
"Requested test dependencies are missing",
|
||||||
|
)?;
|
||||||
|
ui::set_assume_yes(false);
|
||||||
|
|
||||||
|
assert!(!prompted);
|
||||||
|
assert!(!spec.build.flags.skip_tests);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn rootfs_is_system_root_detects_live_rootfs() {
|
fn rootfs_is_system_root_detects_live_rootfs() {
|
||||||
assert!(rootfs_is_system_root(Path::new("/")));
|
assert!(rootfs_is_system_root(Path::new("/")));
|
||||||
|
|||||||
@@ -172,18 +172,6 @@ impl ShellHelpers {
|
|||||||
self.depot_executable.to_string_lossy().into_owned(),
|
self.depot_executable.to_string_lossy().into_owned(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Apply helper-related variables directly to a `std::process::Command`.
|
|
||||||
pub fn apply_to_command(&self, cmd: &mut std::process::Command) {
|
|
||||||
cmd.env("PATH", &self.path_value)
|
|
||||||
.env("DEPOT_OUTPUTS_DIR", &self.outputs_dir)
|
|
||||||
.env("DEPOT_INTERNAL_DIR", INTERNAL_DEPOT_DIR)
|
|
||||||
.env(DEPOT_HAUL_HELPER_ENV, &self.haul_path)
|
|
||||||
.env(DEPOT_SUBDESTDIR_HELPER_ENV, &self.subdestdir_path)
|
|
||||||
.env(DEPOT_PYTHON_BUILD_HELPER_ENV, &self.python_build_path)
|
|
||||||
.env(DEPOT_PYTHON_INSTALL_HELPER_ENV, &self.python_install_path)
|
|
||||||
.env(DEPOT_EXECUTABLE_ENV, &self.depot_executable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wrap a shell command with helper functions that invoke the helper scripts
|
/// Wrap a shell command with helper functions that invoke the helper scripts
|
||||||
|
|||||||
+92
-28
@@ -10,6 +10,15 @@ use std::process::Command;
|
|||||||
|
|
||||||
use crate::builder::state::{BuildStep, StateTracker};
|
use crate::builder::state::{BuildStep, StateTracker};
|
||||||
|
|
||||||
|
fn hook_env_vars(
|
||||||
|
spec: &PackageSpec,
|
||||||
|
shell_helpers: &crate::shell_helpers::ShellHelpers,
|
||||||
|
) -> crate::builder::EnvVars {
|
||||||
|
let mut env_vars = crate::builder::standard_build_env(spec, None, true, true);
|
||||||
|
shell_helpers.apply_to_env_vars(&mut env_vars);
|
||||||
|
env_vars
|
||||||
|
}
|
||||||
|
|
||||||
/// Apply patches and run `post_extract` commands in the extracted source tree.
|
/// Apply patches and run `post_extract` commands in the extracted source tree.
|
||||||
pub fn post_extract(
|
pub fn post_extract(
|
||||||
spec: &PackageSpec,
|
spec: &PackageSpec,
|
||||||
@@ -85,23 +94,27 @@ fn run_post_extract_commands(spec: &PackageSpec, source: &Source, src_dir: &Path
|
|||||||
"Running {} post-extract command(s)...",
|
"Running {} post-extract command(s)...",
|
||||||
source.post_extract.len()
|
source.post_extract.len()
|
||||||
);
|
);
|
||||||
|
let helper_root = tempfile::tempdir().context("Failed to create post-extract helper root")?;
|
||||||
|
let shell_helpers = crate::shell_helpers::ShellHelpers::new(helper_root.path())?;
|
||||||
|
let env_vars = hook_env_vars(spec, &shell_helpers);
|
||||||
|
|
||||||
for cmd in &source.post_extract {
|
for cmd in &source.post_extract {
|
||||||
let cmd = spec.expand_vars(cmd);
|
let cmd_str = spec.expand_vars(cmd);
|
||||||
crate::log_info!(" post_extract: {}", cmd);
|
crate::log_info!(" post_extract: {}", cmd_str);
|
||||||
|
let wrapped_cmd = crate::shell_helpers::wrap_shell_command(&cmd_str);
|
||||||
|
|
||||||
// Use a shell for convenience; this is a package manager, so specs are trusted input.
|
// Use a shell for convenience; this is a package manager, so specs are trusted input.
|
||||||
let status = Command::new("sh")
|
let mut shell_cmd = Command::new("sh");
|
||||||
.current_dir(src_dir)
|
shell_cmd.current_dir(src_dir);
|
||||||
.env("DEPOT_SPECDIR", &spec.spec_dir)
|
crate::builder::prepare_command(&mut shell_cmd, &env_vars);
|
||||||
.env("PATH", crate::runtime_env::safe_script_path())
|
let status = shell_cmd
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&cmd)
|
.arg(&wrapped_cmd)
|
||||||
.status()
|
.status()
|
||||||
.with_context(|| format!("Failed to run post_extract command: {}", cmd))?;
|
.with_context(|| format!("Failed to run post_extract command: {}", cmd_str))?;
|
||||||
|
|
||||||
if !status.success() {
|
if !status.success() {
|
||||||
bail!("post_extract command failed: {}", cmd);
|
bail!("post_extract command failed: {}", cmd_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,6 +134,12 @@ pub fn run_post_configure_commands(
|
|||||||
|
|
||||||
crate::log_info!("Running {} post-configure command(s)...", commands.len());
|
crate::log_info!("Running {} post-configure command(s)...", commands.len());
|
||||||
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
|
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
|
||||||
|
let mut env_vars = hook_env_vars(spec, &shell_helpers);
|
||||||
|
crate::builder::set_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"DESTDIR",
|
||||||
|
destdir.to_string_lossy().into_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
for cmd in commands {
|
for cmd in commands {
|
||||||
let cmd_str = spec.expand_vars(cmd);
|
let cmd_str = spec.expand_vars(cmd);
|
||||||
@@ -129,13 +148,8 @@ pub fn run_post_configure_commands(
|
|||||||
|
|
||||||
let mut shell_cmd = Command::new("sh");
|
let mut shell_cmd = Command::new("sh");
|
||||||
shell_cmd.current_dir(src_dir);
|
shell_cmd.current_dir(src_dir);
|
||||||
shell_helpers.apply_to_command(&mut shell_cmd);
|
crate::builder::prepare_command(&mut shell_cmd, &env_vars);
|
||||||
let status = shell_cmd
|
let status = shell_cmd
|
||||||
.env("DEPOT_SPECDIR", &spec.spec_dir)
|
|
||||||
.env("DESTDIR", destdir)
|
|
||||||
.env("DEPOT_ROOTFS", &spec.build.flags.rootfs)
|
|
||||||
.env("CC", &spec.build.flags.cc)
|
|
||||||
.env("AR", &spec.build.flags.ar)
|
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&wrapped_cmd)
|
.arg(&wrapped_cmd)
|
||||||
.status()
|
.status()
|
||||||
@@ -158,6 +172,12 @@ pub fn run_post_compile_commands(spec: &PackageSpec, src_dir: &Path, destdir: &P
|
|||||||
|
|
||||||
crate::log_info!("Running {} post-compile command(s)...", commands.len());
|
crate::log_info!("Running {} post-compile command(s)...", commands.len());
|
||||||
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
|
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
|
||||||
|
let mut env_vars = hook_env_vars(spec, &shell_helpers);
|
||||||
|
crate::builder::set_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"DESTDIR",
|
||||||
|
destdir.to_string_lossy().into_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
for cmd in commands {
|
for cmd in commands {
|
||||||
let cmd_str = spec.expand_vars(cmd);
|
let cmd_str = spec.expand_vars(cmd);
|
||||||
@@ -166,13 +186,8 @@ pub fn run_post_compile_commands(spec: &PackageSpec, src_dir: &Path, destdir: &P
|
|||||||
|
|
||||||
let mut shell_cmd = Command::new("sh");
|
let mut shell_cmd = Command::new("sh");
|
||||||
shell_cmd.current_dir(src_dir);
|
shell_cmd.current_dir(src_dir);
|
||||||
shell_helpers.apply_to_command(&mut shell_cmd);
|
crate::builder::prepare_command(&mut shell_cmd, &env_vars);
|
||||||
let status = shell_cmd
|
let status = shell_cmd
|
||||||
.env("DEPOT_SPECDIR", &spec.spec_dir)
|
|
||||||
.env("DESTDIR", destdir)
|
|
||||||
.env("DEPOT_ROOTFS", &spec.build.flags.rootfs)
|
|
||||||
.env("CC", &spec.build.flags.cc)
|
|
||||||
.env("AR", &spec.build.flags.ar)
|
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&wrapped_cmd)
|
.arg(&wrapped_cmd)
|
||||||
.status()
|
.status()
|
||||||
@@ -195,6 +210,12 @@ pub fn run_post_install_commands(spec: &PackageSpec, src_dir: &Path, destdir: &P
|
|||||||
|
|
||||||
crate::log_info!("Running {} post-install command(s)...", commands.len());
|
crate::log_info!("Running {} post-install command(s)...", commands.len());
|
||||||
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
|
let shell_helpers = crate::shell_helpers::ShellHelpers::new(destdir)?;
|
||||||
|
let mut env_vars = hook_env_vars(spec, &shell_helpers);
|
||||||
|
crate::builder::set_env_var(
|
||||||
|
&mut env_vars,
|
||||||
|
"DESTDIR",
|
||||||
|
destdir.to_string_lossy().into_owned(),
|
||||||
|
);
|
||||||
|
|
||||||
for cmd in commands {
|
for cmd in commands {
|
||||||
let cmd_str = spec.expand_vars(cmd);
|
let cmd_str = spec.expand_vars(cmd);
|
||||||
@@ -203,13 +224,8 @@ pub fn run_post_install_commands(spec: &PackageSpec, src_dir: &Path, destdir: &P
|
|||||||
|
|
||||||
let mut shell_cmd = Command::new("sh");
|
let mut shell_cmd = Command::new("sh");
|
||||||
shell_cmd.current_dir(src_dir);
|
shell_cmd.current_dir(src_dir);
|
||||||
shell_helpers.apply_to_command(&mut shell_cmd);
|
crate::builder::prepare_command(&mut shell_cmd, &env_vars);
|
||||||
let status = shell_cmd
|
let status = shell_cmd
|
||||||
.env("DEPOT_SPECDIR", &spec.spec_dir)
|
|
||||||
.env("DESTDIR", destdir)
|
|
||||||
.env("DEPOT_ROOTFS", &spec.build.flags.rootfs)
|
|
||||||
.env("CC", &spec.build.flags.cc)
|
|
||||||
.env("AR", &spec.build.flags.ar)
|
|
||||||
.arg("-c")
|
.arg("-c")
|
||||||
.arg(&wrapped_cmd)
|
.arg(&wrapped_cmd)
|
||||||
.status()
|
.status()
|
||||||
@@ -291,7 +307,7 @@ fn download(url: &str, dest: &Path) -> Result<()> {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{resolve_patch_path, run_post_install_commands};
|
use super::{resolve_patch_path, run_post_extract_commands, run_post_install_commands};
|
||||||
use crate::package::{
|
use crate::package::{
|
||||||
Alternatives, Build, BuildFlags, BuildType, Dependencies, PackageInfo, PackageSpec, Source,
|
Alternatives, Build, BuildFlags, BuildType, Dependencies, PackageInfo, PackageSpec, Source,
|
||||||
};
|
};
|
||||||
@@ -386,4 +402,52 @@ mod tests {
|
|||||||
.exists()
|
.exists()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn post_extract_commands_can_call_python_build_helper() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let spec_dir = tmp.path().join("spec");
|
||||||
|
let src_dir = tmp.path().join("src");
|
||||||
|
std::fs::create_dir_all(&spec_dir).unwrap();
|
||||||
|
std::fs::create_dir_all(&src_dir).unwrap();
|
||||||
|
|
||||||
|
let fake_depot = tmp.path().join("fake-depot");
|
||||||
|
let log_path = tmp.path().join("python-build.log");
|
||||||
|
std::fs::write(
|
||||||
|
&fake_depot,
|
||||||
|
format!(
|
||||||
|
"#!/bin/sh\nset -eu\nprintf '%s\\n' \"$@\" > '{}'\n",
|
||||||
|
log_path.display()
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
use std::os::unix::fs::PermissionsExt;
|
||||||
|
let mut perms = std::fs::metadata(&fake_depot).unwrap().permissions();
|
||||||
|
perms.set_mode(0o755);
|
||||||
|
std::fs::set_permissions(&fake_depot, perms).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let spec = dummy_spec(&spec_dir);
|
||||||
|
let source = Source {
|
||||||
|
url: "https://example.com/foo.tar.gz".into(),
|
||||||
|
sha256: "skip".into(),
|
||||||
|
extract_dir: "foo".into(),
|
||||||
|
patches: Vec::new(),
|
||||||
|
post_extract: vec![format!(
|
||||||
|
"DEPOT_EXECUTABLE='{}' python_build --src-dir . --dist-dir dist",
|
||||||
|
fake_depot.display()
|
||||||
|
)],
|
||||||
|
cherry_pick: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
run_post_extract_commands(&spec, &source, &src_dir).unwrap();
|
||||||
|
|
||||||
|
let logged = std::fs::read_to_string(&log_path).unwrap();
|
||||||
|
assert!(logged.contains("internal"));
|
||||||
|
assert!(logged.contains("python-build"));
|
||||||
|
assert!(logged.contains("--src-dir"));
|
||||||
|
assert!(logged.contains("--dist-dir"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user