diff --git a/Cargo.toml b/Cargo.toml index cf70139..bd16910 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,9 +27,11 @@ reqwest = { version = "0.12", features = [ "json" ] } url = "2.5" tempfile = "3.10" tokio = { version = "1.41", features = [ "sync" ] } +tracing = "0.1" [dev-dependencies] assert2 = "0.3" +mutants = "0.0" pretty_assertions = "1.4" test-log = "0.2" tokio = { version = "1.41", features = [ diff --git a/src/fs/dir.rs b/src/fs/dir.rs index 194d31e..b802a4f 100644 --- a/src/fs/dir.rs +++ b/src/fs/dir.rs @@ -1,6 +1,6 @@ +// use std::fmt::Display; -// use crate::fs::{DirItem, DirItemIterator, Result}; use super::{DirHandle, Error, PathHandle, PathMarker}; @@ -19,8 +19,10 @@ impl DirHandle { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn create(&self) -> Result<()> { self.check_error()?; + tracing::debug!("std::fs::create_dir"); std::fs::create_dir(self.as_pathbuf()).map_err(Error::Io) } @@ -37,8 +39,10 @@ impl DirHandle { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn create_all(&self) -> Result<()> { self.check_error()?; + tracing::debug!("std::fs::create_dir_all"); std::fs::create_dir_all(self.as_pathbuf()).map_err(Error::Io) } @@ -55,8 +59,10 @@ impl DirHandle { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn read(&self) -> Result>>> { self.check_error()?; + tracing::debug!("std::fs::read_dir"); let read_dir = std::fs::read_dir(self.as_pathbuf()).map_err(Error::Io)?; Ok(Box::new(DirItemIterator::new(read_dir))) } @@ -73,8 +79,10 @@ impl DirHandle { /// dir.remove()?; /// # Ok(()) /// } + #[tracing::instrument] pub fn remove(&self) -> Result<()> { self.check_error()?; + tracing::debug!("std::fs::remove"); std::fs::remove_dir(self.as_pathbuf()).map_err(Error::Io) } @@ -90,8 +98,10 @@ impl DirHandle { /// dir.remove_all()?; /// # Ok(()) /// } + #[tracing::instrument] pub fn remove_all(&self) -> Result<()> { self.check_error()?; + tracing::debug!("std::fs::remove_all"); std::fs::remove_dir_all(self.as_pathbuf()).map_err(Error::Io) } } diff --git a/src/fs/dir_item.rs b/src/fs/dir_item.rs index daad67d..972ab04 100644 --- a/src/fs/dir_item.rs +++ b/src/fs/dir_item.rs @@ -28,8 +28,11 @@ impl Iterator for DirItemIterator { } fn map_dir_item(item: std::io::Result) -> super::Result { + tracing::trace!("map_dir_item"); let item = item.map_err(Error::Io)?; + tracing::trace!(?item, "map_dir_item"); let file_type = item.file_type().map_err(Error::Io)?; + tracing::trace!(?file_type, "map_dir_item"); if file_type.is_dir() { Ok(DirItem::Dir(item.path())) } else if file_type.is_file() { diff --git a/src/fs/file.rs b/src/fs/file.rs index d96a205..86a9385 100644 --- a/src/fs/file.rs +++ b/src/fs/file.rs @@ -17,6 +17,7 @@ impl FileHandle { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn reader(&self) -> Result { self.check_error()?; Reader::new(&self.as_pathbuf()) @@ -35,9 +36,12 @@ impl FileHandle { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn write>(&self, contents: C) -> Result<()> { self.check_error()?; - std::fs::write(self.as_pathbuf(), contents).map_err(Error::Io) + let file = self.as_pathbuf(); + tracing::debug!(?file, "std::fs::write"); + std::fs::write(file, contents).map_err(Error::Io) } /// Copies the contents of a file to another file. @@ -56,9 +60,13 @@ impl FileHandle { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn copy(&self, dest: &FileHandle) -> Result { self.check_error()?; - std::fs::copy(self.as_pathbuf(), dest.as_pathbuf()).map_err(Error::Io) + let from = self.as_pathbuf(); + let to = dest.as_pathbuf(); + tracing::debug!(?from, ?to, "std::fs::copy"); + std::fs::copy(from, to).map_err(Error::Io) } /// Removes a file. @@ -74,9 +82,12 @@ impl FileHandle { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn remove(&self) -> Result<()> { self.check_error()?; - std::fs::remove_file(self.as_pathbuf()).map_err(Error::Io) + let file = self.as_pathbuf(); + tracing::debug!(?file, "std::fs::remove_file"); + std::fs::remove_file(file).map_err(Error::Io) } /// Creates a hard link on the filesystem. @@ -96,9 +107,13 @@ impl FileHandle { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn hard_link(&self, dest: &FileHandle) -> Result<()> { self.check_error()?; - std::fs::hard_link(self.as_pathbuf(), dest.as_pathbuf()).map_err(Error::Io) + let original = self.as_pathbuf(); + let link = dest.as_pathbuf(); + tracing::debug!(?original, ?link, "std::fs::hard_link"); + std::fs::hard_link(original, link).map_err(Error::Io) } } impl TryFrom> for FileHandle { diff --git a/src/fs/mod.rs b/src/fs/mod.rs index df3a4f5..a7dcca8 100644 --- a/src/fs/mod.rs +++ b/src/fs/mod.rs @@ -83,7 +83,9 @@ pub use temp::TempFileSystem; /// `error::Error::PathTraversal` error when attempting the /// opertation. pub fn new(base: impl Into) -> FileSystem { - FileSystem::new(base.into()) + let base = base.into(); + tracing::debug!(?base, "new"); + FileSystem::new(base) } /// Creates a new `TempFileSystem` for a temporary directory. diff --git a/src/fs/path.rs b/src/fs/path.rs index f9e38e4..69ee12b 100644 --- a/src/fs/path.rs +++ b/src/fs/path.rs @@ -38,10 +38,12 @@ pub struct PathReal { pub(super) error: Option, } impl PathReal { + #[tracing::instrument(skip_all)] pub(super) fn new(base: impl Into, path: impl Into) -> Self { let base: PathBuf = base.into(); let path: PathBuf = path.into(); let error = PathReal::::validate(&base, &path); + tracing::debug!(?base, ?path, ?error, "new"); Self { base, path, @@ -66,6 +68,7 @@ impl PathReal { self.base.join(&self.path) } + // only stores the first error, subsequent errors are dropped pub(super) fn put(&mut self, error: Error) { if self.error.is_none() { self.error.replace(error); @@ -87,20 +90,25 @@ impl PathReal { } } + #[tracing::instrument] fn clean_path(path: &Path) -> Result { - // let path = path.as_ref(); use path_clean::PathClean; let abs_path = if path.is_absolute() { + tracing::debug!("is absolute"); path.to_path_buf() } else { + tracing::debug!("std::env::current_dir"); std::env::current_dir().expect("current_dir").join(path) } .clean(); + tracing::debug!(?abs_path); Ok(abs_path) } + #[tracing::instrument(skip_all)] pub(super) fn check_error(&self) -> Result<()> { if let Some(error) = &self.error { + tracing::warn!(?error, "error"); Err(error.clone()) } else { Ok(()) @@ -123,9 +131,12 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn exists(&self) -> Result { self.check_error()?; - Ok(self.as_pathbuf().exists()) + let path = self.as_pathbuf(); + tracing::debug!(?path, "PathBuf::exists"); + Ok(path.exists()) } /// Returns true if the path is a directory. @@ -140,9 +151,12 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn is_dir(&self) -> Result { self.check_error()?; - Ok(self.as_pathbuf().is_dir()) + let path = self.as_pathbuf(); + tracing::debug!(?path, "PathBuf::is_dir"); + Ok(path.is_dir()) } /// Returns true if the path is a file. @@ -157,9 +171,12 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn is_file(&self) -> Result { self.check_error()?; - Ok(self.as_pathbuf().is_file()) + let path = self.as_pathbuf(); + tracing::debug!(?path, "PathBuf::is_file"); + Ok(path.is_file()) } /// Returns the path as a directory if it exists and is a directory, otherwise @@ -176,9 +193,13 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn as_dir(&self) -> Result> { self.check_error()?; - if self.as_pathbuf().is_dir() { + let path = self.as_pathbuf(); + let is_dir = path.is_dir(); + tracing::debug!(?path, ?is_dir, "PathBuf::is_dir"); + if is_dir { Ok(Some(PathReal::new(&self.base, &self.path))) } else { Ok(None) @@ -199,9 +220,13 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn as_file(&self) -> Result> { self.check_error()?; - if self.as_pathbuf().is_file() { + let path = self.as_pathbuf(); + let is_file = path.is_file(); + tracing::debug!(?path, ?is_file, "PathBuf::is_file"); + if is_file { Ok(Some(PathReal::new(&self.base, &self.path))) } else { Ok(None) @@ -225,9 +250,13 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn rename(&self, dest: &PathHandle) -> Result<()> { self.check_error()?; - std::fs::rename(self.as_pathbuf(), dest.as_pathbuf()).map_err(Error::Io) + let from = self.as_pathbuf(); + let to = dest.as_pathbuf(); + tracing::debug!(?from, ?to, "std::fs::rename"); + std::fs::rename(from, to).map_err(Error::Io) } /// Returns the metadata for a path. @@ -243,9 +272,12 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn metadata(&self) -> Result { self.check_error()?; - std::fs::metadata(self.as_pathbuf()).map_err(Error::Io) + let path = self.as_pathbuf(); + tracing::debug!(?path, "std::fs::metadata"); + std::fs::metadata(path).map_err(Error::Io) } /// Creates a symbolic link to a path. @@ -265,9 +297,13 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn soft_link(&self, link: &PathReal) -> Result<()> { self.check_error()?; - std::os::unix::fs::symlink(self.as_pathbuf(), link.as_pathbuf()).map_err(Error::Io) + let original = self.as_pathbuf(); + let link = link.as_pathbuf(); + tracing::debug!(?original, ?link, "std::os::unix::fs::symlink"); + std::os::unix::fs::symlink(original, link).map_err(Error::Io) } /// Returns true if the path is a symbolic link. @@ -283,9 +319,12 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn is_link(&self) -> Result { self.check_error()?; - Ok(self.as_pathbuf().is_symlink()) + let path = self.as_pathbuf(); + tracing::debug!(?path, "PathBuf::is_symlink"); + Ok(path.is_symlink()) } /// Returns the canonical, absolute form of the path with all intermediate @@ -302,9 +341,12 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn canonicalize(&self) -> Result { self.check_error()?; - self.as_pathbuf().canonicalize().map_err(Error::Io) + let path = self.as_pathbuf(); + tracing::debug!(?path, "PathBuf::canonicalize"); + path.canonicalize().map_err(Error::Io) } /// Returns the metadata for a path without following symlinks. @@ -320,9 +362,12 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn symlink_metadata(&self) -> Result { self.check_error()?; - std::fs::symlink_metadata(self.as_pathbuf()).map_err(Error::Io) + let path = self.as_pathbuf(); + tracing::debug!(?path, "std::fs::symlink_metadata"); + std::fs::symlink_metadata(path).map_err(Error::Io) } /// Sets the permissions of a file or directory. @@ -341,14 +386,20 @@ impl PathReal { /// # Ok(()) /// # } /// ``` + #[tracing::instrument(skip_all)] pub fn set_permissions(&self, perms: std::fs::Permissions) -> Result<()> { self.check_error()?; - std::fs::set_permissions(self.as_pathbuf(), perms).map_err(Error::Io) + let path = self.as_pathbuf(); + tracing::debug!(?path, ?perms, "std::fs::set_permissions"); + std::fs::set_permissions(path, perms).map_err(Error::Io) } + #[tracing::instrument(skip_all)] pub fn read_link(&self) -> Result> { self.check_error()?; - let read_path = std::fs::read_link(self.as_pathbuf()).map_err(Error::Io)?; + let path = self.as_pathbuf(); + tracing::debug!(?path, "std::fs::read_link"); + let read_path = std::fs::read_link(path).map_err(Error::Io)?; let path = read_path.strip_prefix(&self.base).unwrap().to_path_buf(); Ok(PathReal::new(&self.base, &path)) } diff --git a/src/fs/reader.rs b/src/fs/reader.rs index 93e2ad2..8cdb6a6 100644 --- a/src/fs/reader.rs +++ b/src/fs/reader.rs @@ -11,8 +11,11 @@ pub struct Reader { contents: String, } impl Reader { + #[tracing::instrument] pub(super) fn new(path: &Path) -> Result { + tracing::debug!("std::fs::read_to_string"); let contents = std::fs::read_to_string(path).map_err(Error::Io)?; + tracing::debug!(len = contents.len(), "contents"); Ok(Self { contents }) } diff --git a/src/fs/system.rs b/src/fs/system.rs index e98cf7c..7d72958 100644 --- a/src/fs/system.rs +++ b/src/fs/system.rs @@ -34,6 +34,7 @@ impl FileSystem { } /// Returns a [PathBuf] for the path. + #[tracing::instrument] pub fn path_of(&self, path: PathBuf) -> Result { let path_of = self.base.as_path().join(path); self.validate(&path_of)?; @@ -55,13 +56,16 @@ impl FileSystem { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn dir(&self, path: &Path) -> DirHandle { let mut dir = PathReal::new(&self.base, path); if dir.error.is_none() { if let Ok(exists) = dir.exists() { + tracing::debug!(?exists); if exists { if let Ok(is_dir) = dir.is_dir() { + tracing::debug!(?is_dir); if !is_dir { dir.put(Error::NotADirectory { path: dir.as_pathbuf(), @@ -90,13 +94,16 @@ impl FileSystem { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn file(&self, path: &Path) -> FileHandle { let mut file = PathReal::new(&self.base, path); if file.error.is_none() { if let Ok(exists) = file.exists() { + tracing::debug!(?exists); if exists { if let Ok(is_file) = file.is_file() { + tracing::debug!(?is_file); if !is_file { file.put(Error::NotAFile { path: file.as_pathbuf(), @@ -124,10 +131,12 @@ impl FileSystem { /// # Ok(()) /// # } /// ``` + #[tracing::instrument] pub fn path(&self, path: &Path) -> PathHandle { PathReal::new(&self.base, path) } + #[tracing::instrument] fn validate(&self, path: &Path) -> Result<()> { let path = self.clean_path(path)?; if !path.starts_with(&self.base) { @@ -139,15 +148,19 @@ impl FileSystem { Ok(()) } + #[tracing::instrument] fn clean_path(&self, path: &Path) -> Result { // let path = path.as_ref(); use path_clean::PathClean; let abs_path = if path.is_absolute() { + tracing::debug!("is_absolute"); path.to_path_buf() } else { + tracing::debug!("std::env::current_dir"); std::env::current_dir().map_err(Error::Io)?.join(path) } .clean(); + tracing::debug!(?abs_path); Ok(abs_path) } } diff --git a/src/fs/temp.rs b/src/fs/temp.rs index 3ab38d1..b5c2369 100644 --- a/src/fs/temp.rs +++ b/src/fs/temp.rs @@ -10,6 +10,7 @@ pub struct TempFileSystem { _temp_dir: Arc>, } impl TempFileSystem { + #[tracing::instrument] pub fn new() -> super::Result { let temp_dir = tempfile::tempdir().map_err(Error::Io)?; let base = temp_dir.path().to_path_buf(); @@ -34,3 +35,10 @@ impl std::ops::Deref for TempFileSystem { &self.real } } +impl Drop for TempFileSystem { + #[cfg_attr(test, mutants::skip)] + #[tracing::instrument] + fn drop(&mut self) { + tracing::debug!("drop"); + } +}