Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,8 +1,8 @@ [package] name = "orphanage" -version = "0.1.0" +version = "0.1.1" edition = "2021" license = "0BSD" # https://crates.io/category_slugs categories = [ "network-programming" ] keywords = [ "sqlite", "fs", "path" ] Index: src/path.rs ================================================================== --- src/path.rs +++ src/path.rs @@ -3,13 +3,66 @@ //! There's some functionality that overlaps with [`fs`](super::fs), but the //! main difference is that functions in `fs` assume the file system objects //! exists, while functions in the `path` submodule (generally) make no such //! assumptions. -use std::path::{Path, PathBuf}; +use std::{ + fs, + path::{Path, PathBuf} +}; use crate::err::Error; + +/// Path extensions. +#[allow(clippy::module_name_repetitions)] +pub trait PathExt { + /// Expand a path and return it. + /// + /// # Errors + /// [`Error::BadFormat`] means the input path could not be expanded. + fn expand(input: &str) -> Result { + match shellexpand::full(&input) { + Ok(value) => Ok(PathBuf::from(value.into_owned())), + Err(e) => Err(Error::BadFormat(format!("Unable to expand path; {e}"))) + } + } + + /// Expand a path, run a closure on the expanded path, and then return the + /// expanded path. + /// + /// # Errors + /// [`Error::BadFormat`] means the input path could not be expanded. + fn expand_and(input: &str, f: F) -> Result + where + F: FnOnce(&Path) -> Result<(), Error> + { + let expanded = PathBuf::expand(input)?; + f(&expanded)?; + Ok(expanded) + } + + /// Expand a path, run a closure on the expanded path, canonicalize the path + /// and then return it. + /// + /// The canonicalization occurs _after_ the closure has been called because + /// the the canonicalization may not be possible until the closure has run + /// (for instance, if the closure is meant to create the file system object + /// that is meant to be canonicalized). + /// + /// # Errors + /// [`Error::BadFormat`] means the input path could not be expanded. + fn expand_and_canon(input: &str, f: F) -> Result + where + F: FnOnce(&Path) -> Result<(), Error> + { + let expanded = PathBuf::expand_and(input, f)?; + Ok(fs::canonicalize(&expanded)?) + } +} + +impl PathExt for PathBuf {} + /// Expand a string path and return it as a `PathBuf`. /// /// The expansion is done using [`shellexpand::full()`]. /// @@ -78,6 +131,39 @@ } inner(basedir, pth.as_ref()) } + +/* +/// Expand, perform action on expanded path. +pub fn expand_and(input: impl AsRef, f: F) -> Result +where + F: FnOnce(&Path) -> Result<(), Error> +{ + let expanded = match shellexpand::full(&input) { + Ok(value) => Ok(PathBuf::from(value.into_owned())), + Err(e) => Err(Error::BadFormat(format!("Unable to expand path; {e}"))) + }?; + + // Call closure to process the expanded path + f(&expanded)?; + + Ok(expanded) +} + +/// Expand, perform action on expanded path and return canonicalized path. +pub fn expand_canonizalize( + input: impl AsRef, + f: F +) -> Result +where + F: FnOnce(&Path) -> Result<(), Error> +{ + let expanded = expand_and(input, f)?; + + // Canonicalize + Ok(fs::canonicalize(&expanded)?) +} +*/ + // vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : Index: www/changelog.md ================================================================== --- www/changelog.md +++ www/changelog.md @@ -3,10 +3,17 @@ ## [Unreleased] [Details](/vdiff?from=orphanage-0.1.0&to=trunk) ### Added + +- Add `path::PathExt`, and implement it for `PathBuf`. + - `PathBuf::expand()` expands a string to a `PathBuf` and returns it. + - `PathBuf::expand_and()` works like `PathBuf::expand()` but it runs a + closure on the expanded pwth before returning it. + - `PathBuf::expand_and_canon()` works like `PathBuf::expand_and()` but it + canonicalizes the path just before returning it. ### Changed ### Removed