Replace 'failure' crate with anyhow+thiserror

Closes #148
This commit is contained in:
dbr 2021-03-25 16:33:35 +11:00
parent 3cccdc7e32
commit 4d9755c43b
41 changed files with 255 additions and 316 deletions

View file

@ -7,7 +7,7 @@ version = "0.3.0"
[dependencies]
dirs = "^3.0.1"
env_logger = "^0.8.2"
failure = "^0.1.8"
anyhow = "1.0"
log = "^0.4.11"
nom = "^6.0.1"
prettytable-rs = "^0.8.0"

View file

@ -1,6 +1,6 @@
use super::args::*;
use super::{ArgList, Subcommand};
use failure::{format_err, Fallible};
use anyhow::bail;
use nom::{combinator::*, sequence::*, Err, IResult};
/// A command is the overall command that the CLI should execute.
@ -29,16 +29,16 @@ impl Command {
}
/// Parse a command from the given list of strings.
pub fn from_argv(argv: &[&str]) -> Fallible<Command> {
pub fn from_argv(argv: &[&str]) -> anyhow::Result<Command> {
match Command::parse(argv) {
Ok((&[], cmd)) => Ok(cmd),
Ok((trailing, _)) => Err(format_err!(
Ok((trailing, _)) => bail!(
"command line has trailing arguments: {:?}",
trailing
)),
),
Err(Err::Incomplete(_)) => unreachable!(),
Err(Err::Error(e)) => Err(format_err!("command line not recognized: {:?}", e)),
Err(Err::Failure(e)) => Err(format_err!("command line not recognized: {:?}", e)),
Err(Err::Error(e)) => bail!("command line not recognized: {:?}", e),
Err(Err::Failure(e)) => bail!("command line not recognized: {:?}", e),
}
}
}

View file

