use std::path::{Component, Path, PathBuf};
use anyhow::{Result, bail};
pub(crate) const STATE_DIR: &str = ".toolconfig-state";
pub(crate) fn absolute(base: &Path, path: &Path) -> Result<PathBuf> {
let joined = if path.is_absolute() {
path.to_path_buf()
} else {
base.join(path)
};
let mut result = PathBuf::new();
for component in joined.components() {
match component {
Component::CurDir => {}
Component::ParentDir => {
if !result.pop() {
bail!("path escapes its filesystem root: {}", joined.display());
}
}
part => result.push(part.as_os_str()),
}
}
if !result.is_absolute() {
bail!("path is not absolute: {}", result.display());
}
Ok(result)
}
pub(crate) fn key(path: &Path) -> String {
let key = path.to_string_lossy();
if cfg!(any(windows, target_os = "macos")) {
key.to_lowercase()
} else {
key.into_owned()
}
}
pub(crate) fn relative(root: &Path, path: &Path) -> String {
let relative = path.strip_prefix(root).unwrap_or(path);
let text = relative.to_string_lossy().replace('\\', "/");
if text.is_empty() {
".".to_owned()
} else {
text
}
}