refactor command flow and add signed package/hook safety
- split CLI definitions and command execution out of main.rs into new cli.rs and commands.rs modules\n- add transaction hook support via /etc/depot.d/hooks/*.toml with pre/post phases, operation/package/path filters, wildcard negation, and optional affected-path stdin\n- execute transaction hooks around install/update/remove operations and add package-action prompts for install/build/remove flows\n- require and verify detached minisign signatures for binary package archives when allow_unsigned=false, including cache handling and tests\n- persist optional dependencies from package metadata into repo index data and include optional deps in produced metadata\n- update dependency/planner logic to ignore dependencies provided by local split outputs and stop pulling test deps into install planning\n- auto-disable tests when required test dependencies are missing instead of hard-failing build/install paths\n- improve autotools defaults by injecting standard install directory flags when supported and preserving user overrides\n- remove static .a archives during staging by default with new build.flags.no_delete_static escape hatch\n- preserve symlinks and file metadata (permissions/timestamps) in extractor fallback copy path and add regression tests\n- refresh README docs for detached package signatures, optional dependencies, and transaction hooks\n- adjust dependency set: add filetime, disable reqwest default features, and simplify git2/OpenSSL linkage
This commit is contained in:
+84
-17
@@ -9,7 +9,7 @@
|
||||
//! - `package<=1.2.3` - less than or equal to 1.2.3
|
||||
|
||||
use crate::db;
|
||||
use crate::package::PackageSpec;
|
||||
use crate::package::{BuildType, PackageSpec};
|
||||
use crate::ui;
|
||||
use anyhow::Result;
|
||||
use std::path::Path;
|
||||
@@ -139,6 +139,13 @@ fn is_dep_satisfied(
|
||||
}
|
||||
}
|
||||
|
||||
fn build_type_runs_automatic_tests(spec: &PackageSpec) -> bool {
|
||||
matches!(
|
||||
spec.build.build_type,
|
||||
BuildType::Autotools | BuildType::CMake
|
||||
)
|
||||
}
|
||||
|
||||
/// Check whether a dependency expression is satisfied by the installed package DB.
|
||||
pub fn is_dep_satisfied_in_db(dep: &str, db_path: &Path) -> Result<bool> {
|
||||
if !db_path.exists() {
|
||||
@@ -173,15 +180,24 @@ pub fn check_build_deps(spec: &PackageSpec, db_path: &Path) -> Result<Vec<String
|
||||
/// Check if all runtime dependencies are satisfied
|
||||
pub fn check_runtime_deps(spec: &PackageSpec, db_path: &Path) -> Result<Vec<String>> {
|
||||
let mut missing = Vec::new();
|
||||
let local_provides = spec.local_dependency_provides();
|
||||
|
||||
if !db_path.exists() {
|
||||
return Ok(spec.dependencies.runtime.clone());
|
||||
for dep in &spec.dependencies.runtime {
|
||||
if !local_provides.contains(dep_name(dep)) {
|
||||
missing.push(dep.clone());
|
||||
}
|
||||
}
|
||||
return Ok(missing);
|
||||
}
|
||||
|
||||
let installed = db::get_installed_packages(db_path)?;
|
||||
let provides = db::get_all_provides(db_path)?;
|
||||
|
||||
for dep in &spec.dependencies.runtime {
|
||||
if local_provides.contains(dep_name(dep)) {
|
||||
continue;
|
||||
}
|
||||
if !is_dep_satisfied(dep, &installed, &provides, db_path)? {
|
||||
missing.push(dep.clone());
|
||||
}
|
||||
@@ -244,11 +260,21 @@ pub fn print_dep_status(spec: &PackageSpec, db_path: &Path) -> Result<()> {
|
||||
"Test dependencies: {}",
|
||||
spec.dependencies.test.join(", ")
|
||||
));
|
||||
if !missing_test.is_empty() {
|
||||
if !spec.build.flags.skip_tests
|
||||
&& build_type_runs_automatic_tests(spec)
|
||||
&& !missing_test.is_empty()
|
||||
{
|
||||
ui::warn(format!("Test deps missing: {}", missing_test.join(", ")));
|
||||
}
|
||||
}
|
||||
|
||||
if !spec.dependencies.optional.is_empty() {
|
||||
ui::info(format!(
|
||||
"Optional dependencies: {}",
|
||||
spec.dependencies.optional.join(", ")
|
||||
));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -266,20 +292,6 @@ pub fn require_build_deps(spec: &PackageSpec, db_path: &Path) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify all test dependencies are installed, error if not
|
||||
pub fn require_test_deps(spec: &PackageSpec, db_path: &Path) -> Result<()> {
|
||||
let missing = check_test_deps(spec, db_path)?;
|
||||
|
||||
if !missing.is_empty() {
|
||||
anyhow::bail!(
|
||||
"Missing test dependencies: {}\nInstall them first with: depot install <package>",
|
||||
missing.join(", ")
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify all runtime dependencies are installed, error if not.
|
||||
pub fn require_runtime_deps(spec: &PackageSpec, db_path: &Path) -> Result<()> {
|
||||
let missing = check_runtime_deps(spec, db_path)?;
|
||||
@@ -372,6 +384,7 @@ mod tests {
|
||||
build: Vec::new(),
|
||||
runtime: Vec::new(),
|
||||
test: vec!["bats".into(), "python".into()],
|
||||
optional: Vec::new(),
|
||||
},
|
||||
package_alternatives: Default::default(),
|
||||
package_dependencies: Default::default(),
|
||||
@@ -411,6 +424,7 @@ mod tests {
|
||||
build: Vec::new(),
|
||||
runtime: vec!["python".into()],
|
||||
test: Vec::new(),
|
||||
optional: Vec::new(),
|
||||
},
|
||||
package_alternatives: Default::default(),
|
||||
package_dependencies: Default::default(),
|
||||
@@ -421,4 +435,57 @@ mod tests {
|
||||
.expect_err("runtime deps should be required");
|
||||
assert!(err.to_string().contains("Missing runtime dependencies"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_check_runtime_deps_ignores_local_outputs_and_provides() {
|
||||
let spec = PackageSpec {
|
||||
package: crate::package::PackageInfo {
|
||||
name: "foo".into(),
|
||||
version: "1.0".into(),
|
||||
revision: 1,
|
||||
description: "d".into(),
|
||||
homepage: "h".into(),
|
||||
license: vec!["MIT".into()],
|
||||
},
|
||||
packages: vec![crate::package::PackageInfo {
|
||||
name: "foo-libs".into(),
|
||||
version: "1.0".into(),
|
||||
revision: 1,
|
||||
description: "d".into(),
|
||||
homepage: "h".into(),
|
||||
license: vec!["MIT".into()],
|
||||
}],
|
||||
alternatives: Default::default(),
|
||||
manual_sources: Vec::new(),
|
||||
source: vec![crate::package::Source {
|
||||
url: "https://example.test/foo.tar.gz".into(),
|
||||
sha256: "skip".into(),
|
||||
extract_dir: "foo".into(),
|
||||
patches: Vec::new(),
|
||||
post_extract: Vec::new(),
|
||||
}],
|
||||
build: crate::package::Build {
|
||||
build_type: crate::package::BuildType::Custom,
|
||||
flags: crate::package::BuildFlags::default(),
|
||||
},
|
||||
dependencies: crate::package::Dependencies {
|
||||
build: Vec::new(),
|
||||
runtime: vec!["foo-libs".into(), "libfoo".into(), "python".into()],
|
||||
test: Vec::new(),
|
||||
optional: Vec::new(),
|
||||
},
|
||||
package_alternatives: std::collections::BTreeMap::from([(
|
||||
"foo-libs".to_string(),
|
||||
crate::package::Alternatives {
|
||||
provides: vec!["libfoo".into()],
|
||||
replaces: Vec::new(),
|
||||
},
|
||||
)]),
|
||||
package_dependencies: Default::default(),
|
||||
spec_dir: std::path::PathBuf::from("."),
|
||||
};
|
||||
|
||||
let missing = check_runtime_deps(&spec, Path::new("/definitely/not/a/real/db")).unwrap();
|
||||
assert_eq!(missing, vec!["python".to_string()]);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user