Skip to content

Commit

Permalink
Show source by default, add feature to hide it
Browse files Browse the repository at this point in the history
close andrewhickman#59

Changes the default behavior so that the output in the readme now matches the output a user would see when they use the library. Specifically, it now includes the original `std::io::Error` in the output.

It introduces a feature `anyhow`. By default:

- By default: fs-err will include `std::io::Error` in the Display output, and return `None` from `Error::source()`
- With `anyhow` fs-err will not include std::io::Error in the Display output, and return `Some(std::io::Error)` from `Error::source()`

This is based on the guidance from andrewhickman#51. That discussion links to this 2020 discussion rust-lang/project-error-handling#23 that suggests that you should either print the source and return `None` from `Error::source()` (https://doc.rust-lang.org/std/error/trait.Error.html#method.source) or not print anything and return `Some(E)`.

This allows users of anyhow (or similar) libraries to configure fs-err for the behavior they desire, while not hiding information by default from unsuspecting adopters that are not using those libraries. It optimizes for the case of accidentally showing extra information that a user can then investigate and disable, rather than hiding information that the user might not realize is missing.
  • Loading branch information
schneems committed Oct 18, 2024
1 parent 7a49316 commit b2179c1
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 2 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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))
Expand Down
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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}}"
Expand Down
26 changes: 24 additions & 2 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
}

Expand All @@ -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)
}
Expand Down Expand Up @@ -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(())
}
}

Expand All @@ -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)
}
Expand Down
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit b2179c1

Please sign in to comment.