From c59aacd4bc1b88682712eb5d68250acb697e2d5a Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Sun, 3 Nov 2024 17:49:34 +0000 Subject: [PATCH] feat(fs): add .path(path).soft_link(other), .path(path).is_link() --- src/fs/path.rs | 40 ++++++++++++++++++++++++++++++++++++++++ tests/fs.rs | 48 +++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/src/fs/path.rs b/src/fs/path.rs index c6aacce..62eafca 100644 --- a/src/fs/path.rs +++ b/src/fs/path.rs @@ -262,6 +262,46 @@ impl<'base, 'path, T: PathType> PathReal<'base, 'path, T> { self.check_error()?; std::fs::metadata(self.as_pathbuf()).map_err(Error::Io) } + + /// Creates a symbolic link to a path. + /// + /// Wrapper for [std::os::unix::fs::symlink] + /// + /// ``` + /// # use kxio::fs::Result; + /// # fn main() -> Result<()> { + /// let fs = kxio::fs::temp()?; + /// let src_path = fs.base().join("foo"); + /// let src = fs.file(&src_path); + /// # src.write("bar")?; + /// let link_path = fs.base().join("bar"); + /// let link = fs.path(&link_path); + /// src.soft_link(&link)?; + /// # Ok(()) + /// # } + /// ``` + pub fn soft_link(&self, link: &PathReal<'_, '_, PathMarker>) -> Result<()> { + self.check_error()?; + std::os::unix::fs::symlink(self.as_pathbuf(), link.as_pathbuf()).map_err(Error::Io) + } + + /// Returns true if the path is a symbolic link. + /// + /// ``` + /// # use kxio::fs::Result; + /// # fn main() -> Result<()> { + /// let fs = kxio::fs::temp()?; + /// let path = fs.base().join("foo"); + /// let dir = fs.dir(&path); + /// # dir.create()?; + /// if dir.is_link()? { /* ... */ } + /// # Ok(()) + /// # } + /// ``` + pub fn is_link(&self) -> Result { + self.check_error()?; + Ok(self.as_pathbuf().is_symlink()) + } } impl<'base, 'path> From> for PathBuf { fn from(path: PathReal) -> Self { diff --git a/tests/fs.rs b/tests/fs.rs index 7ee9bdc..43a6aee 100644 --- a/tests/fs.rs +++ b/tests/fs.rs @@ -299,6 +299,42 @@ mod path { mod file { use super::*; + // // test for reading the symlink metadata + // #[test] + // fn symlink_metadata() -> 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("bar"); + // let link = fs.path(&link_path); + // file.soft_link(&link).expect("soft_link"); + // let md = link.symlink_metadata().expect("symlink metadata"); + // assert!(md.is_file()); + // Ok(()) + // } + + #[test] + fn create_soft_link() -> TestResult { + let fs = fs::temp().expect("temp fs"); + + let file_path = fs.base().join("foo"); + let file = fs.file(&file_path); + file.write("content").expect("write"); + + let link_path = fs.base().join("bar"); + let link = fs.path(&link_path); + file.soft_link(&link).expect("soft_link"); + + let exists = link.exists().expect("exists"); + assert!(exists); + + let is_link = link.is_link().expect("is_link"); + assert!(is_link); + + Ok(()) + } + #[test] fn create_hard_link() -> TestResult { let fs = fs::temp().expect("temp fs"); @@ -633,16 +669,18 @@ mod canonicalize { #[test] fn should_resolve_symlinks() -> TestResult { let fs = fs::temp().expect("temp fs"); - let path = fs.base().join("foo"); - let file = fs.file(&path); + 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.symlink(&link_path); - link.create_to(&file).expect("create"); + let link = fs.path(&link_path); + file.soft_link(&link).expect("soft_link"); + let canonical = link.canonicalize().expect("canonicalize"); // macos puts all temp files under /private let canonical = Path::new("/").join(canonical.strip_prefix("/private").unwrap()); - assert_eq!(canonical, path); + assert_eq!(canonical, file_path); Ok(()) }