Skip to content
This repository has been archived by the owner on Aug 1, 2024. It is now read-only.

Example of how to call color_eyre::install() multiple times safely. #118

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- next-header -->

## [Unreleased] - ReleaseDate
### Added
- Example of how to use OnceCell to initialize color_eyre

## [0.6.2] - 2022-07-11
### Added
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ tracing = "0.1.13"
pretty_assertions = "1.0.0"
thiserror = "1.0.19"
ansi-parser = "0.8.0"
ctor = "0.1"

[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
wasm-bindgen-test = "0.3.15"
Expand Down
98 changes: 98 additions & 0 deletions examples/cargo_tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//!
//! Try it out with cargo test --example cargo_tests -- --nocapture

use color_eyre::eyre::Result;
use eyre::bail;
use tracing::info;

fn do_some_work_well() -> Result<()> {
info!("Doing some work.");
Ok(())
}

fn do_some_work_badly() -> Result<()> {
bail!("Something went wrong")
}

fn main() -> Result<()> {
do_some_work_well()?;
do_some_work_badly()?;
Ok(())
}
/// # Introduction
/// The following module requires copying the init_color_eyre() to every test
/// function that uses it. This is a bit of a pain, but it's not a big deal.
/// However, if you wanted to avoid it you could use the
/// [ctor crate method](#ctor-method) below .


#[cfg(test)]
mod tests {
use super::*;

pub mod some_common_spot {
use once_cell::sync::OnceCell;

pub struct ColorEyreGuard(());
static INIT_COLOR_EYRE: OnceCell<ColorEyreGuard> = OnceCell::new();

pub fn init_color_eyre() {
INIT_COLOR_EYRE.get_or_init(|| {
if std::env::var("RUST_SPANTRACE").is_err() {
std::env::set_var("RUST_SPANTRACE", "0");
}
// Run with RUST_BACKTRACE=1 to see the backtrace.
if std::env::var("RUST_BACKTRACE").is_err() {
std::env::set_var("RUST_BACKTRACE", "0");
}
if std::env::var("COLOR_EYRE").is_err() {
std::env::set_var("COLOR_EYRE", "1");
}
if std::env::var("COLOR_EYRE").unwrap() == "1" {
color_eyre::install().expect("Failed to initialize color_eyre");
}
ColorEyreGuard(())
});
}
}


#[test]
#[should_panic]
fn test_eyre_init() {
#[cfg(not(with_ctor))]
some_common_spot::init_color_eyre();
do_some_work_badly().unwrap();
assert!(true);
}

/// ## Ctor Method
/// You can run the tests below with the following command:
/// ```rust
/// RUSTFLAGS="--cfg with_ctor" cargo test --example cargo_tests -- --nocapture
/// ```
#[cfg(with_ctor)]
#[test]
#[should_panic(expected = "Something went wrong")]
fn no_need_to_call_init_color_eyre() {
// do not have to call some_common_spot::init_color_eyre();
do_some_work_badly().unwrap();
assert!(true);
}

#[cfg(with_ctor)]
#[ctor::ctor]
/// Initializes color_eyre the tests run.
/// Note that this approach assumes that other constructors that
/// may panic, would still use the method above to initialize color_eyre
/// because the order in which constructors execute is random.
/// Which is why we still use the OnceCell guard.
/// If you are certain that no other constructor is interested in
/// initializing color_eyre, you simply call the color_eyre::install()
/// directly, and then remove the OnceCell guard.
fn __init_color_eyre_ctor() {
some_common_spot::init_color_eyre();
}


}
2 changes: 1 addition & 1 deletion examples/theme_test_helper.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Nothing interesting here. This is just a small helper used in a test.

//! This needs to be an "example" until binaries can declare separate dependencies (see https://github.com/rust-lang/cargo/issues/1982)
//! This needs to be an "example" until binaries can declare separate dependencies (see <https://github.com/rust-lang/cargo/issues/1982>)

//! See "tests/theme.rs" for more information.

Expand Down
22 changes: 22 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,7 @@
//! [`examples/custom_filter.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/custom_filter.rs
//! [`examples/custom_section.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/custom_section.rs
//! [`examples/multiple_errors.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/multiple_errors.rs
//! [`examples/cargo_tests.rs`]: https://github.com/yaahc/color-eyre/blob/master/examples/cargo_tests.rs
#![doc(html_root_url = "https://docs.rs/color-eyre/0.6.2")]
#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(
Expand Down Expand Up @@ -458,6 +459,27 @@ pub enum ErrorKind<'a> {
/// # Ok(())
/// }
/// ```
/// If you need to potentially call `install` multiple times, (e.g. for
/// `cargo test`) you can use `once_cell::sync::OnceCell` to ensure that the
/// installation is only done once. For example:
///
/// ```rust
/// use once_cell::sync::OnceCell;
/// pub struct ColorEyreGuard(());
/// static INIT_COLOR_EYRE: OnceCell<ColorEyreGuard> = OnceCell::new();
///
/// pub fn init_color_eyre() {
/// INIT_COLOR_EYRE.get_or_init(|| {
/// color_eyre::install().expect("Failed to initialize color_eyre");
/// ColorEyreGuard(())
/// });
/// }
/// ```
/// and then you can call init_color_eyre from multiple spots without worrying
/// about it panicking.
///
/// See the [`examples/cargo_tests.rs`](https://github.com/yaahc/color-eyre/blob/master/examples/cargo_tests.rs): for a practical example.

pub fn install() -> Result<(), crate::eyre::Report> {
config::HookBuilder::default().install()
}