use std::path::{Path, PathBuf};
fn rebase_path(path: &Path, base: &Path) -> PathBuf {
use std::path::Component;
let mut components: Vec<_> = base.components().collect();
#[cfg(not(test))]
{
assert!(components.is_empty() || base.is_dir());
assert!(path.is_relative());
}
if components.is_empty() {
return path.to_path_buf();
}
for component in path.components() {
match component {
Component::CurDir => (),
Component::ParentDir => {
match components.pop() {
Some(Component::ParentDir) => {
components.push(Component::ParentDir);
components.push(Component::ParentDir);
}
Some(Component::Normal(_)) => (),
Some(Component::CurDir) | None => components.push(Component::ParentDir),
_ => unreachable!(),
}
}
Component::Normal(_) => components.push(component),
Component::RootDir | Component::Prefix(_) => unreachable!(),
}
}
components.into_iter().fold(PathBuf::new(), |mut acc, el| {
acc.push(el);
acc
})
}
pub(crate) fn resolve_path(path: &Path, root: &Path, parent: Option<&Path>) -> PathBuf {
if path.is_absolute() {
log::info!("path {} is absolute", path.display());
return path.to_path_buf();
}
if root.join(path).exists() {
return rebase_path(path, root);
}
if let Some(parent) = parent
&& parent.join(path).exists()
{
return rebase_path(path, parent);
}
path.to_owned()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_rebase_path() {
let base = Path::new("../../");
let path = Path::new("../../hi.fea");
assert_eq!(rebase_path(path, base), Path::new("../../../../hi.fea"));
let path2 = Path::new("./../../hi.fea");
assert_eq!(rebase_path(path2, base), Path::new("../../../../hi.fea"));
let base = Path::new("../includes/");
let path = Path::new("../font/other.fea");
assert_eq!(rebase_path(path, base), Path::new("../font/other.fea"));
let base = Path::new("font/includes");
let path = Path::new("../../font/includes/features.fea");
assert_eq!(
rebase_path(path, base),
Path::new("font/includes/features.fea")
);
let empty_base = Path::new("");
assert!(!empty_base.is_dir());
let path = Path::new("font/includes/features.fea");
assert_eq!(
rebase_path(path, empty_base),
Path::new("font/includes/features.fea")
);
}
}