From c91b370741752da0929ada4978af1edec70885e6 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Mon, 6 Jul 2020 16:36:39 +0100 Subject: [PATCH] Generate errors, allow API impls to define their own errors --- Cargo.lock | 5 ++--- onep-api-op/Cargo.toml | 3 ++- onep-api-op/src/lib.rs | 43 ++++++++++++++++++++++++++++--------------- onep-api/Cargo.toml | 3 +-- onep-api/src/lib.rs | 22 +++++++--------------- onep-cli/Cargo.toml | 1 + onep-cli/src/main.rs | 8 +++++++- 7 files changed, 48 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5a20de1..cce23b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -175,9 +175,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "onep-api" version = "0.1.0" -dependencies = [ - "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "onep-api-op" @@ -187,6 +184,7 @@ dependencies = [ "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", "serde_with 1.5.0-alpha.1 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -200,6 +198,7 @@ dependencies = [ "onep-api 0.1.0", "onep-api-op 0.1.0", "term-table 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 1.0.20 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/onep-api-op/Cargo.toml b/onep-api-op/Cargo.toml index 19b3e3a..f7a4e12 100644 --- a/onep-api-op/Cargo.toml +++ b/onep-api-op/Cargo.toml @@ -10,4 +10,5 @@ edition = "2018" onep-api = { path = "../onep-api" } serde = { version = "1", features = ["derive"] } serde_json = "1" -serde_with = "1.5.0-alpha.1" \ No newline at end of file +serde_with = "1.5.0-alpha.1" +thiserror = "1.0" \ No newline at end of file diff --git a/onep-api-op/src/lib.rs b/onep-api-op/src/lib.rs index 1e2e7fa..00bf2f6 100644 --- a/onep-api-op/src/lib.rs +++ b/onep-api-op/src/lib.rs @@ -1,8 +1,19 @@ use serde::Deserialize; use serde_json::Value; -use onep_api::OnePasswordApiError; use std::process::Command; +#[derive(thiserror::Error, Debug)] +pub enum Error { + #[error("op backend returned an error:\n{0}")] + Backend(String), + #[error("failed to exec backend:\n{0}")] + Exec(std::io::Error), + #[error("failed to parse json from op:\n{0}")] + Json(#[from] serde_json::error::Error), + #[error("failed to convert op response to utf-8:\n{0}")] + Utf8(#[from] std::str::Utf8Error) +} + #[derive(Debug, Deserialize)] struct GetAccount { name: String, @@ -120,26 +131,28 @@ impl Into for GetItemSectionField { pub struct OnepasswordOp {} impl OnepasswordOp { - fn exec(&self, args: &[&str]) -> Result, OnePasswordApiError> { - let cmd = Command::new("op").args(args).output().map_err(OnePasswordApiError::Exec)?; + fn exec(&self, args: &[&str]) -> Result, Error> { + let cmd = Command::new("op").args(args).output().map_err(Error::Exec)?; if cmd.status.success() { Ok(cmd.stdout) } else { - Err(OnePasswordApiError::Backend( - std::str::from_utf8(&cmd.stderr).unwrap().to_string() + Err(Error::Backend( + std::str::from_utf8(&cmd.stderr)?.to_string() )) } } } impl onep_api::OnePassword for OnepasswordOp { - fn totp(&self, uuid: &str) -> Result { - Ok(std::str::from_utf8(&self.exec(&["get", "totp", uuid])?).unwrap().to_string()) + type Error = Error; + + fn totp(&self, uuid: &str) -> Result { + Ok(std::str::from_utf8(&self.exec(&["get", "totp", uuid])?)?.to_string()) } - fn account(&self) -> Result { - let ret: GetAccount = serde_json::from_slice(&self.exec(&["get", "account"])?).unwrap(); + fn account(&self) -> Result { + let ret: GetAccount = serde_json::from_slice(&self.exec(&["get", "account"])?)?; Ok(onep_api::AccountMetadata { name: ret.name, @@ -147,8 +160,8 @@ impl onep_api::OnePassword for OnepasswordOp { }) } - fn vaults(&self) -> Result, OnePasswordApiError> { - let ret: Vec = serde_json::from_slice(&self.exec(&["list", "vaults"])?).unwrap(); + fn vaults(&self) -> Result, Self::Error> { + let ret: Vec = serde_json::from_slice(&self.exec(&["list", "vaults"])?)?; Ok(ret.into_iter() .map(|v| onep_api::VaultMetadata { @@ -158,8 +171,8 @@ impl onep_api::OnePassword for OnepasswordOp { .collect()) } - fn search(&self, terms: Option<&str>) -> Result, OnePasswordApiError> { - let ret: Vec = serde_json::from_slice(&self.exec(&["list", "items"])?).unwrap(); + fn search(&self, terms: Option<&str>) -> Result, Self::Error> { + let ret: Vec = serde_json::from_slice(&self.exec(&["list", "items"])?)?; Ok(ret.into_iter() .filter(|v| { @@ -183,8 +196,8 @@ impl onep_api::OnePassword for OnepasswordOp { .collect()) } - fn get(&self, uuid: &str) -> Result, OnePasswordApiError> { - let ret: GetItem = serde_json::from_slice(&self.exec(&["get", "item", uuid])?).unwrap(); + fn get(&self, uuid: &str) -> Result, Self::Error> { + let ret: GetItem = serde_json::from_slice(&self.exec(&["get", "item", uuid])?)?; Ok(Some(onep_api::Item { title: ret.overview.title, diff --git a/onep-api/Cargo.toml b/onep-api/Cargo.toml index 57b5b99..09bee57 100644 --- a/onep-api/Cargo.toml +++ b/onep-api/Cargo.toml @@ -6,5 +6,4 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] -thiserror = "1.0" \ No newline at end of file +[dependencies] \ No newline at end of file diff --git a/onep-api/src/lib.rs b/onep-api/src/lib.rs index fd6523c..ee203b5 100644 --- a/onep-api/src/lib.rs +++ b/onep-api/src/lib.rs @@ -1,13 +1,3 @@ -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum OnePasswordApiError { - #[error("1password backend returned an error:\n{0}")] - Backend(String), - #[error("failed to exec backend:\n{0}")] - Exec(std::io::Error), -} - #[derive(Debug)] pub struct AccountMetadata { pub name: String, @@ -48,9 +38,11 @@ pub struct ItemSection { } pub trait OnePassword { - fn totp(&self, uuid: &str) -> Result; - fn account(&self) -> Result; - fn vaults(&self) -> Result, OnePasswordApiError>; - fn search(&self, terms: Option<&str>) -> Result, OnePasswordApiError>; - fn get(&self, uuid: &str) -> Result, OnePasswordApiError>; + type Error; + + fn totp(&self, uuid: &str) -> Result; + fn account(&self) -> Result; + fn vaults(&self) -> Result, Self::Error>; + fn search(&self, terms: Option<&str>) -> Result, Self::Error>; + fn get(&self, uuid: &str) -> Result, Self::Error>; } diff --git a/onep-cli/Cargo.toml b/onep-cli/Cargo.toml index 581178b..d1d5e68 100644 --- a/onep-cli/Cargo.toml +++ b/onep-cli/Cargo.toml @@ -15,4 +15,5 @@ term-table = "1.3" itertools = "0.9" colored = "1.9" +thiserror = "1.0" anyhow = "1.0" \ No newline at end of file diff --git a/onep-cli/src/main.rs b/onep-cli/src/main.rs index 51ff0b0..598e3bc 100644 --- a/onep-cli/src/main.rs +++ b/onep-cli/src/main.rs @@ -8,6 +8,12 @@ use term_table::{ Table, TableStyle, }; +#[derive(thiserror::Error, Debug)] +enum Error { + #[error("Couldn't find the requested item.")] + NotFound, +} + #[derive(Clap, Debug)] #[clap(author, version)] /// 1password cli for humans @@ -125,7 +131,7 @@ fn run() -> anyhow::Result<()> { } } Opt::Show { uuid } => { - let result = imp.get(&uuid)?.unwrap(); + let result = imp.get(&uuid)?.ok_or(Error::NotFound)?; let mut table = Table::new(); table.style = TableStyle::extended(); -- libgit2 1.7.2