Generate errors, allow API impls to define their own errors
Diff
Cargo.lock | 5 ++---
onep-api-op/Cargo.toml | 3 ++-
onep-api/Cargo.toml | 3 +--
onep-cli/Cargo.toml | 1 +
onep-api-op/src/lib.rs | 43 ++++++++++++++++++++++++++++++++++++-------
onep-api/src/lib.rs | 22 ++++++++--------------
onep-cli/src/main.rs | 8 +++++++-
7 files changed, 48 insertions(+), 37 deletions(-)
@@ -175,9 +175,6 @@
[[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 @@
"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 @@
"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]]
@@ -10,4 +10,5 @@
onep-api = { path = "../onep-api" }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_with = "1.5.0-alpha.1"
serde_with = "1.5.0-alpha.1"
thiserror = "1.0"
@@ -6,5 +6,4 @@
[dependencies]
thiserror = "1.0"
[dependencies]
@@ -15,4 +15,5 @@
itertools = "0.9"
colored = "1.9"
thiserror = "1.0"
anyhow = "1.0"
@@ -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 @@
pub struct OnepasswordOp {}
impl OnepasswordOp {
fn exec(&self, args: &[&str]) -> Result<Vec<u8>, OnePasswordApiError> {
let cmd = Command::new("op").args(args).output().map_err(OnePasswordApiError::Exec)?;
fn exec(&self, args: &[&str]) -> Result<Vec<u8>, 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<String, OnePasswordApiError> {
Ok(std::str::from_utf8(&self.exec(&["get", "totp", uuid])?).unwrap().to_string())
type Error = Error;
fn totp(&self, uuid: &str) -> Result<String, Self::Error> {
Ok(std::str::from_utf8(&self.exec(&["get", "totp", uuid])?)?.to_string())
}
fn account(&self) -> Result<onep_api::AccountMetadata, OnePasswordApiError> {
let ret: GetAccount = serde_json::from_slice(&self.exec(&["get", "account"])?).unwrap();
fn account(&self) -> Result<onep_api::AccountMetadata, Self::Error> {
let ret: GetAccount = serde_json::from_slice(&self.exec(&["get", "account"])?)?;
Ok(onep_api::AccountMetadata {
name: ret.name,
@@ -147,8 +160,8 @@
})
}
fn vaults(&self) -> Result<Vec<onep_api::VaultMetadata>, OnePasswordApiError> {
let ret: Vec<ListVault> = serde_json::from_slice(&self.exec(&["list", "vaults"])?).unwrap();
fn vaults(&self) -> Result<Vec<onep_api::VaultMetadata>, Self::Error> {
let ret: Vec<ListVault> = serde_json::from_slice(&self.exec(&["list", "vaults"])?)?;
Ok(ret.into_iter()
.map(|v| onep_api::VaultMetadata {
@@ -158,8 +171,8 @@
.collect())
}
fn search(&self, terms: Option<&str>) -> Result<Vec<onep_api::ItemMetadata>, OnePasswordApiError> {
let ret: Vec<ListItem> = serde_json::from_slice(&self.exec(&["list", "items"])?).unwrap();
fn search(&self, terms: Option<&str>) -> Result<Vec<onep_api::ItemMetadata>, Self::Error> {
let ret: Vec<ListItem> = serde_json::from_slice(&self.exec(&["list", "items"])?)?;
Ok(ret.into_iter()
.filter(|v| {
@@ -183,8 +196,8 @@
.collect())
}
fn get(&self, uuid: &str) -> Result<Option<onep_api::Item>, OnePasswordApiError> {
let ret: GetItem = serde_json::from_slice(&self.exec(&["get", "item", uuid])?).unwrap();
fn get(&self, uuid: &str) -> Result<Option<onep_api::Item>, Self::Error> {
let ret: GetItem = serde_json::from_slice(&self.exec(&["get", "item", uuid])?)?;
Ok(Some(onep_api::Item {
title: ret.overview.title,
@@ -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 trait OnePassword {
fn totp(&self, uuid: &str) -> Result<String, OnePasswordApiError>;
fn account(&self) -> Result<AccountMetadata, OnePasswordApiError>;
fn vaults(&self) -> Result<Vec<VaultMetadata>, OnePasswordApiError>;
fn search(&self, terms: Option<&str>) -> Result<Vec<ItemMetadata>, OnePasswordApiError>;
fn get(&self, uuid: &str) -> Result<Option<Item>, OnePasswordApiError>;
type Error;
fn totp(&self, uuid: &str) -> Result<String, Self::Error>;
fn account(&self) -> Result<AccountMetadata, Self::Error>;
fn vaults(&self) -> Result<Vec<VaultMetadata>, Self::Error>;
fn search(&self, terms: Option<&str>) -> Result<Vec<ItemMetadata>, Self::Error>;
fn get(&self, uuid: &str) -> Result<Option<Item>, Self::Error>;
}
@@ -8,6 +8,12 @@
Table, TableStyle,
};
#[derive(thiserror::Error, Debug)]
enum Error {
#[error("Couldn't find the requested item.")]
NotFound,
}
#[derive(Clap, Debug)]
#[clap(author, version)]
@@ -125,7 +131,7 @@
}
}
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();