use std::path::{Path, PathBuf};
pub(super) fn normalize(path: &str) -> String {
path.replace('\\', "/").trim_start_matches("./").to_owned()
}
pub(super) fn is_relative(path: &str) -> bool {
!path.is_empty() && !Path::new(path).is_absolute()
}
pub(crate) fn repo_relative_file(root: &Path, relative: &str) -> Result<PathBuf, String> {
if !is_relative(relative) {
return Err("source path must be repository-relative".to_owned());
}
let canonical_root = root
.canonicalize()
.map_err(|error| format!("cannot resolve repository root: {error}"))?;
let joined = canonical_root.join(relative);
let path = joined
.canonicalize()
.map_err(|error| format!("cannot resolve {relative}: {error}"))?;
if !path.starts_with(&canonical_root) || !path.is_file() {
return Err(format!(
"source path escapes repository or is not a file: {relative}"
));
}
Ok(path)
}