use thiserror::Error;
use super::PackManifest;
use crate::tree::PackGraph;
pub(crate) mod child_path;
pub mod cycle;
pub mod depends_on;
pub mod dup_symlink;
pub(crate) use child_path::{ChildPathValidator, DupChildPathValidator};
pub use cycle::CycleValidator;
pub use depends_on::DependsOnValidator;
pub use dup_symlink::DuplicateSymlinkValidator;
#[non_exhaustive]
#[derive(Debug, Clone, PartialEq, Eq, Error)]
pub enum PackValidationError {
#[error("duplicate symlink dst `{dst}` (actions at indices {first} and {second})")]
DuplicateSymlinkDst {
dst: String,
first: usize,
second: usize,
},
#[error("cycle detected in pack graph: {chain:?}")]
GraphCycle {
chain: Vec<String>,
},
#[error("pack `{pack}` depends on `{required}` but no such pack exists in the graph")]
DependsOnUnsatisfied {
pack: String,
required: String,
},
#[error("pack child `{child_name}` has invalid path `{path}`: {reason}")]
ChildPathInvalid {
child_name: String,
path: String,
reason: String,
},
#[error("pack has duplicate children resolving to `{path}`: {urls:?}")]
ChildPathDuplicate {
path: String,
urls: Vec<String>,
},
}
pub trait Validator {
fn name(&self) -> &'static str;
fn check(&self, pack: &PackManifest) -> Vec<PackValidationError>;
}
#[must_use]
pub fn run_all(pack: &PackManifest) -> Vec<PackValidationError> {
let validators: [&dyn Validator; 3] =
[&DuplicateSymlinkValidator, &ChildPathValidator, &DupChildPathValidator];
let mut errs = Vec::new();
for v in validators {
errs.extend(v.check(pack));
}
errs
}
pub trait GraphValidator {
fn name(&self) -> &'static str;
fn check(&self, graph: &PackGraph) -> Vec<PackValidationError>;
}
#[must_use]
pub fn run_all_graph(graph: &PackGraph) -> Vec<PackValidationError> {
let validators: [&dyn GraphValidator; 2] = [&CycleValidator, &DependsOnValidator];
let mut errs = Vec::new();
for v in validators {
errs.extend(v.check(graph));
}
errs
}
impl PackGraph {
pub fn validate(&self) -> Result<(), Vec<PackValidationError>> {
let errs = run_all_graph(self);
if errs.is_empty() {
Ok(())
} else {
Err(errs)
}
}
}