@ -1,7 +1,7 @@
use super::args::{arg_matching, id_list, minus_tag, plus_tag, status_colon, TaskId};
use super::ArgList;
use crate::usage;
use failure::{bail, Fallible};
use anyhow::bail;
use nom::{branch::alt, combinator::*, multi::fold_many0, IResult};
use taskchampion::Status;
@ -44,7 +44,7 @@ impl Condition {
}
/// Parse a single condition string
pub(crate) fn parse_str(input: &str) -> Fallible<Condition> {
pub(crate) fn parse_str(input: &str) -> anyhow::Result<Condition> {
let input = &[input];
Ok(match Condition::parse(input) {
Ok((&[], cond)) => cond,

View file

@ -1,5 +1,4 @@
use crate::argparse::{DescriptionMod, Modification};
use failure::Fallible;
use taskchampion::{Replica, Status};
use termcolor::WriteColor;
@ -7,7 +6,7 @@ pub(crate) fn execute<W: WriteColor>(
w: &mut W,
replica: &mut Replica,
modification: Modification,
) -> Fallible<()> {
) -> anyhow::Result<()> {
let description = match modification.description {
DescriptionMod::Set(ref s) => s.clone(),
_ => "(no description)".to_owned(),

View file

@ -1,8 +1,7 @@
use failure::Fallible;
use taskchampion::Replica;
use termcolor::WriteColor;
pub(crate) fn execute<W: WriteColor>(w: &mut W, replica: &mut Replica) -> Fallible<()> {
pub(crate) fn execute<W: WriteColor>(w: &mut W, replica: &mut Replica) -> anyhow::Result<()> {
log::debug!("rebuilding working set");
replica.rebuild_working_set(true)?;
writeln!(w, "garbage collected.")?;

View file

@ -1,12 +1,11 @@
use crate::usage::Usage;
use failure::Fallible;
use termcolor::WriteColor;
pub(crate) fn execute<W: WriteColor>(
w: &mut W,
command_name: String,
summary: bool,
) -> Fallible<()> {
) -> anyhow::Result<()> {
let usage = Usage::new();
usage.write_help(w, command_name.as_ref(), summary)?;
Ok(())

View file

@ -1,7 +1,6 @@
use crate::argparse::Filter;
use crate::invocation::filtered_tasks;
use crate::table;
use failure::Fallible;
use prettytable::{cell, row, Table};
use taskchampion::Replica;
use termcolor::WriteColor;
@ -11,7 +10,7 @@ pub(crate) fn execute<W: WriteColor>(
replica: &mut Replica,
filter: Filter,
debug: bool,
) -> Fallible<()> {
) -> anyhow::Result<()> {
let working_set = replica.working_set()?;
for task in filtered_tasks(replica, &filter)? {

View file

@ -1,6 +1,5 @@
use crate::argparse::{Filter, Modification};
use crate::invocation::{apply_modification, filtered_tasks};
use failure::Fallible;
use taskchampion::Replica;
use termcolor::WriteColor;
@ -9,7 +8,7 @@ pub(crate) fn execute<W: WriteColor>(
replica: &mut Replica,
filter: Filter,
modification: Modification,
) -> Fallible<()> {
) -> anyhow::Result<()> {
for task in filtered_tasks(replica, &filter)? {
let mut task = task.into_mut(replica);

View file

@ -1,7 +1,6 @@
use crate::argparse::Filter;
use crate::invocation::display_report;
use config::Config;
use failure::Fallible;
use taskchampion::Replica;
use termcolor::WriteColor;
@ -11,7 +10,7 @@ pub(crate) fn execute<W: WriteColor>(
settings: &Config,
report_name: String,
filter: Filter,
) -> Fallible<()> {
) -> anyhow::Result<()> {
display_report(w, replica, settings, report_name, filter)
}

View file

@ -1,4 +1,3 @@
use failure::Fallible;
use taskchampion::{server::Server, Replica};
use termcolor::WriteColor;
@ -6,8 +5,8 @@ pub(crate) fn execute<W: WriteColor>(
w: &mut W,
replica: &mut Replica,
server: &mut Box<dyn Server>,
) -> Fallible<()> {
replica.sync(server)?;
) -> anyhow::Result<()> {
replica.sync(server).unwrap();
writeln!(w, "sync complete.")?;
Ok(())
}

View file

@ -1,7 +1,6 @@
use failure::Fallible;
use termcolor::{ColorSpec, WriteColor};
pub(crate) fn execute<W: WriteColor>(w: &mut W) -> Fallible<()> {
pub(crate) fn execute<W: WriteColor>(w: &mut W) -> anyhow::Result<()> {
write!(w, "TaskChampion ")?;
w.set_color(ColorSpec::new().set_bold(true))?;
writeln!(w, "{}", env!("CARGO_PKG_VERSION"))?;

View file

@ -1,5 +1,4 @@
use crate::argparse::{Condition, Filter, TaskId};
use failure::Fallible;
use std::collections::HashSet;
use std::convert::TryInto;
use taskchampion::{Replica, Status, Tag, Task, Uuid, WorkingSet};
@ -108,7 +107,7 @@ fn universe_for_filter(filter: &Filter) -> Universe {
pub(super) fn filtered_tasks(
replica: &mut Replica,
filter: &Filter,
) -> Fallible<impl Iterator<Item = Task>> {
) -> anyhow::Result<impl Iterator<Item = Task>> {
let mut res = vec![];
log::debug!("Applying filter {:?}", filter);
@ -253,7 +252,7 @@ mod test {
}
#[test]
fn tag_filtering() -> Fallible<()> {
fn tag_filtering() -> anyhow::Result<()> {
let mut replica = test_replica();
let yes: Tag = "yes".try_into()?;
let no: Tag = "no".try_into()?;

View file

@ -2,7 +2,6 @@
use crate::argparse::{Command, Subcommand};
use config::Config;
use failure::{format_err, Fallible};
use taskchampion::{Replica, Server, ServerConfig, StorageConfig, Uuid};
use termcolor::{ColorChoice, StandardStream};
@ -20,7 +19,7 @@ use report::display_report;
/// Invoke the given Command in the context of the given settings
#[allow(clippy::needless_return)]
pub(crate) fn invoke(command: Command, settings: Config) -> Fallible<()> {
pub(crate) fn invoke(command: Command, settings: Config) -> anyhow::Result<()> {
log::debug!("command: {:?}", command);
log::debug!("settings: {:?}", settings);
@ -101,7 +100,7 @@ pub(crate) fn invoke(command: Command, settings: Config) -> Fallible<()> {
// utilities for invoke
/// Get the replica for this invocation
fn get_replica(settings: &Config) -> Fallible<Replica> {
fn get_replica(settings: &Config) -> anyhow::Result<Replica> {
let taskdb_dir = settings.get_str("data_dir")?.into();
log::debug!("Replica data_dir: {:?}", taskdb_dir);
let storage_config = StorageConfig::OnDisk { taskdb_dir };
@ -109,7 +108,7 @@ fn get_replica(settings: &Config) -> Fallible<Replica> {
}
/// Get the server for this invocation
fn get_server(settings: &Config) -> Fallible<Box<dyn Server>> {
fn get_server(settings: &Config) -> anyhow::Result<Box<dyn Server>> {
// if server_client_key and server_origin are both set, use
// the remote server
let config = if let (Ok(client_key), Ok(origin)) = (
@ -119,7 +118,7 @@ fn get_server(settings: &Config) -> Fallible<Box<dyn Server>> {
let client_key = Uuid::parse_str(&client_key)?;
let encryption_secret = settings
.get_str("encryption_secret")
.map_err(|_| format_err!("Could not read `encryption_secret` configuration"))?;
.map_err(|_| anyhow::anyhow!("Could not read `encryption_secret` configuration"))?;
log::debug!("Using sync-server with origin {}", origin);
log::debug!("Sync client ID: {}", client_key);
@ -137,7 +136,7 @@ fn get_server(settings: &Config) -> Fallible<Box<dyn Server>> {
}
/// Get a WriteColor implementation based on whether the output is a tty.
fn get_writer() -> Fallible<StandardStream> {
fn get_writer() -> anyhow::Result<StandardStream> {
Ok(StandardStream::stdout(if atty::is(atty::Stream::Stdout) {
ColorChoice::Auto
} else {

View file

@ -1,5 +1,4 @@
use crate::argparse::{DescriptionMod, Modification};
use failure::Fallible;
use std::convert::TryInto;
use taskchampion::TaskMut;
use termcolor::WriteColor;
@ -9,7 +8,7 @@ pub(super) fn apply_modification<W: WriteColor>(
w: &mut W,
task: &mut TaskMut,
modification: &Modification,
) -> Fallible<()> {
) -> anyhow::Result<()> {
match modification.description {
DescriptionMod::Set(ref description) => task.set_description(description.clone())?,
DescriptionMod::Prepend(ref description) => {

View file

@ -3,7 +3,6 @@ use crate::invocation::filtered_tasks;
use crate::report::{Column, Property, Report, SortBy};
use crate::table;
use config::Config;
use failure::{format_err, Fallible};
use prettytable::{Row, Table};
use std::cmp::Ordering;
use taskchampion::{Replica, Task, WorkingSet};
@ -83,13 +82,13 @@ pub(super) fn display_report<W: WriteColor>(
settings: &Config,
report_name: String,
filter: Filter,
) -> Fallible<()> {
) -> anyhow::Result<()> {
let mut t = Table::new();
let working_set = replica.working_set()?;
// Get the report from settings
let mut report = Report::from_config(settings.get(&format!("reports.{}", report_name))?)
.map_err(|e| format_err!("report.{}{}", report_name, e))?;
.map_err(|e| anyhow::anyhow!("report.{}{}", report_name, e))?;
// include any user-supplied filter conditions
report.filter = report.filter.intersect(filter);

View file

@ -29,7 +29,6 @@ For the public TaskChampion Rust API, see the `taskchampion` crate.
*/
use failure::Fallible;
use std::os::unix::ffi::OsStringExt;
use std::string::FromUtf8Error;
@ -45,7 +44,7 @@ mod usage;
/// The main entry point for the command-line interface. This builds an Invocation
/// from the particulars of the operating-system interface, and then executes it.
pub fn main() -> Fallible<()> {
pub fn main() -> anyhow::Result<()> {
env_logger::init();
// parse the command line into a vector of &str, failing if

View file

@ -1,7 +1,7 @@
//! This module contains the data structures used to define reports.
use crate::argparse::{Condition, Filter};
use failure::{bail, format_err, Fallible};
use anyhow::{bail};
/// A report specifies a filter as well as a sort order and information about which
/// task attributes to display
@ -77,43 +77,43 @@ impl Report {
/// Create a Report from a config value. This should be the `report.<report_name>` value.
/// The error message begins with any additional path information, e.g., `.sort[1].sort_by:
/// ..`.
pub(crate) fn from_config(cfg: config::Value) -> Fallible<Report> {
let mut map = cfg.into_table().map_err(|e| format_err!(": {}", e))?;
pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result<Report> {
let mut map = cfg.into_table().map_err(|e| anyhow::anyhow!(": {}", e))?;
let sort = if let Some(sort_array) = map.remove("sort") {
sort_array
.into_array()
.map_err(|e| format_err!(".sort: {}", e))?
.map_err(|e| anyhow::anyhow!(".sort: {}", e))?
.drain(..)
.enumerate()
.map(|(i, v)| Sort::from_config(v).map_err(|e| format_err!(".sort[{}]{}", i, e)))
.collect::<Fallible<Vec<_>>>()?
.map(|(i, v)| Sort::from_config(v).map_err(|e| anyhow::anyhow!(".sort[{}]{}", i, e)))
.collect::<anyhow::Result<Vec<_>>>()?
} else {
vec![]
};
let columns = map
.remove("columns")
.ok_or_else(|| format_err!(": 'columns' property is required"))?
.ok_or_else(|| anyhow::anyhow!(": 'columns' property is required"))?
.into_array()
.map_err(|e| format_err!(".columns: {}", e))?
.map_err(|e| anyhow::anyhow!(".columns: {}", e))?
.drain(..)
.enumerate()
.map(|(i, v)| Column::from_config(v).map_err(|e| format_err!(".columns[{}]{}", i, e)))
.collect::<Fallible<Vec<_>>>()?;
.map(|(i, v)| Column::from_config(v).map_err(|e| anyhow::anyhow!(".columns[{}]{}", i, e)))
.collect::<anyhow::Result<Vec<_>>>()?;
let conditions = if let Some(conditions) = map.remove("filter") {
conditions
.into_array()
.map_err(|e| format_err!(".filter: {}", e))?
.map_err(|e| anyhow::anyhow!(".filter: {}", e))?
.drain(..)
.enumerate()
.map(|(i, v)| {
v.into_str()
.map_err(|e| e.into())
.and_then(|s| Condition::parse_str(&s))
.map_err(|e| format_err!(".filter[{}]: {}", i, e))
.map_err(|e| anyhow::anyhow!(".filter[{}]: {}", i, e))
})
.collect::<Fallible<Vec<_>>>()?
.collect::<anyhow::Result<Vec<_>>>()?
} else {
vec![]
};
@ -133,18 +133,18 @@ impl Report {
}
impl Column {
pub(crate) fn from_config(cfg: config::Value) -> Fallible<Column> {
let mut map = cfg.into_table().map_err(|e| format_err!(": {}", e))?;
pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result<Column> {
let mut map = cfg.into_table().map_err(|e| anyhow::anyhow!(": {}", e))?;
let label = map
.remove("label")
.ok_or_else(|| format_err!(": 'label' property is required"))?
.ok_or_else(|| anyhow::anyhow!(": 'label' property is required"))?
.into_str()
.map_err(|e| format_err!(".label: {}", e))?;
.map_err(|e| anyhow::anyhow!(".label: {}", e))?;
let property: config::Value = map
.remove("property")
.ok_or_else(|| format_err!(": 'property' property is required"))?;
.ok_or_else(|| anyhow::anyhow!(": 'property' property is required"))?;
let property =
Property::from_config(property).map_err(|e| format_err!(".property{}", e))?;
Property::from_config(property).map_err(|e| anyhow::anyhow!(".property{}", e))?;
if !map.is_empty() {
bail!(": unknown properties");
@ -155,8 +155,8 @@ impl Column {
}
impl Property {
pub(crate) fn from_config(cfg: config::Value) -> Fallible<Property> {
let s = cfg.into_str().map_err(|e| format_err!(": {}", e))?;
pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result<Property> {
let s = cfg.into_str().map_err(|e| anyhow::anyhow!(": {}", e))?;
Ok(match s.as_ref() {
"id" => Property::Id,
"uuid" => Property::Uuid,
@ -169,18 +169,18 @@ impl Property {
}
impl Sort {
pub(crate) fn from_config(cfg: config::Value) -> Fallible<Sort> {
let mut map = cfg.into_table().map_err(|e| format_err!(": {}", e))?;
pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result<Sort> {
let mut map = cfg.into_table().map_err(|e| anyhow::anyhow!(": {}", e))?;
let ascending = match map.remove("ascending") {
Some(v) => v
.into_bool()
.map_err(|e| format_err!(".ascending: {}", e))?,
.map_err(|e| anyhow::anyhow!(".ascending: {}", e))?,
None => true, // default
};
let sort_by: config::Value = map
.remove("sort_by")
.ok_or_else(|| format_err!(": 'sort_by' property is required"))?;
let sort_by = SortBy::from_config(sort_by).map_err(|e| format_err!(".sort_by{}", e))?;
.ok_or_else(|| anyhow::anyhow!(": 'sort_by' property is required"))?;
let sort_by = SortBy::from_config(sort_by).map_err(|e| anyhow::anyhow!(".sort_by{}", e))?;
if !map.is_empty() {
bail!(": unknown properties");
@ -191,8 +191,8 @@ impl Sort {
}
impl SortBy {
pub(crate) fn from_config(cfg: config::Value) -> Fallible<SortBy> {
let s = cfg.into_str().map_err(|e| format_err!(": {}", e))?;
pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result<SortBy> {
let s = cfg.into_str().map_err(|e| anyhow::anyhow!(": {}", e))?;
Ok(match s.as_ref() {
"id" => SortBy::Id,
"uuid" => SortBy::Uuid,

View file

@ -1,5 +1,4 @@
use config::{Config, Environment, File, FileFormat, FileSourceFile, FileSourceString};
use failure::Fallible;
use std::env;
use std::path::PathBuf;
@ -34,7 +33,7 @@ reports:
"#;
/// Get the default settings for this application
pub(crate) fn default_settings() -> Fallible<Config> {
pub(crate) fn default_settings() -> anyhow::Result<Config> {
let mut settings = Config::default();
// set up defaults
@ -62,7 +61,7 @@ pub(crate) fn default_settings() -> Fallible<Config> {
Ok(settings)
}
pub(crate) fn read_settings() -> Fallible<Config> {
pub(crate) fn read_settings() -> anyhow::Result<Config> {
let mut settings = default_settings()?;
// load either from the path in TASKCHAMPION_CONFIG, or from CONFIG_DIR/taskchampion