From f810927faffe228cdf56707e22bf3c7a3b334c46 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 3 Nov 2024 11:17:30 +0000 Subject: [PATCH] feat(fs): add .path(path).canonicalize() --- README.md | 2 +- src/fs/path.rs | 19 +++++++++++++++++++ tests/fs.rs | 28 ++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5205003..e5dc156 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Provides injectable Filesystem and Network resources to make code more testable. #### std::fs alternatives -- [ ] `std::fs::canonicalize` - `path(path).canonicalize()` - Returns the canonical, absolute form of a path with all intermediate components normalized and symbolic links resolved. +- [x] `std::fs::canonicalize` - `path(path).canonicalize()` - Returns the canonical, absolute form of a path with all intermediate components normalized and symbolic links resolved. - [x] `std::fs::copy` - `file(path).copy(target)` - Copies the contents of one file to another. This function will also copy the permission bits of the original file to the destination file. - [x] `std::fs::create_dir` - `dir(path).create()` - Creates a new, empty directory at the provided path - [x] `std::fs::create_dir_all` - `dir(path).create_all()` - Recursively create a directory and all of its parent components if they are missing. diff --git a/src/fs/path.rs b/src/fs/path.rs index 9325971..58937ff 100644 --- a/src/fs/path.rs +++ b/src/fs/path.rs @@ -283,6 +283,25 @@ impl<'base, 'path, T: PathType> PathReal<'base, 'path, T> { self.check_error()?; Ok(self.as_pathbuf().is_symlink()) } + + /// Returns the canonical, absolute form of the path with all intermediate + /// components normalized and symbolic links resolved. + /// + /// ``` + /// # use kxio::fs::Result; + /// # fn main() -> Result<()> { + /// let fs = kxio::fs::temp()?; + /// let path = fs.base().join("foo"); + /// # fs.dir(&path).create()?; + /// let dir = fs.path(&path); + /// let canonical = dir.canonicalize()?; + /// # Ok(()) + /// # } + /// ``` + pub fn canonicalize(&self) -> Result { + self.check_error()?; + self.as_pathbuf().canonicalize().map_err(Error::Io) + } } impl<'base, 'path> From> for PathBuf { fn from(path: PathReal) -> Self { diff --git a/tests/fs.rs b/tests/fs.rs index 7d947de..f21082a 100644 --- a/tests/fs.rs +++ b/tests/fs.rs @@ -661,3 +661,31 @@ mod dir { } } } +mod canonicalize { + use std::path::Path; + + use super::*; + + #[test] + fn should_resolve_symlinks() -> TestResult { + let fs = fs::temp().expect("temp fs"); + + let file_path = fs.base().join("foo"); + let file = fs.file(&file_path); + file.write("bar").expect("write"); + + let link_path = fs.base().join("link"); + let link = fs.path(&link_path); + file.soft_link(&link).expect("create"); + let canonical = link.canonicalize().expect("canonicalize"); + let canonical = if canonical.starts_with("/private") { + // INFO: macos puts all temp files under /private + Path::new("/").join(canonical.strip_prefix("/private").unwrap()) + } else { + canonical + }; + assert_eq!(canonical, file_path); + + Ok(()) + } +}