feat(fs): add tracing
This commit is contained in:
parent
c6f167dc16
commit
6e5ea556a9
9 changed files with 127 additions and 20 deletions
|
@ -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 = [
|
||||
|
|
|
@ -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<Box<dyn Iterator<Item = Result<DirItem>>>> {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,11 @@ impl Iterator for DirItemIterator {
|
|||
}
|
||||
|
||||
fn map_dir_item(item: std::io::Result<DirEntry>) -> super::Result<DirItem> {
|
||||
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() {
|
||||
|
|
|
@ -17,6 +17,7 @@ impl FileHandle {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument]
|
||||
pub fn reader(&self) -> Result<Reader> {
|
||||
self.check_error()?;
|
||||
Reader::new(&self.as_pathbuf())
|
||||
|
@ -35,9 +36,12 @@ impl FileHandle {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn write<C: AsRef<[u8]>>(&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<u64> {
|
||||
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<PathHandle<PathMarker>> for FileHandle {
|
||||
|
|
|
@ -83,7 +83,9 @@ pub use temp::TempFileSystem;
|
|||
/// `error::Error::PathTraversal` error when attempting the
|
||||
/// opertation.
|
||||
pub fn new(base: impl Into<PathBuf>) -> FileSystem {
|
||||
FileSystem::new(base.into())
|
||||
let base = base.into();
|
||||
tracing::debug!(?base, "new");
|
||||
FileSystem::new(base)
|
||||
}
|
||||
|
||||
/// Creates a new `TempFileSystem` for a temporary directory.
|
||||
|
|
|
@ -38,10 +38,12 @@ pub struct PathReal<T: PathType> {
|
|||
pub(super) error: Option<Error>,
|
||||
}
|
||||
impl<T: PathType> PathReal<T> {
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub(super) fn new(base: impl Into<PathBuf>, path: impl Into<PathBuf>) -> Self {
|
||||
let base: PathBuf = base.into();
|
||||
let path: PathBuf = path.into();
|
||||
let error = PathReal::<T>::validate(&base, &path);
|
||||
tracing::debug!(?base, ?path, ?error, "new");
|
||||
Self {
|
||||
base,
|
||||
path,
|
||||
|
@ -66,6 +68,7 @@ impl<T: PathType> PathReal<T> {
|
|||
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<T: PathType> PathReal<T> {
|
|||
}
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
fn clean_path(path: &Path) -> Result<PathBuf> {
|
||||
// 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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn exists(&self) -> Result<bool> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn is_dir(&self) -> Result<bool> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn is_file(&self) -> Result<bool> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn as_dir(&self) -> Result<Option<DirHandle>> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn as_file(&self) -> Result<Option<FileHandle>> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn rename(&self, dest: &PathHandle<T>) -> 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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn metadata(&self) -> Result<std::fs::Metadata> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
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)
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn is_link(&self) -> Result<bool> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn canonicalize(&self) -> Result<PathBuf> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[tracing::instrument(skip_all)]
|
||||
pub fn symlink_metadata(&self) -> Result<std::fs::Metadata> {
|
||||
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<T: PathType> PathReal<T> {
|
|||
/// # 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<PathReal<PathMarker>> {
|
||||
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))
|
||||
}
|
||||
|
|
|
@ -11,8 +11,11 @@ pub struct Reader {
|
|||
contents: String,
|
||||
}
|
||||
impl Reader {
|
||||
#[tracing::instrument]
|
||||
pub(super) fn new(path: &Path) -> Result<Self> {
|
||||
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 })
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ impl FileSystem {
|
|||
}
|
||||
|
||||
/// Returns a [PathBuf] for the path.
|
||||
#[tracing::instrument]
|
||||
pub fn path_of(&self, path: PathBuf) -> Result<PathBuf> {
|
||||
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<PathMarker> {
|
||||
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<PathBuf> {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ pub struct TempFileSystem {
|
|||
_temp_dir: Arc<Mutex<TempDir>>,
|
||||
}
|
||||
impl TempFileSystem {
|
||||
#[tracing::instrument]
|
||||
pub fn new() -> super::Result<Self> {
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue