From 4d9755c43b0554f92153fa971a248436741bd0ca Mon Sep 17 00:00:00 2001 From: dbr Date: Thu, 25 Mar 2021 16:33:35 +1100 Subject: [PATCH] Replace 'failure' crate with anyhow+thiserror Closes #148 --- Cargo.lock | 47 ++++------------ cli/Cargo.toml | 2 +- cli/src/argparse/command.rs | 12 ++--- cli/src/argparse/filter.rs | 4 +- cli/src/invocation/cmd/add.rs | 3 +- cli/src/invocation/cmd/gc.rs | 3 +- cli/src/invocation/cmd/help.rs | 3 +- cli/src/invocation/cmd/info.rs | 3 +- cli/src/invocation/cmd/modify.rs | 3 +- cli/src/invocation/cmd/report.rs | 3 +- cli/src/invocation/cmd/sync.rs | 5 +- cli/src/invocation/cmd/version.rs | 3 +- cli/src/invocation/filter.rs | 5 +- cli/src/invocation/mod.rs | 11 ++-- cli/src/invocation/modify.rs | 3 +- cli/src/invocation/report.rs | 5 +- cli/src/lib.rs | 3 +- cli/src/report.rs | 56 +++++++++---------- cli/src/settings.rs | 5 +- sync-server/Cargo.toml | 2 +- sync-server/src/api/mod.rs | 2 +- sync-server/src/main.rs | 3 +- sync-server/src/server.rs | 17 +++--- sync-server/src/storage/inmemory.rs | 19 ++++--- sync-server/src/storage/kv.rs | 26 +++++---- sync-server/src/storage/mod.rs | 15 +++--- taskchampion/Cargo.toml | 3 +- taskchampion/src/errors.rs | 7 ++- taskchampion/src/replica.rs | 21 ++++---- taskchampion/src/server/config.rs | 3 +- taskchampion/src/server/local.rs | 24 ++++----- taskchampion/src/server/remote/crypto.rs | 11 ++-- taskchampion/src/server/remote/mod.rs | 15 +++--- taskchampion/src/server/test.rs | 5 +- taskchampion/src/server/types.rs | 5 +- taskchampion/src/storage/config.rs | 3 +- taskchampion/src/storage/inmemory.rs | 43 ++++++++------- taskchampion/src/storage/kv.rs | 68 ++++++++++++------------ taskchampion/src/storage/mod.rs | 36 ++++++------- taskchampion/src/task.rs | 33 ++++++------ taskchampion/src/taskdb.rs | 31 ++++++----- 41 files changed, 255 insertions(+), 316 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 154c73a61..ea49e2fd2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -294,6 +294,12 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "anyhow" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cddc5f91628367664cc7c69714ff08deee8a3efc54623011c772544d7b2767" + [[package]] name = "arrayref" version = "0.3.6" @@ -821,28 +827,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "failure" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d32e9bd16cc02eae7db7ef620b392808b89f6a5e16bb3497d159c6b92a0f4f86" -dependencies = [ - "backtrace", - "failure_derive", -] - -[[package]] -name = "failure_derive" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", -] - [[package]] name = "flate2" version = "1.0.19" @@ -2230,18 +2214,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "synstructure" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "unicode-xid", -] - [[package]] name = "tap" version = "1.0.0" @@ -2252,8 +2224,8 @@ checksum = "36474e732d1affd3a6ed582781b3683df3d0563714c59c39591e8ff707cf078e" name = "taskchampion" version = "0.3.0" dependencies = [ + "anyhow", "chrono", - "failure", "kv", "lmdb-rkv", "log", @@ -2261,6 +2233,7 @@ dependencies = [ "serde", "serde_json", "tempdir", + "thiserror", "tindercrypt", "ureq", "uuid", @@ -2270,12 +2243,12 @@ dependencies = [ name = "taskchampion-cli" version = "0.3.0" dependencies = [ + "anyhow", "assert_cmd", "atty", "config", "dirs 3.0.1", "env_logger", - "failure", "log", "nom 6.0.1", "predicates", @@ -2292,9 +2265,9 @@ version = "0.3.0" dependencies = [ "actix-rt", "actix-web", + "anyhow", "clap", "env_logger", - "failure", "futures", "kv", "log", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index d2aed0b9d..c68c40934 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -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" diff --git a/cli/src/argparse/command.rs b/cli/src/argparse/command.rs index fec430d2c..198a0abf5 100644 --- a/cli/src/argparse/command.rs +++ b/cli/src/argparse/command.rs @@ -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 { + pub fn from_argv(argv: &[&str]) -> anyhow::Result { 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), } } } diff --git a/cli/src/argparse/filter.rs b/cli/src/argparse/filter.rs index 812917845..49273999b 100644 --- a/cli/src/argparse/filter.rs +++ b/cli/src/argparse/filter.rs @@ -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 { + pub(crate) fn parse_str(input: &str) -> anyhow::Result { let input = &[input]; Ok(match Condition::parse(input) { Ok((&[], cond)) => cond, diff --git a/cli/src/invocation/cmd/add.rs b/cli/src/invocation/cmd/add.rs index 1175b587e..8a4456282 100644 --- a/cli/src/invocation/cmd/add.rs +++ b/cli/src/invocation/cmd/add.rs @@ -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: &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(), diff --git a/cli/src/invocation/cmd/gc.rs b/cli/src/invocation/cmd/gc.rs index 75451808e..775b3096f 100644 --- a/cli/src/invocation/cmd/gc.rs +++ b/cli/src/invocation/cmd/gc.rs @@ -1,8 +1,7 @@ -use failure::Fallible; use taskchampion::Replica; use termcolor::WriteColor; -pub(crate) fn execute(w: &mut W, replica: &mut Replica) -> Fallible<()> { +pub(crate) fn execute(w: &mut W, replica: &mut Replica) -> anyhow::Result<()> { log::debug!("rebuilding working set"); replica.rebuild_working_set(true)?; writeln!(w, "garbage collected.")?; diff --git a/cli/src/invocation/cmd/help.rs b/cli/src/invocation/cmd/help.rs index df7bb5919..878234933 100644 --- a/cli/src/invocation/cmd/help.rs +++ b/cli/src/invocation/cmd/help.rs @@ -1,12 +1,11 @@ use crate::usage::Usage; -use failure::Fallible; use termcolor::WriteColor; pub(crate) fn execute( 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(()) diff --git a/cli/src/invocation/cmd/info.rs b/cli/src/invocation/cmd/info.rs index 603093315..1f90b79f3 100644 --- a/cli/src/invocation/cmd/info.rs +++ b/cli/src/invocation/cmd/info.rs @@ -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( replica: &mut Replica, filter: Filter, debug: bool, -) -> Fallible<()> { +) -> anyhow::Result<()> { let working_set = replica.working_set()?; for task in filtered_tasks(replica, &filter)? { diff --git a/cli/src/invocation/cmd/modify.rs b/cli/src/invocation/cmd/modify.rs index d914da418..06b4ccc0e 100644 --- a/cli/src/invocation/cmd/modify.rs +++ b/cli/src/invocation/cmd/modify.rs @@ -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( replica: &mut Replica, filter: Filter, modification: Modification, -) -> Fallible<()> { +) -> anyhow::Result<()> { for task in filtered_tasks(replica, &filter)? { let mut task = task.into_mut(replica); diff --git a/cli/src/invocation/cmd/report.rs b/cli/src/invocation/cmd/report.rs index 9076c7b23..bcb258298 100644 --- a/cli/src/invocation/cmd/report.rs +++ b/cli/src/invocation/cmd/report.rs @@ -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( settings: &Config, report_name: String, filter: Filter, -) -> Fallible<()> { +) -> anyhow::Result<()> { display_report(w, replica, settings, report_name, filter) } diff --git a/cli/src/invocation/cmd/sync.rs b/cli/src/invocation/cmd/sync.rs index 9abc8b657..9acc8e581 100644 --- a/cli/src/invocation/cmd/sync.rs +++ b/cli/src/invocation/cmd/sync.rs @@ -1,4 +1,3 @@ -use failure::Fallible; use taskchampion::{server::Server, Replica}; use termcolor::WriteColor; @@ -6,8 +5,8 @@ pub(crate) fn execute( w: &mut W, replica: &mut Replica, server: &mut Box, -) -> Fallible<()> { - replica.sync(server)?; +) -> anyhow::Result<()> { + replica.sync(server).unwrap(); writeln!(w, "sync complete.")?; Ok(()) } diff --git a/cli/src/invocation/cmd/version.rs b/cli/src/invocation/cmd/version.rs index db3f2a80b..baef94161 100644 --- a/cli/src/invocation/cmd/version.rs +++ b/cli/src/invocation/cmd/version.rs @@ -1,7 +1,6 @@ -use failure::Fallible; use termcolor::{ColorSpec, WriteColor}; -pub(crate) fn execute(w: &mut W) -> Fallible<()> { +pub(crate) fn execute(w: &mut W) -> anyhow::Result<()> { write!(w, "TaskChampion ")?; w.set_color(ColorSpec::new().set_bold(true))?; writeln!(w, "{}", env!("CARGO_PKG_VERSION"))?; diff --git a/cli/src/invocation/filter.rs b/cli/src/invocation/filter.rs index 28e25c238..0cc6e31fe 100644 --- a/cli/src/invocation/filter.rs +++ b/cli/src/invocation/filter.rs @@ -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> { +) -> anyhow::Result> { 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()?; diff --git a/cli/src/invocation/mod.rs b/cli/src/invocation/mod.rs index 32e66a940..fd910a8f0 100644 --- a/cli/src/invocation/mod.rs +++ b/cli/src/invocation/mod.rs @@ -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 { +fn get_replica(settings: &Config) -> anyhow::Result { 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 { } /// Get the server for this invocation -fn get_server(settings: &Config) -> Fallible> { +fn get_server(settings: &Config) -> anyhow::Result> { // 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> { 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> { } /// Get a WriteColor implementation based on whether the output is a tty. -fn get_writer() -> Fallible { +fn get_writer() -> anyhow::Result { Ok(StandardStream::stdout(if atty::is(atty::Stream::Stdout) { ColorChoice::Auto } else { diff --git a/cli/src/invocation/modify.rs b/cli/src/invocation/modify.rs index 74b9b8d00..b67620788 100644 --- a/cli/src/invocation/modify.rs +++ b/cli/src/invocation/modify.rs @@ -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: &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) => { diff --git a/cli/src/invocation/report.rs b/cli/src/invocation/report.rs index 185eaa4b3..0556d3b9d 100644 --- a/cli/src/invocation/report.rs +++ b/cli/src/invocation/report.rs @@ -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( 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); diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 38546f6cb..29b3f8afc 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -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 diff --git a/cli/src/report.rs b/cli/src/report.rs index 12ba0af99..fb60246a0 100644 --- a/cli/src/report.rs +++ b/cli/src/report.rs @@ -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.` 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 { - let mut map = cfg.into_table().map_err(|e| format_err!(": {}", e))?; + pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result { + 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::>>()? + .map(|(i, v)| Sort::from_config(v).map_err(|e| anyhow::anyhow!(".sort[{}]{}", i, e))) + .collect::>>()? } 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::>>()?; + .map(|(i, v)| Column::from_config(v).map_err(|e| anyhow::anyhow!(".columns[{}]{}", i, e))) + .collect::>>()?; 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::>>()? + .collect::>>()? } else { vec![] }; @@ -133,18 +133,18 @@ impl Report { } impl Column { - pub(crate) fn from_config(cfg: config::Value) -> Fallible { - let mut map = cfg.into_table().map_err(|e| format_err!(": {}", e))?; + pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result { + 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 { - let s = cfg.into_str().map_err(|e| format_err!(": {}", e))?; + pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result { + 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 { - let mut map = cfg.into_table().map_err(|e| format_err!(": {}", e))?; + pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result { + 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 { - let s = cfg.into_str().map_err(|e| format_err!(": {}", e))?; + pub(crate) fn from_config(cfg: config::Value) -> anyhow::Result { + let s = cfg.into_str().map_err(|e| anyhow::anyhow!(": {}", e))?; Ok(match s.as_ref() { "id" => SortBy::Id, "uuid" => SortBy::Uuid, diff --git a/cli/src/settings.rs b/cli/src/settings.rs index 88d972dc4..27c6a067f 100644 --- a/cli/src/settings.rs +++ b/cli/src/settings.rs @@ -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 { +pub(crate) fn default_settings() -> anyhow::Result { let mut settings = Config::default(); // set up defaults @@ -62,7 +61,7 @@ pub(crate) fn default_settings() -> Fallible { Ok(settings) } -pub(crate) fn read_settings() -> Fallible { +pub(crate) fn read_settings() -> anyhow::Result { let mut settings = default_settings()?; // load either from the path in TASKCHAMPION_CONFIG, or from CONFIG_DIR/taskchampion diff --git a/sync-server/Cargo.toml b/sync-server/Cargo.toml index d1662b230..233282612 100644 --- a/sync-server/Cargo.toml +++ b/sync-server/Cargo.toml @@ -9,7 +9,7 @@ edition = "2018" [dependencies] uuid = { version = "^0.8.1", features = ["serde", "v4"] } actix-web = "^3.3.0" -failure = "^0.1.8" +anyhow = "1.0" futures = "^0.3.8" serde = "^1.0.104" kv = {version = "^0.10.0", features = ["msgpack-value"]} diff --git a/sync-server/src/api/mod.rs b/sync-server/src/api/mod.rs index 5929f28c1..26aa8eba0 100644 --- a/sync-server/src/api/mod.rs +++ b/sync-server/src/api/mod.rs @@ -29,7 +29,7 @@ pub(crate) fn api_scope() -> Scope { } /// Convert a failure::Error to an Actix ISE -fn failure_to_ise(err: failure::Error) -> impl actix_web::ResponseError { +fn failure_to_ise(err: anyhow::Error) -> impl actix_web::ResponseError { error::InternalError::new(err, StatusCode::INTERNAL_SERVER_ERROR) } diff --git a/sync-server/src/main.rs b/sync-server/src/main.rs index 28481d3e7..296a18aa2 100644 --- a/sync-server/src/main.rs +++ b/sync-server/src/main.rs @@ -4,7 +4,6 @@ use crate::storage::{KVStorage, Storage}; use actix_web::{get, middleware::Logger, web, App, HttpServer, Responder, Scope}; use api::{api_scope, ServerState}; use clap::Arg; -use failure::Fallible; mod api; mod server; @@ -27,7 +26,7 @@ pub(crate) fn app_scope(server_state: ServerState) -> Scope { } #[actix_web::main] -async fn main() -> Fallible<()> { +async fn main() -> anyhow::Result<()> { env_logger::init(); let matches = clap::App::new("taskchampion-sync-server") .version(env!("CARGO_PKG_VERSION")) diff --git a/sync-server/src/server.rs b/sync-server/src/server.rs index 6c0e183cc..be67639be 100644 --- a/sync-server/src/server.rs +++ b/sync-server/src/server.rs @@ -1,7 +1,6 @@ //! This module implements the core logic of the server: handling transactions, upholding //! invariants, and so on. use crate::storage::{Client, StorageTxn}; -use failure::Fallible; use uuid::Uuid; /// The distinguished value for "no version" @@ -23,7 +22,7 @@ pub(crate) fn get_child_version<'a>( mut txn: Box, client_key: ClientKey, parent_version_id: VersionId, -) -> Fallible> { +) -> anyhow::Result> { Ok(txn .get_version_by_parent(client_key, parent_version_id)? .map(|version| GetVersionResult { @@ -48,7 +47,7 @@ pub(crate) fn add_version<'a>( client: Client, parent_version_id: VersionId, history_segment: HistorySegment, -) -> Fallible { +) -> anyhow::Result { log::debug!( "add_version(client_key: {}, parent_version_id: {})", client_key, @@ -84,7 +83,7 @@ mod test { use crate::storage::{InMemoryStorage, Storage}; #[test] - fn gcv_not_found() -> Fallible<()> { + fn gcv_not_found() -> anyhow::Result<()> { let storage = InMemoryStorage::new(); let txn = storage.txn()?; let client_key = Uuid::new_v4(); @@ -94,7 +93,7 @@ mod test { } #[test] - fn gcv_found() -> Fallible<()> { + fn gcv_found() -> anyhow::Result<()> { let storage = InMemoryStorage::new(); let mut txn = storage.txn()?; let client_key = Uuid::new_v4(); @@ -121,7 +120,7 @@ mod test { } #[test] - fn av_conflict() -> Fallible<()> { + fn av_conflict() -> anyhow::Result<()> { let storage = InMemoryStorage::new(); let mut txn = storage.txn()?; let client_key = Uuid::new_v4(); @@ -154,7 +153,7 @@ mod test { Ok(()) } - fn test_av_success(latest_version_id_nil: bool) -> Fallible<()> { + fn test_av_success(latest_version_id_nil: bool) -> anyhow::Result<()> { let storage = InMemoryStorage::new(); let mut txn = storage.txn()?; let client_key = Uuid::new_v4(); @@ -198,12 +197,12 @@ mod test { } #[test] - fn av_success_with_existing_history() -> Fallible<()> { + fn av_success_with_existing_history() -> anyhow::Result<()> { test_av_success(true) } #[test] - fn av_success_nil_latest_version_id() -> Fallible<()> { + fn av_success_nil_latest_version_id() -> anyhow::Result<()> { test_av_success(false) } } diff --git a/sync-server/src/storage/inmemory.rs b/sync-server/src/storage/inmemory.rs index fbd56db65..e37abb07a 100644 --- a/sync-server/src/storage/inmemory.rs +++ b/sync-server/src/storage/inmemory.rs @@ -1,5 +1,4 @@ use super::{Client, Storage, StorageTxn, Uuid, Version}; -use failure::{format_err, Fallible}; use std::collections::HashMap; use std::sync::{Mutex, MutexGuard}; @@ -28,19 +27,19 @@ struct InnerTxn<'a>(MutexGuard<'a, Inner>); /// /// NOTE: this does not implement transaction rollback. impl Storage for InMemoryStorage { - fn txn<'a>(&'a self) -> Fallible> { + fn txn<'a>(&'a self) -> anyhow::Result> { Ok(Box::new(InnerTxn(self.0.lock().expect("poisoned lock")))) } } impl<'a> StorageTxn for InnerTxn<'a> { - fn get_client(&mut self, client_key: Uuid) -> Fallible> { + fn get_client(&mut self, client_key: Uuid) -> anyhow::Result> { Ok(self.0.clients.get(&client_key).cloned()) } - fn new_client(&mut self, client_key: Uuid, latest_version_id: Uuid) -> Fallible<()> { + fn new_client(&mut self, client_key: Uuid, latest_version_id: Uuid) -> anyhow::Result<()> { if self.0.clients.get(&client_key).is_some() { - return Err(format_err!("Client {} already exists", client_key)); + return Err(anyhow::anyhow!("Client {} already exists", client_key)); } self.0 .clients @@ -52,12 +51,12 @@ impl<'a> StorageTxn for InnerTxn<'a> { &mut self, client_key: Uuid, latest_version_id: Uuid, - ) -> Fallible<()> { + ) -> anyhow::Result<()> { if let Some(client) = self.0.clients.get_mut(&client_key) { client.latest_version_id = latest_version_id; Ok(()) } else { - Err(format_err!("Client {} does not exist", client_key)) + Err(anyhow::anyhow!("Client {} does not exist", client_key)) } } @@ -65,7 +64,7 @@ impl<'a> StorageTxn for InnerTxn<'a> { &mut self, client_key: Uuid, parent_version_id: Uuid, - ) -> Fallible> { + ) -> anyhow::Result> { Ok(self .0 .versions @@ -79,7 +78,7 @@ impl<'a> StorageTxn for InnerTxn<'a> { version_id: Uuid, parent_version_id: Uuid, history_segment: Vec, - ) -> Fallible<()> { + ) -> anyhow::Result<()> { // TODO: verify it doesn't exist (`.entry`?) let version = Version { version_id, @@ -92,7 +91,7 @@ impl<'a> StorageTxn for InnerTxn<'a> { Ok(()) } - fn commit(&mut self) -> Fallible<()> { + fn commit(&mut self) -> anyhow::Result<()> { Ok(()) } } diff --git a/sync-server/src/storage/kv.rs b/sync-server/src/storage/kv.rs index f3cc178b2..41f441844 100644 --- a/sync-server/src/storage/kv.rs +++ b/sync-server/src/storage/kv.rs @@ -1,5 +1,4 @@ use super::{Client, Storage, StorageTxn, Uuid, Version}; -use failure::Fallible; use kv::msgpack::Msgpack; use kv::{Bucket, Config, Error, Serde, Store, ValueBuf}; use std::path::Path; @@ -29,7 +28,7 @@ pub(crate) struct KVStorage<'t> { } impl<'t> KVStorage<'t> { - pub fn new>(directory: P) -> Fallible> { + pub fn new>(directory: P) -> anyhow::Result> { let mut config = Config::default(directory); config.bucket("clients", None); config.bucket("versions", None); @@ -50,7 +49,7 @@ impl<'t> KVStorage<'t> { } impl<'t> Storage for KVStorage<'t> { - fn txn<'a>(&'a self) -> Fallible> { + fn txn<'a>(&'a self) -> anyhow::Result> { Ok(Box::new(Txn { storage: self, txn: Some(self.store.write_txn()?), @@ -82,7 +81,7 @@ impl<'t> Txn<'t> { } impl<'t> StorageTxn for Txn<'t> { - fn get_client(&mut self, client_key: Uuid) -> Fallible> { + fn get_client(&mut self, client_key: Uuid) -> anyhow::Result> { let key = client_db_key(client_key); let bucket = self.clients_bucket(); let kvtxn = self.kvtxn(); @@ -97,7 +96,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(Some(client)) } - fn new_client(&mut self, client_key: Uuid, latest_version_id: Uuid) -> Fallible<()> { + fn new_client(&mut self, client_key: Uuid, latest_version_id: Uuid) -> anyhow::Result<()> { let key = client_db_key(client_key); let bucket = self.clients_bucket(); let kvtxn = self.kvtxn(); @@ -110,7 +109,7 @@ impl<'t> StorageTxn for Txn<'t> { &mut self, client_key: Uuid, latest_version_id: Uuid, - ) -> Fallible<()> { + ) -> anyhow::Result<()> { // implementation is the same as new_client.. self.new_client(client_key, latest_version_id) } @@ -119,7 +118,7 @@ impl<'t> StorageTxn for Txn<'t> { &mut self, client_key: Uuid, parent_version_id: Uuid, - ) -> Fallible> { + ) -> anyhow::Result> { let key = version_db_key(client_key, parent_version_id); let bucket = self.versions_bucket(); let kvtxn = self.kvtxn(); @@ -139,7 +138,7 @@ impl<'t> StorageTxn for Txn<'t> { version_id: Uuid, parent_version_id: Uuid, history_segment: Vec, - ) -> Fallible<()> { + ) -> anyhow::Result<()> { let key = version_db_key(client_key, parent_version_id); let bucket = self.versions_bucket(); let kvtxn = self.kvtxn(); @@ -152,7 +151,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(()) } - fn commit(&mut self) -> Fallible<()> { + fn commit(&mut self) -> anyhow::Result<()> { if let Some(kvtxn) = self.txn.take() { kvtxn.commit()?; } else { @@ -165,11 +164,10 @@ impl<'t> StorageTxn for Txn<'t> { #[cfg(test)] mod test { use super::*; - use failure::Fallible; use tempdir::TempDir; #[test] - fn test_get_client_empty() -> Fallible<()> { + fn test_get_client_empty() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let storage = KVStorage::new(&tmp_dir.path())?; let mut txn = storage.txn()?; @@ -179,7 +177,7 @@ mod test { } #[test] - fn test_client_storage() -> Fallible<()> { + fn test_client_storage() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let storage = KVStorage::new(&tmp_dir.path())?; let mut txn = storage.txn()?; @@ -201,7 +199,7 @@ mod test { } #[test] - fn test_gvbp_empty() -> Fallible<()> { + fn test_gvbp_empty() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let storage = KVStorage::new(&tmp_dir.path())?; let mut txn = storage.txn()?; @@ -211,7 +209,7 @@ mod test { } #[test] - fn test_add_version_and_gvbp() -> Fallible<()> { + fn test_add_version_and_gvbp() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let storage = KVStorage::new(&tmp_dir.path())?; let mut txn = storage.txn()?; diff --git a/sync-server/src/storage/mod.rs b/sync-server/src/storage/mod.rs index c02d24fba..e0e13ae93 100644 --- a/sync-server/src/storage/mod.rs +++ b/sync-server/src/storage/mod.rs @@ -1,4 +1,3 @@ -use failure::Fallible; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -24,24 +23,24 @@ pub(crate) struct Version { pub(crate) trait StorageTxn { /// Get information about the given client - fn get_client(&mut self, client_key: Uuid) -> Fallible>; + fn get_client(&mut self, client_key: Uuid) -> anyhow::Result>; /// Create a new client with the given latest_version_id - fn new_client(&mut self, client_key: Uuid, latest_version_id: Uuid) -> Fallible<()>; + fn new_client(&mut self, client_key: Uuid, latest_version_id: Uuid) -> anyhow::Result<()>; /// Set the client's latest_version_id fn set_client_latest_version_id( &mut self, client_key: Uuid, latest_version_id: Uuid, - ) -> Fallible<()>; + ) -> anyhow::Result<()>; /// Get a version, indexed by parent version id fn get_version_by_parent( &mut self, client_key: Uuid, parent_version_id: Uuid, - ) -> Fallible>; + ) -> anyhow::Result>; /// Add a version (that must not already exist) fn add_version( @@ -50,16 +49,16 @@ pub(crate) trait StorageTxn { version_id: Uuid, parent_version_id: Uuid, history_segment: Vec, - ) -> Fallible<()>; + ) -> anyhow::Result<()>; /// Commit any changes made in the transaction. It is an error to call this more than /// once. It is safe to skip this call for read-only operations. - fn commit(&mut self) -> Fallible<()>; + fn commit(&mut self) -> anyhow::Result<()>; } /// A trait for objects able to act as storage. Most of the interesting behavior is in the /// [`crate::storage::StorageTxn`] trait. pub(crate) trait Storage: Send + Sync { /// Begin a transaction - fn txn<'a>(&'a self) -> Fallible>; + fn txn<'a>(&'a self) -> anyhow::Result>; } diff --git a/taskchampion/Cargo.toml b/taskchampion/Cargo.toml index e04610ceb..aa21c40cc 100644 --- a/taskchampion/Cargo.toml +++ b/taskchampion/Cargo.toml @@ -15,7 +15,8 @@ uuid = { version = "^0.8.1", features = ["serde", "v4"] } serde = "^1.0.104" serde_json = "^1.0" chrono = { version = "^0.4.10", features = ["serde"] } -failure = {version = "^0.1.5", features = ["derive"] } +anyhow = "1.0" +thiserror = "1.0" kv = {version = "^0.10.0", features = ["msgpack-value"]} lmdb-rkv = {version = "^0.12.3"} ureq = "^1.5.2" diff --git a/taskchampion/src/errors.rs b/taskchampion/src/errors.rs index 08884376f..801eb5926 100644 --- a/taskchampion/src/errors.rs +++ b/taskchampion/src/errors.rs @@ -1,7 +1,6 @@ -use failure::Fail; - -#[derive(Debug, Fail, Eq, PartialEq, Clone)] +use thiserror::Error; +#[derive(Debug, Error, Eq, PartialEq, Clone)] pub enum Error { - #[fail(display = "Task Database Error: {}", _0)] + #[error("Task Database Error: {}", _0)] DBError(String), } diff --git a/taskchampion/src/replica.rs b/taskchampion/src/replica.rs index f13bc19c2..f223e55aa 100644 --- a/taskchampion/src/replica.rs +++ b/taskchampion/src/replica.rs @@ -5,7 +5,6 @@ use crate::task::{Status, Task}; use crate::taskdb::TaskDB; use crate::workingset::WorkingSet; use chrono::Utc; -use failure::Fallible; use log::trace; use std::collections::HashMap; use uuid::Uuid; @@ -48,7 +47,7 @@ impl Replica { uuid: Uuid, property: S1, value: Option, - ) -> Fallible<()> + ) -> anyhow::Result<()> where S1: Into, S2: Into, @@ -62,12 +61,12 @@ impl Replica { } /// Add the given uuid to the working set, returning its index. - pub(crate) fn add_to_working_set(&mut self, uuid: Uuid) -> Fallible { + pub(crate) fn add_to_working_set(&mut self, uuid: Uuid) -> anyhow::Result { self.taskdb.add_to_working_set(uuid) } /// Get all tasks represented as a map keyed by UUID - pub fn all_tasks(&mut self) -> Fallible> { + pub fn all_tasks(&mut self) -> anyhow::Result> { let mut res = HashMap::new(); for (uuid, tm) in self.taskdb.all_tasks()?.drain(..) { res.insert(uuid, Task::new(uuid, tm)); @@ -76,18 +75,18 @@ impl Replica { } /// Get the UUIDs of all tasks - pub fn all_task_uuids(&mut self) -> Fallible> { + pub fn all_task_uuids(&mut self) -> anyhow::Result> { self.taskdb.all_task_uuids() } /// Get the "working set" for this replica. This is a snapshot of the current state, /// and it is up to the caller to decide how long to store this value. - pub fn working_set(&mut self) -> Fallible { + pub fn working_set(&mut self) -> anyhow::Result { Ok(WorkingSet::new(self.taskdb.working_set()?)) } /// Get an existing task by its UUID - pub fn get_task(&mut self, uuid: Uuid) -> Fallible> { + pub fn get_task(&mut self, uuid: Uuid) -> anyhow::Result> { Ok(self .taskdb .get_task(uuid)? @@ -95,7 +94,7 @@ impl Replica { } /// Create a new task. The task must not already exist. - pub fn new_task(&mut self, status: Status, description: String) -> Fallible { + pub fn new_task(&mut self, status: Status, description: String) -> anyhow::Result { let uuid = Uuid::new_v4(); self.taskdb.apply(Operation::Create { uuid })?; trace!("task {} created", uuid); @@ -109,7 +108,7 @@ impl Replica { /// Deleted; this is the final purge of the task. This is not a public method as deletion /// should only occur through expiration. #[allow(dead_code)] - fn delete_task(&mut self, uuid: Uuid) -> Fallible<()> { + fn delete_task(&mut self, uuid: Uuid) -> anyhow::Result<()> { // check that it already exists; this is a convenience check, as the task may already exist // when this Create operation is finally sync'd with operations from other replicas if self.taskdb.get_task(uuid)?.is_none() { @@ -123,7 +122,7 @@ impl Replica { /// Synchronize this replica against the given server. The working set is rebuilt after /// this occurs, but without renumbering, so any newly-pending tasks should appear in /// the working set. - pub fn sync(&mut self, server: &mut Box) -> Fallible<()> { + pub fn sync(&mut self, server: &mut Box) -> anyhow::Result<()> { self.taskdb.sync(server)?; self.rebuild_working_set(false) } @@ -132,7 +131,7 @@ impl Replica { /// `renumber` is true, then existing tasks may be moved to new working-set indices; in any /// case, on completion all pending tasks are in the working set and all non- pending tasks are /// not. - pub fn rebuild_working_set(&mut self, renumber: bool) -> Fallible<()> { + pub fn rebuild_working_set(&mut self, renumber: bool) -> anyhow::Result<()> { let pending = String::from(Status::Pending.to_taskmap()); self.taskdb .rebuild_working_set(|t| t.get("status") == Some(&pending), renumber)?; diff --git a/taskchampion/src/server/config.rs b/taskchampion/src/server/config.rs index 3de8243b4..efc444ed8 100644 --- a/taskchampion/src/server/config.rs +++ b/taskchampion/src/server/config.rs @@ -1,6 +1,5 @@ use super::types::Server; use super::{LocalServer, RemoteServer}; -use failure::Fallible; use std::path::PathBuf; use uuid::Uuid; @@ -27,7 +26,7 @@ pub enum ServerConfig { impl ServerConfig { /// Get a server based on this configuration - pub fn into_server(self) -> Fallible> { + pub fn into_server(self) -> anyhow::Result> { Ok(match self { ServerConfig::Local { server_dir } => Box::new(LocalServer::new(server_dir)?), ServerConfig::Remote { diff --git a/taskchampion/src/server/local.rs b/taskchampion/src/server/local.rs index 9cc4b2b28..f24ee96f6 100644 --- a/taskchampion/src/server/local.rs +++ b/taskchampion/src/server/local.rs @@ -2,7 +2,6 @@ use crate::server::{ AddVersionResult, GetVersionResult, HistorySegment, Server, VersionId, NO_VERSION_ID, }; use crate::utils::Key; -use failure::Fallible; use kv::msgpack::Msgpack; use kv::{Bucket, Config, Error, Integer, Serde, Store, ValueBuf}; use serde::{Deserialize, Serialize}; @@ -25,7 +24,7 @@ pub struct LocalServer<'t> { impl<'t> LocalServer<'t> { /// A test server has no notion of clients, signatures, encryption, etc. - pub fn new>(directory: P) -> Fallible> { + pub fn new>(directory: P) -> anyhow::Result> { let mut config = Config::default(directory); config.bucket("versions", None); config.bucket("numbers", None); @@ -48,7 +47,7 @@ impl<'t> LocalServer<'t> { }) } - fn get_latest_version_id(&mut self) -> Fallible { + fn get_latest_version_id(&mut self) -> anyhow::Result { let txn = self.store.read_txn()?; let base_version = match txn.get(&self.latest_version_bucket, 0.into()) { Ok(buf) => buf, @@ -60,7 +59,7 @@ impl<'t> LocalServer<'t> { Ok(base_version as VersionId) } - fn set_latest_version_id(&mut self, version_id: VersionId) -> Fallible<()> { + fn set_latest_version_id(&mut self, version_id: VersionId) -> anyhow::Result<()> { let mut txn = self.store.write_txn()?; txn.set( &self.latest_version_bucket, @@ -74,7 +73,7 @@ impl<'t> LocalServer<'t> { fn get_version_by_parent_version_id( &mut self, parent_version_id: VersionId, - ) -> Fallible> { + ) -> anyhow::Result> { let txn = self.store.read_txn()?; let version = match txn.get(&self.versions_bucket, parent_version_id.into()) { @@ -87,7 +86,7 @@ impl<'t> LocalServer<'t> { Ok(Some(version)) } - fn add_version_by_parent_version_id(&mut self, version: Version) -> Fallible<()> { + fn add_version_by_parent_version_id(&mut self, version: Version) -> anyhow::Result<()> { let mut txn = self.store.write_txn()?; txn.set( &self.versions_bucket, @@ -109,7 +108,7 @@ impl<'t> Server for LocalServer<'t> { &mut self, parent_version_id: VersionId, history_segment: HistorySegment, - ) -> Fallible { + ) -> anyhow::Result { // no client lookup // no signature validation @@ -133,7 +132,7 @@ impl<'t> Server for LocalServer<'t> { } /// Get a vector of all versions after `since_version` - fn get_child_version(&mut self, parent_version_id: VersionId) -> Fallible { + fn get_child_version(&mut self, parent_version_id: VersionId) -> anyhow::Result { if let Some(version) = self.get_version_by_parent_version_id(parent_version_id)? { Ok(GetVersionResult::Version { version_id: version.version_id, @@ -149,11 +148,10 @@ impl<'t> Server for LocalServer<'t> { #[cfg(test)] mod test { use super::*; - use failure::Fallible; use tempdir::TempDir; #[test] - fn test_empty() -> Fallible<()> { + fn test_empty() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut server = LocalServer::new(&tmp_dir.path())?; let child_version = server.get_child_version(NO_VERSION_ID)?; @@ -162,7 +160,7 @@ mod test { } #[test] - fn test_add_zero_base() -> Fallible<()> { + fn test_add_zero_base() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut server = LocalServer::new(&tmp_dir.path())?; let history = b"1234".to_vec(); @@ -187,7 +185,7 @@ mod test { } #[test] - fn test_add_nonzero_base() -> Fallible<()> { + fn test_add_nonzero_base() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut server = LocalServer::new(&tmp_dir.path())?; let history = b"1234".to_vec(); @@ -215,7 +213,7 @@ mod test { } #[test] - fn test_add_nonzero_base_forbidden() -> Fallible<()> { + fn test_add_nonzero_base_forbidden() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut server = LocalServer::new(&tmp_dir.path())?; let history = b"1234".to_vec(); diff --git a/taskchampion/src/server/remote/crypto.rs b/taskchampion/src/server/remote/crypto.rs index 89dc91398..3751d606f 100644 --- a/taskchampion/src/server/remote/crypto.rs +++ b/taskchampion/src/server/remote/crypto.rs @@ -1,5 +1,4 @@ use crate::server::HistorySegment; -use failure::{format_err, Fallible}; use std::convert::TryFrom; use std::io::Read; use tindercrypt::cryptors::RingCryptor; @@ -27,7 +26,7 @@ pub(super) struct HistoryCleartext { impl HistoryCleartext { /// Seal the payload into its ciphertext - pub(super) fn seal(self, secret: &Secret) -> Fallible { + pub(super) fn seal(self, secret: &Secret) -> anyhow::Result { let cryptor = RingCryptor::new().with_aad(self.parent_version_id.as_bytes()); let ciphertext = cryptor.seal_with_passphrase(secret.as_ref(), &self.history_segment)?; Ok(HistoryCiphertext(ciphertext)) @@ -42,7 +41,7 @@ impl HistoryCiphertext { self, secret: &Secret, parent_version_id: Uuid, - ) -> Fallible { + ) -> anyhow::Result { let cryptor = RingCryptor::new().with_aad(parent_version_id.as_bytes()); let plaintext = cryptor.open(secret.as_ref(), &self.0)?; @@ -54,16 +53,16 @@ impl HistoryCiphertext { } impl TryFrom for HistoryCiphertext { - type Error = failure::Error; + type Error = anyhow::Error; - fn try_from(resp: ureq::Response) -> Result { + fn try_from(resp: ureq::Response) -> Result { if let Some("application/vnd.taskchampion.history-segment") = resp.header("Content-Type") { let mut reader = resp.into_reader(); let mut bytes = vec![]; reader.read_to_end(&mut bytes)?; Ok(Self(bytes)) } else { - Err(format_err!("Response did not have expected content-type")) + Err(anyhow::anyhow!("Response did not have expected content-type")) } } } diff --git a/taskchampion/src/server/remote/mod.rs b/taskchampion/src/server/remote/mod.rs index cd20618ec..ed88d4b15 100644 --- a/taskchampion/src/server/remote/mod.rs +++ b/taskchampion/src/server/remote/mod.rs @@ -1,5 +1,4 @@ use crate::server::{AddVersionResult, GetVersionResult, HistorySegment, Server, VersionId}; -use failure::{format_err, Fallible}; use std::convert::TryInto; use uuid::Uuid; @@ -31,8 +30,8 @@ impl RemoteServer { } /// Convert a ureq::Response to an Error -fn resp_to_error(resp: ureq::Response) -> failure::Error { - return format_err!( +fn resp_to_error(resp: ureq::Response) -> anyhow::Error { + return anyhow::anyhow!( "error {}: {}", resp.status(), resp.into_string() @@ -41,12 +40,12 @@ fn resp_to_error(resp: ureq::Response) -> failure::Error { } /// Read a UUID-bearing header or fail trying -fn get_uuid_header(resp: &ureq::Response, name: &str) -> Fallible { +fn get_uuid_header(resp: &ureq::Response, name: &str) -> anyhow::Result { let value = resp .header(name) - .ok_or_else(|| format_err!("Response does not have {} header", name))?; + .ok_or_else(|| anyhow::anyhow!("Response does not have {} header", name))?; let value = Uuid::parse_str(value) - .map_err(|e| format_err!("{} header is not a valid UUID: {}", name, e))?; + .map_err(|e| anyhow::anyhow!("{} header is not a valid UUID: {}", name, e))?; Ok(value) } @@ -55,7 +54,7 @@ impl Server for RemoteServer { &mut self, parent_version_id: VersionId, history_segment: HistorySegment, - ) -> Fallible { + ) -> anyhow::Result { let url = format!("{}/client/add-version/{}", self.origin, parent_version_id); let history_cleartext = HistoryCleartext { parent_version_id, @@ -84,7 +83,7 @@ impl Server for RemoteServer { } } - fn get_child_version(&mut self, parent_version_id: VersionId) -> Fallible { + fn get_child_version(&mut self, parent_version_id: VersionId) -> anyhow::Result { let url = format!( "{}/client/get-child-version/{}", self.origin, parent_version_id diff --git a/taskchampion/src/server/test.rs b/taskchampion/src/server/test.rs index 3d57147ca..b8e439b47 100644 --- a/taskchampion/src/server/test.rs +++ b/taskchampion/src/server/test.rs @@ -1,7 +1,6 @@ use crate::server::{ AddVersionResult, GetVersionResult, HistorySegment, Server, VersionId, NO_VERSION_ID, }; -use failure::Fallible; use std::collections::HashMap; use uuid::Uuid; @@ -34,7 +33,7 @@ impl Server for TestServer { &mut self, parent_version_id: VersionId, history_segment: HistorySegment, - ) -> Fallible { + ) -> anyhow::Result { // no client lookup // no signature validation @@ -64,7 +63,7 @@ impl Server for TestServer { } /// Get a vector of all versions after `since_version` - fn get_child_version(&mut self, parent_version_id: VersionId) -> Fallible { + fn get_child_version(&mut self, parent_version_id: VersionId) -> anyhow::Result { if let Some(version) = self.versions.get(&parent_version_id) { Ok(GetVersionResult::Version { version_id: version.version_id, diff --git a/taskchampion/src/server/types.rs b/taskchampion/src/server/types.rs index b0a28a842..4478934d5 100644 --- a/taskchampion/src/server/types.rs +++ b/taskchampion/src/server/types.rs @@ -1,4 +1,3 @@ -use failure::Fallible; use uuid::Uuid; /// Versions are referred to with sha2 hashes. @@ -41,8 +40,8 @@ pub trait Server { &mut self, parent_version_id: VersionId, history_segment: HistorySegment, - ) -> Fallible; + ) -> anyhow::Result; /// Get the version with the given parent VersionId - fn get_child_version(&mut self, parent_version_id: VersionId) -> Fallible; + fn get_child_version(&mut self, parent_version_id: VersionId) -> anyhow::Result; } diff --git a/taskchampion/src/storage/config.rs b/taskchampion/src/storage/config.rs index 5ef964575..c87ae007d 100644 --- a/taskchampion/src/storage/config.rs +++ b/taskchampion/src/storage/config.rs @@ -1,5 +1,4 @@ use super::{InMemoryStorage, KVStorage, Storage}; -use failure::Fallible; use std::path::PathBuf; /// The configuration required for a replica's storage. @@ -14,7 +13,7 @@ pub enum StorageConfig { } impl StorageConfig { - pub fn into_storage(self) -> Fallible> { + pub fn into_storage(self) -> anyhow::Result> { Ok(match self { StorageConfig::OnDisk { taskdb_dir } => Box::new(KVStorage::new(taskdb_dir)?), StorageConfig::InMemory => Box::new(InMemoryStorage::new()), diff --git a/taskchampion/src/storage/inmemory.rs b/taskchampion/src/storage/inmemory.rs index e05f60258..e400d61bf 100644 --- a/taskchampion/src/storage/inmemory.rs +++ b/taskchampion/src/storage/inmemory.rs @@ -1,7 +1,6 @@ #![allow(clippy::new_without_default)] use crate::storage::{Operation, Storage, StorageTxn, TaskMap, VersionId, DEFAULT_BASE_VERSION}; -use failure::{bail, Fallible}; use std::collections::hash_map::Entry; use std::collections::HashMap; use uuid::Uuid; @@ -41,14 +40,14 @@ impl<'t> Txn<'t> { } impl<'t> StorageTxn for Txn<'t> { - fn get_task(&mut self, uuid: Uuid) -> Fallible> { + fn get_task(&mut self, uuid: Uuid) -> anyhow::Result> { match self.data_ref().tasks.get(&uuid) { None => Ok(None), Some(t) => Ok(Some(t.clone())), } } - fn create_task(&mut self, uuid: Uuid) -> Fallible { + fn create_task(&mut self, uuid: Uuid) -> anyhow::Result { if let ent @ Entry::Vacant(_) = self.mut_data_ref().tasks.entry(uuid) { ent.or_insert_with(TaskMap::new); Ok(true) @@ -57,16 +56,16 @@ impl<'t> StorageTxn for Txn<'t> { } } - fn set_task(&mut self, uuid: Uuid, task: TaskMap) -> Fallible<()> { + fn set_task(&mut self, uuid: Uuid, task: TaskMap) -> anyhow::Result<()> { self.mut_data_ref().tasks.insert(uuid, task); Ok(()) } - fn delete_task(&mut self, uuid: Uuid) -> Fallible { + fn delete_task(&mut self, uuid: Uuid) -> anyhow::Result { Ok(self.mut_data_ref().tasks.remove(&uuid).is_some()) } - fn all_tasks<'a>(&mut self) -> Fallible> { + fn all_tasks<'a>(&mut self) -> anyhow::Result> { Ok(self .data_ref() .tasks @@ -75,58 +74,58 @@ impl<'t> StorageTxn for Txn<'t> { .collect()) } - fn all_task_uuids<'a>(&mut self) -> Fallible> { + fn all_task_uuids<'a>(&mut self) -> anyhow::Result> { Ok(self.data_ref().tasks.keys().copied().collect()) } - fn base_version(&mut self) -> Fallible { + fn base_version(&mut self) -> anyhow::Result { Ok(self.data_ref().base_version) } - fn set_base_version(&mut self, version: VersionId) -> Fallible<()> { + fn set_base_version(&mut self, version: VersionId) -> anyhow::Result<()> { self.mut_data_ref().base_version = version; Ok(()) } - fn operations(&mut self) -> Fallible> { + fn operations(&mut self) -> anyhow::Result> { Ok(self.data_ref().operations.clone()) } - fn add_operation(&mut self, op: Operation) -> Fallible<()> { + fn add_operation(&mut self, op: Operation) -> anyhow::Result<()> { self.mut_data_ref().operations.push(op); Ok(()) } - fn set_operations(&mut self, ops: Vec) -> Fallible<()> { + fn set_operations(&mut self, ops: Vec) -> anyhow::Result<()> { self.mut_data_ref().operations = ops; Ok(()) } - fn get_working_set(&mut self) -> Fallible>> { + fn get_working_set(&mut self) -> anyhow::Result>> { Ok(self.data_ref().working_set.clone()) } - fn add_to_working_set(&mut self, uuid: Uuid) -> Fallible { + fn add_to_working_set(&mut self, uuid: Uuid) -> anyhow::Result { let working_set = &mut self.mut_data_ref().working_set; working_set.push(Some(uuid)); Ok(working_set.len()) } - fn set_working_set_item(&mut self, index: usize, uuid: Option) -> Fallible<()> { + fn set_working_set_item(&mut self, index: usize, uuid: Option) -> anyhow::Result<()> { let working_set = &mut self.mut_data_ref().working_set; if index >= working_set.len() { - bail!("Index {} is not in the working set", index); + anyhow::bail!("Index {} is not in the working set", index); } working_set[index] = uuid; Ok(()) } - fn clear_working_set(&mut self) -> Fallible<()> { + fn clear_working_set(&mut self) -> anyhow::Result<()> { self.mut_data_ref().working_set = vec![None]; Ok(()) } - fn commit(&mut self) -> Fallible<()> { + fn commit(&mut self) -> anyhow::Result<()> { // copy the new_data back into storage to commit the transaction if let Some(data) = self.new_data.take() { self.storage.data = data; @@ -156,7 +155,7 @@ impl InMemoryStorage { } impl Storage for InMemoryStorage { - fn txn<'a>(&'a mut self) -> Fallible> { + fn txn<'a>(&'a mut self) -> anyhow::Result> { Ok(Box::new(Txn { storage: self, new_data: None, @@ -172,7 +171,7 @@ mod test { // elsewhere and not tested here) #[test] - fn get_working_set_empty() -> Fallible<()> { + fn get_working_set_empty() -> anyhow::Result<()> { let mut storage = InMemoryStorage::new(); { @@ -185,7 +184,7 @@ mod test { } #[test] - fn add_to_working_set() -> Fallible<()> { + fn add_to_working_set() -> anyhow::Result<()> { let mut storage = InMemoryStorage::new(); let uuid1 = Uuid::new_v4(); let uuid2 = Uuid::new_v4(); @@ -207,7 +206,7 @@ mod test { } #[test] - fn clear_working_set() -> Fallible<()> { + fn clear_working_set() -> anyhow::Result<()> { let mut storage = InMemoryStorage::new(); let uuid1 = Uuid::new_v4(); let uuid2 = Uuid::new_v4(); diff --git a/taskchampion/src/storage/kv.rs b/taskchampion/src/storage/kv.rs index 5a5e06242..a08b6b284 100644 --- a/taskchampion/src/storage/kv.rs +++ b/taskchampion/src/storage/kv.rs @@ -1,6 +1,5 @@ use crate::storage::{Operation, Storage, StorageTxn, TaskMap, VersionId, DEFAULT_BASE_VERSION}; use crate::utils::Key; -use failure::{bail, Fallible}; use kv::msgpack::Msgpack; use kv::{Bucket, Config, Error, Integer, Serde, Store, ValueBuf}; use std::path::Path; @@ -21,7 +20,7 @@ const NEXT_OPERATION: u64 = 2; const NEXT_WORKING_SET_INDEX: u64 = 3; impl<'t> KVStorage<'t> { - pub fn new>(directory: P) -> Fallible> { + pub fn new>(directory: P) -> anyhow::Result> { let mut config = Config::default(directory); config.bucket("tasks", None); config.bucket("numbers", None); @@ -61,7 +60,7 @@ impl<'t> KVStorage<'t> { } impl<'t> Storage for KVStorage<'t> { - fn txn<'a>(&'a mut self) -> Fallible> { + fn txn<'a>(&'a mut self) -> anyhow::Result> { Ok(Box::new(Txn { storage: self, txn: Some(self.store.write_txn()?), @@ -103,7 +102,7 @@ impl<'t> Txn<'t> { } impl<'t> StorageTxn for Txn<'t> { - fn get_task(&mut self, uuid: Uuid) -> Fallible> { + fn get_task(&mut self, uuid: Uuid) -> anyhow::Result> { let bucket = self.tasks_bucket(); let buf = match self.kvtxn().get(bucket, uuid.into()) { Ok(buf) => buf, @@ -114,7 +113,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(Some(value)) } - fn create_task(&mut self, uuid: Uuid) -> Fallible { + fn create_task(&mut self, uuid: Uuid) -> anyhow::Result { let bucket = self.tasks_bucket(); let kvtxn = self.kvtxn(); match kvtxn.get(bucket, uuid.into()) { @@ -127,14 +126,14 @@ impl<'t> StorageTxn for Txn<'t> { } } - fn set_task(&mut self, uuid: Uuid, task: TaskMap) -> Fallible<()> { + fn set_task(&mut self, uuid: Uuid, task: TaskMap) -> anyhow::Result<()> { let bucket = self.tasks_bucket(); let kvtxn = self.kvtxn(); kvtxn.set(bucket, uuid.into(), Msgpack::to_value_buf(task)?)?; Ok(()) } - fn delete_task(&mut self, uuid: Uuid) -> Fallible { + fn delete_task(&mut self, uuid: Uuid) -> anyhow::Result { let bucket = self.tasks_bucket(); let kvtxn = self.kvtxn(); match kvtxn.del(bucket, uuid.into()) { @@ -144,7 +143,7 @@ impl<'t> StorageTxn for Txn<'t> { } } - fn all_tasks(&mut self) -> Fallible> { + fn all_tasks(&mut self) -> anyhow::Result> { let bucket = self.tasks_bucket(); let kvtxn = self.kvtxn(); let all_tasks: Result, Error> = kvtxn @@ -155,7 +154,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(all_tasks?) } - fn all_task_uuids(&mut self) -> Fallible> { + fn all_task_uuids(&mut self) -> anyhow::Result> { let bucket = self.tasks_bucket(); let kvtxn = self.kvtxn(); Ok(kvtxn @@ -165,7 +164,7 @@ impl<'t> StorageTxn for Txn<'t> { .collect()) } - fn base_version(&mut self) -> Fallible { + fn base_version(&mut self) -> anyhow::Result { let bucket = self.uuids_bucket(); let base_version = match self.kvtxn().get(bucket, BASE_VERSION.into()) { Ok(buf) => buf, @@ -177,7 +176,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(base_version as VersionId) } - fn set_base_version(&mut self, version: VersionId) -> Fallible<()> { + fn set_base_version(&mut self, version: VersionId) -> anyhow::Result<()> { let uuids_bucket = self.uuids_bucket(); let kvtxn = self.kvtxn(); @@ -189,7 +188,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(()) } - fn operations(&mut self) -> Fallible> { + fn operations(&mut self) -> anyhow::Result> { let bucket = self.operations_bucket(); let kvtxn = self.kvtxn(); let all_ops: Result, Error> = kvtxn @@ -204,7 +203,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(all_ops.iter().map(|(_, v)| v.clone()).collect()) } - fn add_operation(&mut self, op: Operation) -> Fallible<()> { + fn add_operation(&mut self, op: Operation) -> anyhow::Result<()> { let numbers_bucket = self.numbers_bucket(); let operations_bucket = self.operations_bucket(); let kvtxn = self.kvtxn(); @@ -228,7 +227,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(()) } - fn set_operations(&mut self, ops: Vec) -> Fallible<()> { + fn set_operations(&mut self, ops: Vec) -> anyhow::Result<()> { let numbers_bucket = self.numbers_bucket(); let operations_bucket = self.operations_bucket(); let kvtxn = self.kvtxn(); @@ -250,7 +249,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(()) } - fn get_working_set(&mut self) -> Fallible>> { + fn get_working_set(&mut self) -> anyhow::Result>> { let working_set_bucket = self.working_set_bucket(); let numbers_bucket = self.numbers_bucket(); let kvtxn = self.kvtxn(); @@ -273,7 +272,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(res) } - fn add_to_working_set(&mut self, uuid: Uuid) -> Fallible { + fn add_to_working_set(&mut self, uuid: Uuid) -> anyhow::Result { let working_set_bucket = self.working_set_bucket(); let numbers_bucket = self.numbers_bucket(); let kvtxn = self.kvtxn(); @@ -297,7 +296,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(next_index as usize) } - fn set_working_set_item(&mut self, index: usize, uuid: Option) -> Fallible<()> { + fn set_working_set_item(&mut self, index: usize, uuid: Option) -> anyhow::Result<()> { let working_set_bucket = self.working_set_bucket(); let numbers_bucket = self.numbers_bucket(); let kvtxn = self.kvtxn(); @@ -310,7 +309,7 @@ impl<'t> StorageTxn for Txn<'t> { }; if index >= next_index { - bail!("Index {} is not in the working set", index); + anyhow::bail!("Index {} is not in the working set", index); } if let Some(uuid) = uuid { @@ -326,7 +325,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(()) } - fn clear_working_set(&mut self) -> Fallible<()> { + fn clear_working_set(&mut self) -> anyhow::Result<()> { let working_set_bucket = self.working_set_bucket(); let numbers_bucket = self.numbers_bucket(); let kvtxn = self.kvtxn(); @@ -341,7 +340,7 @@ impl<'t> StorageTxn for Txn<'t> { Ok(()) } - fn commit(&mut self) -> Fallible<()> { + fn commit(&mut self) -> anyhow::Result<()> { if let Some(kvtxn) = self.txn.take() { kvtxn.commit()?; } else { @@ -355,11 +354,10 @@ impl<'t> StorageTxn for Txn<'t> { mod test { use super::*; use crate::storage::taskmap_with; - use failure::Fallible; use tempdir::TempDir; #[test] - fn test_create() -> Fallible<()> { + fn test_create() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid = Uuid::new_v4(); @@ -377,7 +375,7 @@ mod test { } #[test] - fn test_create_exists() -> Fallible<()> { + fn test_create_exists() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid = Uuid::new_v4(); @@ -395,7 +393,7 @@ mod test { } #[test] - fn test_get_missing() -> Fallible<()> { + fn test_get_missing() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid = Uuid::new_v4(); @@ -408,7 +406,7 @@ mod test { } #[test] - fn test_set_task() -> Fallible<()> { + fn test_set_task() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid = Uuid::new_v4(); @@ -429,7 +427,7 @@ mod test { } #[test] - fn test_delete_task_missing() -> Fallible<()> { + fn test_delete_task_missing() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid = Uuid::new_v4(); @@ -441,7 +439,7 @@ mod test { } #[test] - fn test_delete_task_exists() -> Fallible<()> { + fn test_delete_task_exists() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid = Uuid::new_v4(); @@ -458,7 +456,7 @@ mod test { } #[test] - fn test_all_tasks_empty() -> Fallible<()> { + fn test_all_tasks_empty() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; { @@ -470,7 +468,7 @@ mod test { } #[test] - fn test_all_tasks_and_uuids() -> Fallible<()> { + fn test_all_tasks_and_uuids() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid1 = Uuid::new_v4(); @@ -524,7 +522,7 @@ mod test { } #[test] - fn test_base_version_default() -> Fallible<()> { + fn test_base_version_default() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; { @@ -535,7 +533,7 @@ mod test { } #[test] - fn test_base_version_setting() -> Fallible<()> { + fn test_base_version_setting() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let u = Uuid::new_v4(); @@ -552,7 +550,7 @@ mod test { } #[test] - fn test_operations() -> Fallible<()> { + fn test_operations() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid1 = Uuid::new_v4(); @@ -616,7 +614,7 @@ mod test { } #[test] - fn get_working_set_empty() -> Fallible<()> { + fn get_working_set_empty() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; @@ -630,7 +628,7 @@ mod test { } #[test] - fn add_to_working_set() -> Fallible<()> { + fn add_to_working_set() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid1 = Uuid::new_v4(); @@ -653,7 +651,7 @@ mod test { } #[test] - fn clear_working_set() -> Fallible<()> { + fn clear_working_set() -> anyhow::Result<()> { let tmp_dir = TempDir::new("test")?; let mut storage = KVStorage::new(&tmp_dir.path())?; let uuid1 = Uuid::new_v4(); diff --git a/taskchampion/src/storage/mod.rs b/taskchampion/src/storage/mod.rs index fec354ed2..883f5e8b7 100644 --- a/taskchampion/src/storage/mod.rs +++ b/taskchampion/src/storage/mod.rs @@ -7,9 +7,9 @@ Typical uses of this crate do not interact directly with this module; [`StorageC However, users who wish to implement their own storage backends can implement the traits defined here and pass the result to [`Replica`](crate::Replica). */ -use failure::Fallible; use std::collections::HashMap; use uuid::Uuid; +use anyhow::Result; mod config; mod inmemory; @@ -55,66 +55,66 @@ pub(crate) const DEFAULT_BASE_VERSION: Uuid = crate::server::NO_VERSION_ID; /// It is safe and performant to drop transactions that did not modify any data without committing. pub trait StorageTxn { /// Get an (immutable) task, if it is in the storage - fn get_task(&mut self, uuid: Uuid) -> Fallible>; + fn get_task(&mut self, uuid: Uuid) -> Result>; /// Create an (empty) task, only if it does not already exist. Returns true if /// the task was created (did not already exist). - fn create_task(&mut self, uuid: Uuid) -> Fallible; + fn create_task(&mut self, uuid: Uuid) -> Result; /// Set a task, overwriting any existing task. If the task does not exist, this implicitly /// creates it (use `get_task` to check first, if necessary). - fn set_task(&mut self, uuid: Uuid, task: TaskMap) -> Fallible<()>; + fn set_task(&mut self, uuid: Uuid, task: TaskMap) -> Result<()>; /// Delete a task, if it exists. Returns true if the task was deleted (already existed) - fn delete_task(&mut self, uuid: Uuid) -> Fallible; + fn delete_task(&mut self, uuid: Uuid) -> Result; /// Get the uuids and bodies of all tasks in the storage, in undefined order. - fn all_tasks(&mut self) -> Fallible>; + fn all_tasks(&mut self) -> Result>; /// Get the uuids of all tasks in the storage, in undefined order. - fn all_task_uuids(&mut self) -> Fallible>; + fn all_task_uuids(&mut self) -> Result>; /// Get the current base_version for this storage -- the last version synced from the server. - fn base_version(&mut self) -> Fallible; + fn base_version(&mut self) -> Result; /// Set the current base_version for this storage. - fn set_base_version(&mut self, version: VersionId) -> Fallible<()>; + fn set_base_version(&mut self, version: VersionId) -> Result<()>; /// Get the current set of outstanding operations (operations that have not been sync'd to the /// server yet) - fn operations(&mut self) -> Fallible>; + fn operations(&mut self) -> Result>; /// Add an operation to the end of the list of operations in the storage. Note that this /// merely *stores* the operation; it is up to the TaskDB to apply it. - fn add_operation(&mut self, op: Operation) -> Fallible<()>; + fn add_operation(&mut self, op: Operation) -> Result<()>; /// Replace the current list of operations with a new list. - fn set_operations(&mut self, ops: Vec) -> Fallible<()>; + fn set_operations(&mut self, ops: Vec) -> Result<()>; /// Get the entire working set, with each task UUID at its appropriate (1-based) index. /// Element 0 is always None. - fn get_working_set(&mut self) -> Fallible>>; + fn get_working_set(&mut self) -> Result>>; /// Add a task to the working set and return its (one-based) index. This index will be one greater /// than the highest used index. - fn add_to_working_set(&mut self, uuid: Uuid) -> Fallible; + fn add_to_working_set(&mut self, uuid: Uuid) -> Result; /// Update the working set task at the given index. This cannot add a new item to the /// working set. - fn set_working_set_item(&mut self, index: usize, uuid: Option) -> Fallible<()>; + fn set_working_set_item(&mut self, index: usize, uuid: Option) -> Result<()>; /// Clear all tasks from the working set in preparation for a garbage-collection operation. /// Note that this is the only way items are removed from the set. - fn clear_working_set(&mut self) -> Fallible<()>; + fn clear_working_set(&mut self) -> Result<()>; /// Commit any changes made in the transaction. It is an error to call this more than /// once. - fn commit(&mut self) -> Fallible<()>; + fn commit(&mut self) -> Result<()>; } /// A trait for objects able to act as task storage. Most of the interesting behavior is in the /// [`crate::storage::StorageTxn`] trait. pub trait Storage { /// Begin a transaction - fn txn<'a>(&'a mut self) -> Fallible>; + fn txn<'a>(&'a mut self) -> Result>; } diff --git a/taskchampion/src/task.rs b/taskchampion/src/task.rs index fcf47f005..afc7fc253 100644 --- a/taskchampion/src/task.rs +++ b/taskchampion/src/task.rs @@ -1,7 +1,6 @@ use crate::replica::Replica; use crate::storage::TaskMap; use chrono::prelude::*; -use failure::{format_err, Fallible}; use log::trace; use std::convert::{TryFrom, TryInto}; use std::fmt; @@ -95,9 +94,9 @@ pub struct Tag(String); pub const INVALID_TAG_CHARACTERS: &str = "+-*/(<>^! %=~"; impl Tag { - fn from_str(value: &str) -> Result { - fn err(value: &str) -> Result { - Err(format_err!("invalid tag {:?}", value)) + fn from_str(value: &str) -> Result { + fn err(value: &str) -> Result { + anyhow::bail!("invalid tag {:?}", value) } if let Some(c) = value.chars().next() { @@ -119,7 +118,7 @@ impl Tag { } impl TryFrom<&str> for Tag { - type Error = failure::Error; + type Error = anyhow::Error; fn try_from(value: &str) -> Result { Self::from_str(value) @@ -127,7 +126,7 @@ impl TryFrom<&str> for Tag { } impl TryFrom<&String> for Tag { - type Error = failure::Error; + type Error = anyhow::Error; fn try_from(value: &String) -> Result { Self::from_str(&value[..]) @@ -264,7 +263,7 @@ impl<'r> TaskMut<'r> { /// Set the task's status. This also adds the task to the working set if the /// new status puts it in that set. - pub fn set_status(&mut self, status: Status) -> Fallible<()> { + pub fn set_status(&mut self, status: Status) -> anyhow::Result<()> { if status == Status::Pending { let uuid = self.uuid; self.replica.add_to_working_set(uuid)?; @@ -272,17 +271,17 @@ impl<'r> TaskMut<'r> { self.set_string("status", Some(String::from(status.to_taskmap()))) } - pub fn set_description(&mut self, description: String) -> Fallible<()> { + pub fn set_description(&mut self, description: String) -> anyhow::Result<()> { self.set_string("description", Some(description)) } - pub fn set_modified(&mut self, modified: DateTime) -> Fallible<()> { + pub fn set_modified(&mut self, modified: DateTime) -> anyhow::Result<()> { self.set_timestamp("modified", Some(modified)) } /// Start the task by creating "start. Fallible<()> { + pub fn start(&mut self) -> anyhow::Result<()> { if self.is_active() { return Ok(()); } @@ -291,7 +290,7 @@ impl<'r> TaskMut<'r> { } /// Stop the task by adding the current timestamp to all un-resolved "start." keys. - pub fn stop(&mut self) -> Fallible<()> { + pub fn stop(&mut self) -> anyhow::Result<()> { let keys = self .taskmap .iter() @@ -308,18 +307,18 @@ impl<'r> TaskMut<'r> { } /// Add a tag to this task. Does nothing if the tag is already present. - pub fn add_tag(&mut self, tag: &Tag) -> Fallible<()> { + pub fn add_tag(&mut self, tag: &Tag) -> anyhow::Result<()> { self.set_string(format!("tag.{}", tag), Some("".to_owned())) } /// Remove a tag from this task. Does nothing if the tag is not present. - pub fn remove_tag(&mut self, tag: &Tag) -> Fallible<()> { + pub fn remove_tag(&mut self, tag: &Tag) -> anyhow::Result<()> { self.set_string(format!("tag.{}", tag), None) } // -- utility functions - fn lastmod(&mut self) -> Fallible<()> { + fn lastmod(&mut self) -> anyhow::Result<()> { if !self.updated_modified { let now = format!("{}", Utc::now().timestamp()); self.replica @@ -331,7 +330,7 @@ impl<'r> TaskMut<'r> { Ok(()) } - fn set_string>(&mut self, property: S, value: Option) -> Fallible<()> { + fn set_string>(&mut self, property: S, value: Option) -> anyhow::Result<()> { let property = property.into(); self.lastmod()?; self.replica @@ -347,7 +346,7 @@ impl<'r> TaskMut<'r> { Ok(()) } - fn set_timestamp(&mut self, property: &str, value: Option>) -> Fallible<()> { + fn set_timestamp(&mut self, property: &str, value: Option>) -> anyhow::Result<()> { self.lastmod()?; if let Some(value) = value { let ts = format!("{}", value.timestamp()); @@ -364,7 +363,7 @@ impl<'r> TaskMut<'r> { /// Used by tests to ensure that updates are properly written #[cfg(test)] - fn reload(&mut self) -> Fallible<()> { + fn reload(&mut self) -> anyhow::Result<()> { let uuid = self.uuid; let task = self.replica.get_task(uuid)?.unwrap(); self.task.taskmap = task.taskmap; diff --git a/taskchampion/src/taskdb.rs b/taskchampion/src/taskdb.rs index cdf924ade..7bee3b741 100644 --- a/taskchampion/src/taskdb.rs +++ b/taskchampion/src/taskdb.rs @@ -1,7 +1,6 @@ use crate::errors::Error; use crate::server::{AddVersionResult, GetVersionResult, Server}; use crate::storage::{Operation, Storage, StorageTxn, TaskMap}; -use failure::{format_err, Fallible}; use log::{info, trace, warn}; use serde::{Deserialize, Serialize}; use std::collections::HashSet; @@ -34,7 +33,7 @@ impl TaskDB { /// Apply an operation to the TaskDB. Aside from synchronization operations, this is the only way /// to modify the TaskDB. In cases where an operation does not make sense, this function will do /// nothing and return an error (but leave the TaskDB in a consistent state). - pub fn apply(&mut self, op: Operation) -> Fallible<()> { + pub fn apply(&mut self, op: Operation) -> anyhow::Result<()> { // TODO: differentiate error types here? let mut txn = self.storage.txn()?; if let err @ Err(_) = TaskDB::apply_op(txn.as_mut(), &op) { @@ -45,7 +44,7 @@ impl TaskDB { Ok(()) } - fn apply_op(txn: &mut dyn StorageTxn, op: &Operation) -> Fallible<()> { + fn apply_op(txn: &mut dyn StorageTxn, op: &Operation) -> anyhow::Result<()> { match op { Operation::Create { uuid } => { // insert if the task does not already exist @@ -81,25 +80,25 @@ impl TaskDB { } /// Get all tasks. - pub fn all_tasks(&mut self) -> Fallible> { + pub fn all_tasks(&mut self) -> anyhow::Result> { let mut txn = self.storage.txn()?; txn.all_tasks() } /// Get the UUIDs of all tasks - pub fn all_task_uuids(&mut self) -> Fallible> { + pub fn all_task_uuids(&mut self) -> anyhow::Result> { let mut txn = self.storage.txn()?; txn.all_task_uuids() } /// Get the working set - pub fn working_set(&mut self) -> Fallible>> { + pub fn working_set(&mut self) -> anyhow::Result>> { let mut txn = self.storage.txn()?; txn.get_working_set() } /// Get a single task, by uuid. - pub fn get_task(&mut self, uuid: Uuid) -> Fallible> { + pub fn get_task(&mut self, uuid: Uuid) -> anyhow::Result> { let mut txn = self.storage.txn()?; txn.get_task(uuid) } @@ -108,7 +107,7 @@ impl TaskDB { /// renumbers the existing working-set tasks to eliminate gaps, and also adds any tasks that /// are not already in the working set but should be. The rebuild occurs in a single /// trasnsaction against the storage backend. - pub fn rebuild_working_set(&mut self, in_working_set: F, renumber: bool) -> Fallible<()> + pub fn rebuild_working_set(&mut self, in_working_set: F, renumber: bool) -> anyhow::Result<()> where F: Fn(&TaskMap) -> bool, { @@ -169,7 +168,7 @@ impl TaskDB { /// Add the given uuid to the working set and return its index; if it is already in the working /// set, its index is returned. This does *not* renumber any existing tasks. - pub fn add_to_working_set(&mut self, uuid: Uuid) -> Fallible { + pub fn add_to_working_set(&mut self, uuid: Uuid) -> anyhow::Result { let mut txn = self.storage.txn()?; // search for an existing entry for this task.. for (i, elt) in txn.get_working_set()?.iter().enumerate() { @@ -185,7 +184,7 @@ impl TaskDB { } /// Sync to the given server, pulling remote changes and pushing local changes. - pub fn sync(&mut self, server: &mut Box) -> Fallible<()> { + pub fn sync(&mut self, server: &mut Box) -> anyhow::Result<()> { let mut txn = self.storage.txn()?; // retry synchronizing until the server accepts our version (this allows for races between @@ -247,9 +246,9 @@ impl TaskDB { ); if let Some(requested) = requested_parent_version_id { if parent_version_id == requested { - return Err(format_err!( + anyhow::bail!( "Server's task history has diverged from this replica" - )); + ); } } requested_parent_version_id = Some(parent_version_id); @@ -261,7 +260,7 @@ impl TaskDB { Ok(()) } - fn apply_version(txn: &mut dyn StorageTxn, mut version: Version) -> Fallible<()> { + fn apply_version(txn: &mut dyn StorageTxn, mut version: Version) -> anyhow::Result<()> { // The situation here is that the server has already applied all server operations, and we // have already applied all local operations, so states have diverged by several // operations. We need to figure out what operations to apply locally and on the server in @@ -502,16 +501,16 @@ mod tests { } #[test] - fn rebuild_working_set_renumber() -> Fallible<()> { + fn rebuild_working_set_renumber() -> anyhow::Result<()> { rebuild_working_set(true) } #[test] - fn rebuild_working_set_no_renumber() -> Fallible<()> { + fn rebuild_working_set_no_renumber() -> anyhow::Result<()> { rebuild_working_set(false) } - fn rebuild_working_set(renumber: bool) -> Fallible<()> { + fn rebuild_working_set(renumber: bool) -> anyhow::Result<()> { let mut db = TaskDB::new_inmemory(); let mut uuids = vec![]; uuids.push(Uuid::new_v4());