diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 798422a..64aae50 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -67,3 +67,9 @@ jobs: command: check args: --features tokio if: ${{ matrix.rust_version == 'stable' || matrix.rust_version == 'beta' }} + + - name: cargo check --features anyhow + uses: actions-rs/cargo@v1 + with: + command: check + args: --features anyhow diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ad5ccc..7db14a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # fs-err Changelog +* Change errors to output original `std::io::Error` information Display by default. This functionality can be disabled for [anyhow](https://docs.rs/anyhow/latest/anyhow/) users by using the new feature `anyhow` ([#60](https://github.com/andrewhickman/fs-err/pull/60)). + ## 2.11.0 * Added the first line of the standard library documentation to each function's rustdocs, to make them more useful in IDEs ([#50](https://github.com/andrewhickman/fs-err/issues/45)) diff --git a/Cargo.toml b/Cargo.toml index 6c999e3..4d8cf44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,9 @@ serde_json = "1.0.64" [features] # Adds I/O safety traits, introduced in Rust 1.63 io_safety = [] +# Removes the original error text from Display and relies on a wrapper library +# (such as anyhow) to emit them via `Error::source()`. +anyhow = [] [package.metadata.release] tag-name = "{{version}}" diff --git a/src/errors.rs b/src/errors.rs index 22a0eaa..a8318d0 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -99,7 +99,12 @@ impl fmt::Display for Error { E::ReadAt => write!(formatter, "failed to read with offset from `{}`", path), #[cfg(unix)] E::WriteAt => write!(formatter, "failed to write with offset to `{}`", path), - } + }?; + + #[cfg(not(feature = "anyhow"))] + write!(formatter, " caused by: {}", self.source)?; + + Ok(()) } } @@ -108,6 +113,12 @@ impl StdError for Error { self.source() } + #[cfg(not(feature = "anyhow"))] + fn source(&self) -> Option<&(dyn StdError + 'static)> { + None + } + + #[cfg(feature = "anyhow")] fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(&self.source) } @@ -188,7 +199,12 @@ impl fmt::Display for SourceDestError { SourceDestErrorKind::SymlinkDir => { write!(formatter, "failed to symlink dir from {} to {}", from, to) } - } + }?; + + #[cfg(not(feature = "anyhow"))] + write!(formatter, " caused by: {}", self.source)?; + + Ok(()) } } @@ -197,6 +213,12 @@ impl StdError for SourceDestError { self.source() } + #[cfg(not(feature = "anyhow"))] + fn source(&self) -> Option<&(dyn StdError + 'static)> { + None + } + + #[cfg(feature = "anyhow")] fn source(&self) -> Option<&(dyn StdError + 'static)> { Some(&self.source) } diff --git a/src/lib.rs b/src/lib.rs index 19b8c8d..991dd52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,6 +26,10 @@ failed to open file `does not exist.txt` caused by: The system cannot find the file specified. (os error 2) ``` +> Note: To bypass displaying the original error message you can enable the `anyhow` feature. +> When the `anyhow` feature is enabled `Error::source()` will return `Some` and the original +> error will not be `Display`-ed via fs-err. + # Usage fs-err's API is the same as [`std::fs`][std::fs], so migrating code to use it is easy.