use std::{
fs,
path::{Path, PathBuf}
};
use crate::err::Error;
#[allow(clippy::module_name_repetitions)]
pub trait PathExt {
fn expand(input: &str) -> Result<PathBuf, Error> {
match shellexpand::full(&input) {
Ok(value) => Ok(PathBuf::from(value.into_owned())),
Err(e) => Err(Error::BadFormat(format!("Unable to expand path; {e}")))
}
}
fn expand_and<F>(input: &str, f: F) -> Result<PathBuf, Error>
where
F: FnOnce(&Path) -> Result<(), Error>
{
let expanded = PathBuf::expand(input)?;
f(&expanded)?;
Ok(expanded)
}
fn expand_and_canon<F>(input: &str, f: F) -> Result<PathBuf, Error>
where
F: FnOnce(&Path) -> Result<(), Error>
{
let expanded = PathBuf::expand_and(input, f)?;
Ok(fs::canonicalize(&expanded)?)
}
}
impl PathExt for PathBuf {}
pub fn expand(input: impl AsRef<str>) -> Result<PathBuf, Error> {
match shellexpand::full(&input) {
Ok(value) => Ok(PathBuf::from(value.into_owned())),
Err(e) => Err(Error::BadFormat(format!("Unable to expand path; {e}")))
}
}
#[allow(clippy::missing_errors_doc)]
pub fn expabs(input: impl AsRef<str>) -> Result<PathBuf, Error> {
let exppth = expand(input)?;
abspath(exppth)
}
#[allow(clippy::missing_errors_doc)]
pub fn abspath<P>(pth: P) -> Result<PathBuf, Error>
where
P: AsRef<Path>
{
fn inner(pth: &Path) -> Result<PathBuf, Error> {
if pth.is_absolute() {
Ok(pth.to_path_buf())
} else {
let cwd = std::env::current_dir()?;
Ok(cwd.join(pth))
}
}
inner(pth.as_ref())
}
pub fn abs_or_base(basedir: &Path, pth: impl AsRef<Path>) -> PathBuf {
fn inner(basedir: &Path, pth: &Path) -> PathBuf {
assert!(basedir.is_absolute());
if pth.is_absolute() {
pth.to_path_buf()
} else {
basedir.join(pth)
}
}
inner(basedir, pth.as_ref())
}
#[must_use]
#[allow(clippy::option_if_let_else)]
pub fn win2unix_sep(pth: impl AsRef<Path>) -> PathBuf {
let pth = pth.as_ref();
if let Some(s) = pth.to_str() {
let converted = s.replace('\\', "/");
PathBuf::from(converted)
} else {
pth.to_path_buf()
}
}