From d9314afa138d7698c919308ed223ac9d2c325a39 Mon Sep 17 00:00:00 2001 From: Jordan Doyle Date: Mon, 6 Jul 2020 16:53:37 +0100 Subject: [PATCH] Clean up type conversion in API impl --- onep-api-op/src/lib.rs | 143 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------------------------------------- onep-api/src/lib.rs | 3 +++ onep-cli/src/main.rs | 18 +++++++++++------- 3 files changed, 99 insertions(+), 65 deletions(-) diff --git a/onep-api-op/src/lib.rs b/onep-api-op/src/lib.rs index 00bf2f6..c121b72 100644 --- a/onep-api-op/src/lib.rs +++ b/onep-api-op/src/lib.rs @@ -1,3 +1,5 @@ +#![deny(clippy::pedantic)] + use serde::Deserialize; use serde_json::Value; use std::process::Command; @@ -11,7 +13,7 @@ pub enum 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) + Utf8(#[from] std::str::Utf8Error), } #[derive(Debug, Deserialize)] @@ -20,12 +22,30 @@ struct GetAccount { domain: String, } +impl Into for GetAccount { + fn into(self) -> onep_api::AccountMetadata { + onep_api::AccountMetadata { + name: self.name, + domain: self.domain, + } + } +} + #[derive(Debug, Deserialize)] struct ListVault { uuid: String, name: String, } +impl Into for ListVault { + fn into(self) -> onep_api::VaultMetadata { + onep_api::VaultMetadata { + uuid: self.uuid, + name: self.name, + } + } +} + #[derive(Debug, Deserialize)] #[serde(rename_all = "camelCase")] struct ListItem { @@ -36,6 +56,17 @@ struct ListItem { overview: ItemOverview, } +impl Into for ListItem { + fn into(self) -> onep_api::ItemMetadata { + onep_api::ItemMetadata { + title: self.overview.title, + account_info: self.overview.account_info, + uuid: self.uuid, + vault_uuid: self.vault_uuid, + } + } +} + #[derive(Debug, Deserialize)] struct ItemOverview { #[serde(rename = "URLs", default)] @@ -63,6 +94,35 @@ struct GetItem { overview: ItemOverview, } +impl Into for GetItem { + fn into(self) -> onep_api::Item { + onep_api::Item { + title: self.overview.title, + fields: self + .details + .fields + .into_iter() + .map(|f| f.into()) + .filter(|f: &onep_api::ItemField| !f.value.is_empty()) + .collect(), + sections: self + .details + .sections + .into_iter() + .map(|v| onep_api::ItemSection { + name: v.title, + fields: v + .fields + .into_iter() + .map(|f| f.into()) + .filter(|f: &onep_api::ItemField| !f.value.is_empty()) + .collect(), + }) + .collect(), + } + } +} + #[derive(Debug, Deserialize)] struct GetItemDetails { #[serde(default)] @@ -130,17 +190,18 @@ impl Into for GetItemSectionField { pub struct OnepasswordOp {} -impl OnepasswordOp { - 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(Error::Backend( - std::str::from_utf8(&cmd.stderr)?.to_string() - )) - } +fn exec(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(Error::Backend( + std::str::from_utf8(&cmd.stderr)?.to_string(), + )) } } @@ -148,33 +209,27 @@ impl onep_api::OnePassword for OnepasswordOp { type Error = Error; fn totp(&self, uuid: &str) -> Result { - Ok(std::str::from_utf8(&self.exec(&["get", "totp", uuid])?)?.to_string()) + Ok(std::str::from_utf8(&exec(&["get", "totp", uuid])?)?.to_string()) } fn account(&self) -> Result { - let ret: GetAccount = serde_json::from_slice(&self.exec(&["get", "account"])?)?; + let ret: GetAccount = serde_json::from_slice(&exec(&["get", "account"])?)?; - Ok(onep_api::AccountMetadata { - name: ret.name, - domain: ret.domain, - }) + Ok(ret.into()) } fn vaults(&self) -> Result, Self::Error> { - let ret: Vec = serde_json::from_slice(&self.exec(&["list", "vaults"])?)?; + let ret: Vec = serde_json::from_slice(&exec(&["list", "vaults"])?)?; - Ok(ret.into_iter() - .map(|v| onep_api::VaultMetadata { - uuid: v.uuid, - name: v.name, - }) - .collect()) + Ok(ret.into_iter().map(|v| v.into()).collect()) } + #[allow(clippy::filter_map)] fn search(&self, terms: Option<&str>) -> Result, Self::Error> { - let ret: Vec = serde_json::from_slice(&self.exec(&["list", "items"])?)?; + let ret: Vec = serde_json::from_slice(&exec(&["list", "items"])?)?; - Ok(ret.into_iter() + Ok(ret + .into_iter() .filter(|v| { if let Some(terms) = terms { v.uuid == terms @@ -187,41 +242,13 @@ impl onep_api::OnePassword for OnepasswordOp { true } }) - .map(|v| onep_api::ItemMetadata { - title: v.overview.title, - account_info: v.overview.account_info, - uuid: v.uuid, - vault_uuid: v.vault_uuid, - }) + .map(|v| v.into()) .collect()) } fn get(&self, uuid: &str) -> Result, Self::Error> { - let ret: GetItem = serde_json::from_slice(&self.exec(&["get", "item", uuid])?)?; + let ret: GetItem = serde_json::from_slice(&exec(&["get", "item", uuid])?)?; - Ok(Some(onep_api::Item { - title: ret.overview.title, - fields: ret - .details - .fields - .into_iter() - .map(|f| f.into()) - .filter(|f: &onep_api::ItemField| !f.value.is_empty()) - .collect(), - sections: ret - .details - .sections - .into_iter() - .map(|v| onep_api::ItemSection { - name: v.title, - fields: v - .fields - .into_iter() - .map(|f| f.into()) - .filter(|f: &onep_api::ItemField| !f.value.is_empty()) - .collect(), - }) - .collect(), - })) + Ok(Some(ret.into())) } } diff --git a/onep-api/src/lib.rs b/onep-api/src/lib.rs index ee203b5..55f78d0 100644 --- a/onep-api/src/lib.rs +++ b/onep-api/src/lib.rs @@ -1,3 +1,6 @@ +#![deny(clippy::pedantic)] +#![allow(clippy::missing_errors_doc)] + #[derive(Debug)] pub struct AccountMetadata { pub name: String, diff --git a/onep-cli/src/main.rs b/onep-cli/src/main.rs index 598e3bc..9840657 100644 --- a/onep-cli/src/main.rs +++ b/onep-cli/src/main.rs @@ -1,5 +1,7 @@ +#![deny(clippy::pedantic)] + use clap::Clap; -use colored::*; +use colored::Colorize; use itertools::Itertools; use onep_api::OnePassword; use term_table::{ @@ -36,15 +38,18 @@ enum Opt { } fn main() { - if let Err(e) = run() { + if let Err(e) = run(&onep_api_op::OnepasswordOp {}) { eprintln!("{}", e); std::process::exit(1); } } -fn run() -> anyhow::Result<()> { - let imp = onep_api_op::OnepasswordOp {}; - +#[warn(clippy::too_many_lines)] +#[allow(clippy::non_ascii_literal)] +fn run(imp: &T) -> anyhow::Result<()> +where + T::Error: 'static + std::error::Error + Send + Sync, +{ match Opt::parse() { Opt::Ls { show_uuids, @@ -67,8 +72,7 @@ fn run() -> anyhow::Result<()> { let vault = vaults .iter() .find(|v| v.uuid == vault) - .map(|v| v.name.clone()) - .unwrap_or_else(|| format!("Unknown Vault ({})", vault)); + .map_or_else(|| format!("Unknown Vault ({})", vault), |v| v.name.clone()); println!( "{} {}", -- libgit2 1.7.2