use crate::error::{Cause, PathAndCause};
use crate::{Error, Result, SPath};
pub(crate) fn check_path_safety_causes(
path: &SPath,
restrict_to_current_dir: bool,
must_contain_any: Option<&[&str]>,
must_contain_all: Option<&[&str]>,
) -> Result<Vec<String>> {
let mut error_causes = Vec::new();
let resolved = path.canonicalize()?;
let resolved_str = resolved.as_str();
let path_str = path.as_str();
if restrict_to_current_dir {
let current_dir = std::env::current_dir().map_err(|e| {
Error::CantGetMetadata(PathAndCause {
path: path.to_string(),
cause: Cause::Io(Box::new(e)),
})
})?;
let current_dir_path = SPath::from_std_path_buf(current_dir)?;
let current_resolved = current_dir_path.canonicalize()?;
let current_str = current_resolved.as_str();
if !resolved_str.starts_with(current_str) {
error_causes.push(format!("is not below current directory '{current_resolved}'"));
}
}
if let Some(patterns) = must_contain_any {
if patterns.is_empty() {
error_causes.push("must_contain_any cannot be an empty list (use None to disable)".to_string());
} else {
let has_any = patterns.iter().any(|s| path_str.contains(s));
if !has_any {
error_causes.push(format!("does not contain any of the required patterns: {patterns:?}"));
}
}
}
if let Some(patterns) = must_contain_all {
if patterns.is_empty() {
error_causes.push("must_contain_all cannot be an empty list (use None to disable)".to_string());
} else {
let missing: Vec<_> = patterns.iter().filter(|s| !path_str.contains(*s)).collect();
if !missing.is_empty() {
error_causes.push(format!("does not contain all required patterns, missing: {missing:?}"));
}
}
}
Ok(error_causes)
}