Skip to content

Commit 403f525

Browse files
authored
Merge pull request #1 from yaahc/testing
Merge customization and test via PR
2 parents bac602c + 3b26dac commit 403f525

26 files changed

+815
-572
lines changed

.github/workflows/ci.yml

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
on: [push, pull_request]
2+
3+
name: Continuous integration
4+
5+
jobs:
6+
check:
7+
name: Check
8+
runs-on: ubuntu-latest
9+
strategy:
10+
matrix:
11+
rust:
12+
- stable
13+
- 1.34.0
14+
steps:
15+
- uses: actions/checkout@v1
16+
- uses: actions-rs/toolchain@v1
17+
with:
18+
toolchain: ${{ matrix.rust }}
19+
override: true
20+
- uses: actions-rs/cargo@v1
21+
with:
22+
command: check
23+
24+
test:
25+
name: Test Suite
26+
runs-on: ubuntu-latest
27+
strategy:
28+
matrix:
29+
rust:
30+
- stable
31+
- nightly
32+
- 1.34.0
33+
steps:
34+
- uses: actions/checkout@v1
35+
- uses: actions-rs/toolchain@v1
36+
with:
37+
toolchain: ${{ matrix.rust }}
38+
override: true
39+
- uses: actions-rs/cargo@v1
40+
with:
41+
command: test
42+
# - uses: actions-rs/cargo@v1
43+
# with:
44+
# command: test
45+
# args: --no-default-features
46+
47+
fmt:
48+
name: Rustfmt
49+
runs-on: ubuntu-latest
50+
strategy:
51+
matrix:
52+
rust:
53+
- stable
54+
- 1.34.0
55+
steps:
56+
- uses: actions/checkout@v1
57+
- uses: actions-rs/toolchain@v1
58+
with:
59+
toolchain: ${{ matrix.rust }}
60+
override: true
61+
- run: rustup component add rustfmt
62+
- uses: actions-rs/cargo@v1
63+
with:
64+
command: fmt
65+
args: --all -- --check
66+
67+
clippy:
68+
name: Clippy
69+
runs-on: ubuntu-latest
70+
strategy:
71+
matrix:
72+
rust:
73+
- stable
74+
- 1.34.0
75+
steps:
76+
- uses: actions/checkout@v1
77+
- uses: actions-rs/toolchain@v1
78+
with:
79+
toolchain: ${{ matrix.rust }}
80+
override: true
81+
- run: rustup component add clippy
82+
- uses: actions-rs/cargo@v1
83+
with:
84+
command: clippy
85+
args: -- -D warnings

.travis.yml

Lines changed: 0 additions & 22 deletions
This file was deleted.

Cargo.toml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
[package]
2-
name = "anyhow"
3-
version = "1.0.26" # remember to update html_root_url
4-
authors = ["David Tolnay <[email protected]>"]
2+
name = "eyre"
3+
version = "0.2.0" # remember to update html_root_url
4+
authors = ["David Tolnay <[email protected]>", "Jane Lusby <[email protected]>"]
55
edition = "2018"
66
license = "MIT OR Apache-2.0"
7-
description = "Flexible concrete Error type built on std::error::Error"
8-
repository = "https://github.com/dtolnay/anyhow"
9-
documentation = "https://docs.rs/anyhow"
7+
description = "Flexible concrete Error Handling and Reporting type built on std::error::Error"
8+
repository = "https://github.com/yaahc/eyre"
9+
documentation = "https://docs.rs/eyre"
1010
readme = "README.md"
1111
categories = ["rust-patterns"]
1212

13-
[badges]
14-
travis-ci = { repository = "dtolnay/anyhow" }
15-
1613
[features]
1714
default = ["std"]
1815
std = []

README.md

Lines changed: 149 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,142 @@
1-
Anyhow&ensp;¯\\\_(ツ)\_
1+
Eyre&ensp;¯\\\_(ツ)\_
22
=========================
33

