Crates.io | narrate |
lib.rs | narrate |
version | 0.4.2 |
source | src |
created_at | 2022-09-14 15:32:24.144899 |
updated_at | 2024-07-12 16:32:52.888032 |
description | narrate is a set of CLI app utilities for error handling and status reporting |
homepage | |
repository | https://github.com/sonro/narrate |
max_upload_size | |
id | 665881 |
size | 131,722 |
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, with optional help messages.
Result
typeUse
narrate::Result<T>
as a return type of any fallible function.
Within the function, use ?
to propagate any error that implements the
std::error::Error
trait. Same as
anyhow::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 to
anyhow::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 a narrate::Error
. By
default this is just 70 (software error)
, but using an apropriate CliError
will change this.
narrate::CliError
collection of typical command line errors. Use them to add context to deeper
application errors. Use their exit_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
or
report::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 narrate::{Color, report};
fn main() {
report::status("Created", "new project `spacetime`", Color::Green);
}
Please view the API Docs and examples for more information.
Anyhow is a great tool for handling errors in your CLI app, but it doesn't come with its own reporting, common set of errors, or the ability to add separate help messages.
Eyre and its companion crates offer fine-grained error reporting and is far more customizable than narrate - which is opinionated in copying Cargo's style. If you don't need that much control, narrate provides a simpler alternative. Plus the added benefit of reporting statuses, not just errors.
If you just use the report
Cargo feature flag,
you can access the report
module and thus the anyhow_err
and anyhow_err_full
functions.
# Cargo.toml
[dependencies]
narrate = { version = "0.4.2", default-features = false, features = ["report"] }
// main.rs
use narrate::report;
fn main() {
if let Err(err) => run() {
report::anyhow_err_full(err);
}
}
fn run() -> anyhow::Result<()> {
...
}
Thank you very much for considering to contribute to this project!
We welcome any form of contribution:
Note: Before you take the time to open a pull request, please open an issue first.
See CONTRIBUTING.md for details.
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.