diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f6a7b52 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,121 @@ +on: + push: + branches: + - master + pull_request: {} + +name: Continuous integration + +jobs: + check: + name: Check + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + override: true + - uses: actions-rs/cargo@v1 + with: + command: check + + test-features: + name: Test Suite + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + - uses: actions-rs/cargo@v1 + with: + command: test + args: --all-features + - uses: actions-rs/cargo@v1 + with: + command: test + args: --no-default-features + + test-versions: + name: Test Suite + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + - beta + - nightly + - 1.39.0 + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + + test-os: + name: Test Suite + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + override: true + profile: minimal + - uses: actions-rs/cargo@v1 + with: + command: test + + fmt: + name: Rustfmt + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + override: true + - run: rustup component add rustfmt + - uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + + clippy: + name: Clippy + runs-on: ubuntu-latest + strategy: + matrix: + rust: + - stable + steps: + - uses: actions/checkout@v1 + - uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.rust }} + override: true + - run: rustup component add clippy + - uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-targets --all-features -- -D warnings diff --git a/Cargo.toml b/Cargo.toml index da23a6b..656d278 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "simple-eyre" -version = "0.1.0" +version = "0.2.0" authors = ["Jane Lusby "] edition = "2018" license = "MIT OR Apache-2.0" @@ -10,12 +10,9 @@ homepage = "https://github.com/yaahc/simple-eyre" documentation = "https://docs.rs/simple-eyre" keywords = ["error"] description = """ -One of the simplest error types one can build ontop of eyre, including only an -inner error boxed as a trait object and a context with only a Backtrace +One of the simplest error reporters one can build ontop of eyre, defining only an error report """ -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -eyre-impl = "0.1.0" -thiserror = "1.0.10" +eyre = "0.4.2" +indenter = "0.3.0" diff --git a/README.md b/README.md index a68085a..523f8c9 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,14 @@ Simple-Eyre [![Latest Version](https://img.shields.io/crates/v/simple-eyre.svg)](https://crates.io/crates/simple-eyre) [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/simple-eyre) +This library provides a custom [`eyre::EyreContext`] type for usage with +[`eyre`] that provides a minimal error report with no additional context. +Essentially the minimal implementation of an error reporter. + ```toml [dependencies] -simple-eyre = "0.1" +eyre = "0.4" +simple-eyre = "0.2" ```
@@ -14,22 +19,18 @@ simple-eyre = "0.1" ## Example ```rust -fn eyre::ErrReport; +use eyre::{eyre, WrapErr}; +use simple_eyre::Report; -fn find_git_root() -> Result { - find_dir_in_ancestors(".git")?; +fn main() -> Result<(), Report> { + let e: Report = eyre!("oh no this program is just bad!"); + + Err(e).wrap_err("usage example successfully experienced a failure") } ```
-## Details - -- This library is meant to be used as a minimal example of how to use - `eyre-impl`. It implements the absolute minimum necessary to function as a - dynamic error wrapper that associates some context with it. In this case the - context is only a Backtrace. -
#### License @@ -47,6 +48,5 @@ for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. - - - +[`eyre::EyreContext`]: https://docs.rs/eyre/*/eyre/trait.EyreContext.html +[`eyre`]: https://docs.rs/eyre diff --git a/src/lib.rs b/src/lib.rs index d049493..c418f08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,82 +1,116 @@ -#![feature(backtrace)] -use eyre_impl::{ErrorReporter, Indented}; -use std::backtrace::{Backtrace, BacktraceStatus}; -use std::fmt::{self, Write as _}; +//! This library provides a custom [`eyre::EyreContext`] type for usage with [`eyre`] that provides +//! a minimal error report with no additional context. Essentially the minimal implementation of an +//! error reporter. +//! +//! # Example +//! +//! ```rust,should_panic +//! use eyre::{eyre, WrapErr}; +//! use simple_eyre::Report; +//! +//! fn main() -> Result<(), Report> { +//! let e: Report = eyre!("oh no this program is just bad!"); +//! +//! Err(e).wrap_err("usage example successfully experienced a failure") +//! } +//! ``` +//! +//! [`eyre::EyreContext`]: https://docs.rs/eyre/*/eyre/trait.EyreContext.html +//! [`eyre`]: https://docs.rs/eyre +#![doc(html_root_url = "https://docs.rs/simple-eyre/0.2.0")] +#![warn( + missing_debug_implementations, + missing_docs, + missing_doc_code_examples, + rust_2018_idioms, + unreachable_pub, + bad_style, + const_err, + dead_code, + improper_ctypes, + non_shorthand_field_patterns, + no_mangle_generic_items, + overflowing_literals, + path_statements, + patterns_in_fns_without_body, + private_in_public, + unconditional_recursion, + unused, + unused_allocation, + unused_comparisons, + unused_parens, + while_true +)] +use eyre::Chain; +use eyre::EyreContext; +use indenter::indented; +use std::error::Error; +/// A custom context type for minimal error reporting via `eyre` #[derive(Debug)] -pub struct BoxError(Box); +pub struct Context; -impl std::error::Error for BoxError { - fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { - self.0.source() +impl EyreContext for Context { + #[allow(unused_variables)] + fn default(error: &(dyn Error + 'static)) -> Self { + Self } -} -impl fmt::Display for BoxError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Display::fmt(&self.0, f) - } -} - -pub struct Context { - backtrace: Backtrace, -} - -impl Default for Context { - fn default() -> Self { - Self { - backtrace: Backtrace::capture(), - } - } -} - -pub struct ErrReport(ErrorReporter); - -impl From for ErrReport -where - E: std::error::Error + Send + Sync + 'static, -{ - fn from(err: E) -> Self { - ErrReport(ErrorReporter::from(BoxError(Box::new(err)))) - } -} - -impl fmt::Debug for ErrReport { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let error = &self.0.error; + fn debug( + &self, + error: &(dyn Error + 'static), + f: &mut core::fmt::Formatter<'_>, + ) -> core::fmt::Result { + use core::fmt::Write as _; if f.alternate() { - return fmt::Debug::fmt(error, f); + return core::fmt::Debug::fmt(error, f); } - let errors = self.0.chain().rev().enumerate(); + write!(f, "{}", error)?; - writeln!(f)?; - - for (n, error) in errors { - write!(Indented::numbered(f, n), "{}", error)?; - writeln!(f)?; - } - - let backtrace = &self.0.context.backtrace; - if let BacktraceStatus::Captured = backtrace.status() { - write!(f, "\n\n{}", backtrace)?; - } - - Ok(()) - } -} - -impl fmt::Display for ErrReport { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.0.error)?; - - if f.alternate() { - for cause in self.0.chain().skip(1) { - write!(f, ": {}", cause)?; + if let Some(cause) = error.source() { + write!(f, "\n\nCaused by:")?; + let multiple = cause.source().is_some(); + for (n, error) in Chain::new(cause).enumerate() { + writeln!(f)?; + if multiple { + write!(indented(f).ind(n), "{}", error)?; + } else { + write!(indented(f), "{}", error)?; + } } } Ok(()) } } + +/// A type alias for `eyre::Report` +/// +/// # Example +/// +/// ```rust +/// use simple_eyre::Report; +/// +/// # struct Config; +/// fn try_thing(path: &str) -> Result { +/// // ... +/// # Ok(Config) +/// } +/// ``` +pub type Report = eyre::Report; + +/// A type alias for `Result` +/// +/// # Example +/// +///``` +/// fn main() -> simple_eyre::Result<()> { +/// +/// // ... +/// +/// Ok(()) +/// } +/// ``` +pub type Result = core::result::Result;