4-
[![Build Status](https://api.travis-ci.com/dtolnay/anyhow.svg?branch=master)](https://travis-ci.com/dtolnay/anyhow)
5-
[![Latest Version](https://img.shields.io/crates/v/anyhow.svg)](https://crates.io/crates/anyhow)
6-
[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/anyhow)
4+
[![Build Status][actions-badge]][actions-url]
5+
[![Latest Version](https://img.shields.io/crates/v/eyre.svg)](https://crates.io/crates/eyre)
6+
[![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/eyre)
7+
8+
This library provides [`eyre::ErrReport`][ErrReport], a trait object based
9+
error handling type for easy idiomatic error handling and reporting in Rust
10+
applications.
11+
12+
First and foremost, this crate is a fork of `anyhow` by @dtolnay. My goal in
13+
writing this crate is to explore new directions of handling context and to
14+
explore new ways to communicate the intended usage of this crate via changes to
15+
the API.
16+
17+
The main changes this crate brings to anyhow are
18+
19+
* Addition of the [`eyre::EyreContext`] trait and a type parameter on the core error
20+
handling type which users can use to insert custom forms of context into
21+
their general error type.
22+
* Rebranding the type as principally for error reporting, rather than
23+
describing it as an error type in its own right. This type is not an error,
24+
it contains errors that it masqerades as, and provides helpers for creating
25+
new errors to wrap those errors and for displaying those chains of errors,
26+
and the included context, to the end user. The goal is to make it obvious
27+
that this type is meant to be used when the only way you expect to handle
28+
errors is to print them.
29+
* Changing the [`anyhow::Context`] trait to [`eyre::WrapErr`] to make it clear
30+
that it is unrelated to the [`eyre::EyreContext`] and the context member, and
31+
is only for inserting new errors into the chain of errors.
32+
* Addition of a new `context` function on [`eyre::ErrReport`] to assist with
33+
extracting members from the inner Context, which is used by
34+
[`eyre::ErrReport`] to extract [`std::backtrace::Backtrace`]'s from generic
35+
contexts types.
36+
37+
These changes were made in order to facilitate the usage of
38+
[`tracing::SpanTrace`] with anyhow, which is a Backtrace-like type for
39+
rendering custom defined runtime context.
40+
41+
**Note**: The way the `eyre!` macro works in practice differs from how
42+
`anyhow!` works due to the addition of the generic type parameter. In anyhow
43+
the following is valid.
44+
45+
```rust
46+
let val = get_optional_val.ok_or_else(|| anyhow!("failed to get value)).unwrap();
47+
```
48+
49+
Where as with `eyre!` this will fail due to being unable to infer the type for
50+
the Context parameter. The solution to this problem, should you encounter it,
51+
is to give the compiler a hint for what type it should be resolving to, either
52+
via your return type or a type annotation.
53+
54+
```rust
55+
// Will work fine
56+
let val: ErrReport = get_optional_val.ok_or_else(|| eyre!("failed to get value)).unwrap();
57+
```
58+
59+
[ErrReport]: https://docs.rs/eyre/1.0/eyre/struct.ErrReport.html
60+
[actions-badge]: https://github.com/yaahc/eyre/workflows/ci/badge.svg
61+
[actions-url]:https://github.com/yaahc/eyre/actions?query=workflow%3Aci
62+
63+
## Customization
64+
65+
In order to insert your own custom context type you must first implement the
66+
`eyre::EyreContext` trait for said type, which has four required methods.
67+
68+
* `fn default(error: &Error) -> Self` - For constructing default context while
69+
allowing special case handling depending on the content of the error you're
70+
wrapping.
71+
72+
This is essentially `Default::default` but more flexible, for example, the
73+
`eyre::DefaultContext` type provide by this crate uses this to only capture a
74+
`Backtrace` if the inner `Error` does not already have one.
75+
76+
```rust
77+
fn default(error: &(dyn StdError + 'static)) -> Self {
78+
let backtrace = backtrace_if_absent!(error);
79+
80+
Self { backtrace }
81+
}
82+
```
83+
84+
* `fn context_raw(&self, typeid TypeID) -> Option<&dyn Any>` - For extracting
85+
arbitrary members from a context based on their type.
786

8-
This library provides [`anyhow::Error`][Error], a trait object based error type
9-
for easy idiomatic error handling in Rust applications.
87+
This method is like a flexible version of the `fn backtrace(&self)` method on
88+
the `Error` trait. In the future we will likely support extracting `Backtrace`s
89+
and `SpanTrace`s by default by relying on the implementation of `context_raw`
90+
provided by the user.
1091

11-
[Error]: https://docs.rs/anyhow/1.0/anyhow/struct.Error.html
92+
93+
Here is how the `eyre::DefaultContext` type uses this to return `Backtrace`s.
94+
95+
```rust
96+
fn context_raw(&self, typeid: TypeId) -> Option<&dyn Any> {
97+
if typeid == TypeId::of::<Backtrace>() {
98+
self.backtrace.as_ref().map(|b| b as &dyn Any)
99+
} else {
100+
None
101+
}
102+
}
103+
```
104+
105+
* `fn debug(&self, error: &(dyn Error + 'static), f: &mut fmt::Formatter<'_>) -> fmt Result`
106+
it's companion `display` version. - For formatting the entire error chain and
107+
the user provided context.
108+
109+
When overriding the context it no longer makes sense for `eyre::ErrReport` to
110+
provide the `Display` and `Debug` implementations for the user, becase we
111+
cannot predict what forms of context you will need to display along side your
112+
chain of errors. Instead we forward the implementations of `Display` and
113+
`Debug` to these methods on the inner `EyreContext` type.
114+
115+
This crate does provide a few helpers to assist in writing display
116+
implementations, specifically the `Chain` type, for treating an error and its
117+
sources like an iterator, and the `Indented` type, for indenting multi line
118+
errors consistently without using heap allocations.
119+
120+
**Note**: best practices for printing errors suggest that `{}` should only
121+
print the current error and none of its sources, and that the primary method of
122+
displaying an error, its sources, and its context should be handled by the
123+
`Debug` implementation, which is what is used to print errors that are returned
124+
from `main`. For examples on how to implement this please refer to the
125+
implementations of `display` and `debug` on `eyre::DefaultContext`
126+
127+
Once you've defined a custom Context type you can use it throughout your
128+
application by defining a type alias.
129+
130+
```rust
131+
type ErrReport = eyre::ErrReport<MyContext>;
132+
133+
// And optionally...
134+
type Result<T, E = eyre::ErrReport<MyContext>> = core::result::Result<T, E>;
135+
```
12136

13137
```toml
14138
[dependencies]
15-
anyhow = "1.0"
139+
eyre = "0.2"
16140
```
17141

18142
*Compiler support: requires rustc 1.34+*
@@ -21,14 +145,14 @@ anyhow = "1.0"
21145

22146
## Details
23147

24-
- Use `Result<T, anyhow::Error>`, or equivalently `anyhow::Result<T>`, as the
148+
- Use `Result<T, eyre::ErrReport>`, or equivalently `eyre::Result<T>`, as the
25149
return type of any fallible function.
26150

27151
Within the function, use `?` to easily propagate any error that implements the
28152
`std::error::Error` trait.
29153

30154
```rust
31-
use anyhow::Result;
155+
use eyre::Result;
32156

33157
fn get_cluster_info() -> Result<ClusterMap> {
34158
let config = std::fs::read_to_string("cluster.json")?;
@@ -43,7 +167,7 @@ anyhow = "1.0"
43167
application was in the middle of.
44168

45169
```rust
46-
use anyhow::{Context, Result};
170+
use eyre::{WrapErr, Result};
47171

48172
fn main() -> Result<()> {
49173
...
@@ -78,7 +202,7 @@ anyhow = "1.0"
78202
type does not already provide its own. In order to see backtraces, the
79203
`RUST_LIB_BACKTRACE=1` environment variable must be defined.
80204

81-
- Anyhow works with any error type that has an impl of `std::error::Error`,
205+
- Eyre works with any error type that has an impl of `std::error::Error`,
82206
including ones defined in your crate. We do not bundle a `derive(Error)` macro
83207
but you can write the impls yourself or use a standalone macro like
84208
[thiserror].
@@ -98,36 +222,40 @@ anyhow = "1.0"
98222
}
99223
```
100224

101-
- One-off error messages can be constructed using the `anyhow!` macro, which
102-
supports string interpolation and produces an `anyhow::Error`.
225+
- One-off error messages can be constructed using the `eyre!` macro, which
226+
supports string interpolation and produces an `eyre::ErrReport`.
103227

104228
```rust
105-
return Err(anyhow!("Missing attribute: {}", missing));
229+
return Err(eyre!("Missing attribute: {}", missing));
106230
```
107231

108232
<br>
109233

110234
## No-std support
111235

236+
**NOTE**: tests are currently broken for `no_std` so I cannot guaruntee that
237+
everything works still. I'm waiting for upstream fixes to be merged rather than
238+
fixing them myself, so bear with me.
239+
112240
In no_std mode, the same API is almost all available and works the same way. To
113-
depend on Anyhow in no_std mode, disable our default enabled "std" feature in
241+
depend on Eyre in no_std mode, disable our default enabled "std" feature in
114242
Cargo.toml. A global allocator is required.
115243

116244
```toml
117245
[dependencies]
118-
anyhow = { version = "1.0", default-features = false }
246+
eyre = { version = "0.2", default-features = false }
119247
```
120248

121249
Since the `?`-based error conversions would normally rely on the
122250
`std::error::Error` trait which is only available through std, no_std mode will
123-
require an explicit `.map_err(Error::msg)` when working with a non-Anyhow error
124-
type inside a function that returns Anyhow's error type.
251+
require an explicit `.map_err(ErrReport::msg)` when working with a non-Eyre error
252+
type inside a function that returns Eyre's error type.
125253

126254
<br>
127255

128256
## Comparison to failure
129257

130-
The `anyhow::Error` type works something like `failure::Error`, but unlike
258+
The `eyre::ErrReport` type works something like `failure::Error`, but unlike
131259
failure ours is built around the standard library's `std::error::Error` trait
132260
rather than a separate trait `failure::Fail`. The standard library has adopted
133261
the necessary improvements for this to be possible as part of [RFC 2504].
@@ -138,7 +266,7 @@ the necessary improvements for this to be possible as part of [RFC 2504].
138266

139267
## Comparison to thiserror
140268

141-
Use Anyhow if you don't care what error type your functions return, you just
269+
Use Eyre if you don't care what error type your functions return, you just
142270
want it to be easy. This is common in application code. Use [thiserror] if you
143271
are a library that wants to design your own dedicated error type(s) so that on
144272
failures the caller gets exactly the information that you choose.

build.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::process::{Command, ExitStatus};
55

66
// This code exercises the surface area that we expect of the std Backtrace
77
// type. If the current toolchain is able to compile it, we go ahead and use
8-
// backtrace in anyhow.
8+
// backtrace in eyre.
99
const PROBE: &str = r#"
1010
#![feature(backtrace)]
1111
#![allow(dead_code)]
@@ -51,7 +51,7 @@ fn compile_probe() -> Option<ExitStatus> {
5151
fs::write(&probefile, PROBE).ok()?;
5252
Command::new(rustc)
5353
.arg("--edition=2018")
54-
.arg("--crate-name=anyhow_build")
54+
.arg("--crate-name=eyre_build")
5555
.arg("--crate-type=lib")
5656
.arg("--emit=metadata")
5757
.arg("--out-dir")

0 commit comments

Comments
 (0)