narrate
This library provides CLI application error and status reporting utilities. The coloured output formatting aims to be similar to Cargo. Error type is a wrapper around Anyhow.
Features
- User facing status messages and error reporting
- Wrap any error with additional context
- Optional help messages for errors
- Set of standard CLI errors with exit codes conforming to sysexits.h
- Convenience
Result
type - Drop in replacement for Anyhow
How to use
-
Use
narrate::Result<T>
as a return type of any fallible function.Within the function, use
?
to propagate any error that implements thestd::error::Error
trait. Same asanyhow::Result<T>
.use narrate::Result; fn get_user() -> Result<User> { let json = std::fs::read_to_string("user.json")?; let user: User = serde_json::from_str(&json)?; Ok(user) }
-
Wrap an error with more context by importing the
narrate::ErrorWrap
trait. Similar toanyhow::Context
, this can give your users more information as to why an error happened.use narrate::{CliError, ErrorWrap, Result}; fn run() -> Result<()> { ... // wrap with contextual information data.acquire().wrap("unable to acquire data")?; // wrap with another error config.load().wrap(CliError::Config)?; // wrap with lazily evaulated string or error config.load().wrap_with(|| format!("cannot load {}", path))?; // wrap with help information create_dir() .wrap("project directory already exists") .add_help("Try using cargo init")?; ... }
error: project directory already exists cause: Is a directory (os error 20) Try using cargo init
-
Use the
narrate::ExitCode
trait to get the sysexits.h conforming exit code from anarrate::Error
. By default this is just70 (software error)
but it can be easily implemented for any type. -
narrate::CliError
collection of typical command line errors. Use them to add context to deeper application errors. Use theirexit_code
to conform to sysexits.h.use narrate::{CliError, ErrorWrap, ExitCode, Result}; fn main() { let res = run(); if let Err(ref err) = res { std::process::exit(err.exit_code()); } } fn run() -> Result<()> { will_error().wrap(CliError::OsErr)? Ok(()) }
-
Report errors to the command line with either
report::err
orreport::err_full
for the complete error chain.use narrate::{CliError, Error, report}; fn main() { let res = run(); if let Err(ref err) = res { report::err_full(&err); std::process::exit(err.exit_code()); } } fn run() -> Result<()> { ... let config: Config = serde_json::from_str(&json) .wrap("bad config file `/app/config.toml`") .wrap(CliError::Config) .add_help("see https://docs.example.rs/config for more help")?; ... }
-
Report application status to the command line with
report::status
. Modeled on the output from Cargo.use colored::Color; use narrate::report; fn main() { report::status("Created", "new project `spacetime`", Color::Green); }
Contributing
Thank you very much for considering to contribute to this project!
We welcome any form of contribution:
- New issues (feature requests, bug reports, questions, ideas, ...)
- Pull requests (documentation improvements, code improvements, new features, ...)
Note: Before you take the time to open a pull request, please open an issue first.
See CONTRIBUTING.md for details.
License
narrate is distributed under the terms of both the MIT license and the Apache License (Version 2.0).
See LICENSE-APACHE and LICENSE-MIT for details.