From 2ac3947f548639ea73ae056eda978b257aeff04b Mon Sep 17 00:00:00 2001 From: Awiteb Date: Tue, 20 Aug 2024 11:34:30 +0000 Subject: [PATCH] refactor: Use `Either` type instade of `String` for index or name Signed-off-by: Awiteb --- src/cli/edit_command.rs | 28 +++++++++++---------- src/cli/get_command.rs | 13 ++++++---- src/cli/remove_command.rs | 28 +++++++++++---------- src/utils.rs | 52 +++++++++++++++++++-------------------- 4 files changed, 63 insertions(+), 58 deletions(-) diff --git a/src/cli/edit_command.rs b/src/cli/edit_command.rs index 23ad011..caa43a1 100644 --- a/src/cli/edit_command.rs +++ b/src/cli/edit_command.rs @@ -14,10 +14,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use std::num::NonZeroUsize; + use clap::Args; +use either::Either; use crate::{ - clap_parsers, + clap_parsers::{either_parser, kv_parser}, utils, vault::{cipher, Vaults}, LprsCommand, @@ -29,8 +32,8 @@ use crate::{ /// Edit command, used to edit the vault content pub struct Edit { /// The vault to edit, index or name - #[arg(name = "INDEX-or-NAME")] - location: String, + #[arg(name = "INDEX-or-NAME", value_parser = either_parser::)] + location: Either, #[arg(short, long)] /// The new vault name @@ -61,7 +64,7 @@ pub struct Edit { /// If the custom field not exist will created it, if it's will update it, /// if there is no value, you will enter it through a prompt (e.g `-c key`) #[arg(name = "KEY=VALUE", short = 'c', long = "custom")] - #[arg(value_parser = clap_parsers::kv_parser)] + #[arg(value_parser = kv_parser)] custom_fields: Vec<(String, Option)>, /// Force edit, will not return error if there is a problem with the args. /// @@ -72,16 +75,15 @@ pub struct Edit { impl LprsCommand for Edit { fn run(self, mut vault_manager: Vaults) -> LprsResult<()> { - let vault = - match utils::vault_by_index_or_name(self.location.trim(), &mut vault_manager.vaults) { - Ok((_, v)) => v, - Err(err) => { - if self.force { - return Ok(()); - } - return Err(err); + let vault = match utils::vault_by_index_or_name(self.location, &mut vault_manager.vaults) { + Ok((_, v)) => v, + Err(err) => { + if self.force { + return Ok(()); } - }; + return Err(err); + } + }; log::info!("Applying the new values to the vault"); if let Some(new_name) = self.name { diff --git a/src/cli/get_command.rs b/src/cli/get_command.rs index 237b1c1..93d5498 100644 --- a/src/cli/get_command.rs +++ b/src/cli/get_command.rs @@ -14,11 +14,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use std::str::FromStr; +use std::{num::NonZeroUsize, str::FromStr}; use clap::Args; +use either::Either; use crate::{ + clap_parsers::either_parser, utils, vault::{cipher, Vault, Vaults}, LprsCommand, @@ -94,8 +96,9 @@ impl VaultGetField { /// Command to get a entire vault or single field from it pub struct Get { /// Whether the index of the vault or its name - #[arg(value_name = "INDEX-or-NAME")] - location: String, + #[arg(name = "INDEX-or-NAME", value_parser = either_parser::)] + location: Either, + /// A Specific field to get. /// /// Can be [name, username, password, service, note, totp_secret, totp_code, @@ -103,13 +106,13 @@ pub struct Get { /// /// where the string means a custom field #[arg(value_parser = VaultGetField::from_str)] - field: Option, + field: Option, } impl LprsCommand for Get { fn run(self, mut vault_manager: Vaults) -> LprsResult<()> { let (index, vault) = - utils::vault_by_index_or_name(self.location.trim(), &mut vault_manager.vaults)?; + utils::vault_by_index_or_name(self.location, &mut vault_manager.vaults)?; if let Some(field) = self.field { if field == VaultGetField::Index { diff --git a/src/cli/remove_command.rs b/src/cli/remove_command.rs index 28d6323..d0a904d 100644 --- a/src/cli/remove_command.rs +++ b/src/cli/remove_command.rs @@ -14,16 +14,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use clap::Args; +use std::num::NonZeroUsize; -use crate::{utils, vault::Vaults, LprsCommand, LprsResult}; +use clap::Args; +use either::Either; + +use crate::{clap_parsers::either_parser, utils, vault::Vaults, LprsCommand, LprsResult}; #[derive(Debug, Args)] /// Remove command, used to remove a vault from the vaults file pub struct Remove { /// The vault to remove, index or name - #[arg(name = "INDEX-or-NAME")] - location: String, + #[arg(name = "INDEX-or-NAME", value_parser = either_parser::)] + location: Either, /// Force remove, will not return error if there is no vault with the given /// index or name @@ -33,16 +36,15 @@ pub struct Remove { impl LprsCommand for Remove { fn run(self, mut vault_manager: Vaults) -> LprsResult<()> { - let index = - match utils::vault_by_index_or_name(self.location.trim(), &mut vault_manager.vaults) { - Ok((idx, _)) => idx, - Err(err) => { - if self.force { - return Ok(()); - } - return Err(err); + let index = match utils::vault_by_index_or_name(self.location, &mut vault_manager.vaults) { + Ok((idx, _)) => idx, + Err(err) => { + if self.force { + return Ok(()); } - }; + return Err(err); + } + }; vault_manager.vaults.remove(index); vault_manager.try_export() } diff --git a/src/utils.rs b/src/utils.rs index 74eccba..86492a7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -15,8 +15,10 @@ // along with this program. If not, see . use std::collections::BTreeMap; +use std::num::NonZeroUsize; use std::{fs, path::PathBuf}; +use either::Either; use inquire::{validator::Validation, Password, PasswordDisplayMode}; use passwords::{analyzer, scorer}; #[cfg(feature = "update-notify")] @@ -231,35 +233,31 @@ pub fn prompt_custom( Ok(new_fields) } -/// Returns the vault with its index by its index or name +/// Returns the vault with its index by either its index or name /// /// ## Errors /// - If there is no vault with the given index or name -pub fn vault_by_index_or_name<'a>( - index_or_name: &str, - vaults: &'a mut [Vault], -) -> LprsResult<(usize, &'a mut Vault)> { - let parsed_index = index_or_name.parse::(); +pub fn vault_by_index_or_name( + location: Either, + vaults: &mut [Vault], +) -> LprsResult<(usize, &mut Vault)> { + let idx = location + .map_right(|name| { + vaults + .iter() + .enumerate() + .find_map(|(idx, v)| (v.name == name).then_some(idx)) + .ok_or_else(|| { + LprsError::Other(format!("There is no vault with the given name `{name}`")) + }) + }) + .map_left(|idx| LprsResult::Ok(idx.get() - 1)) + .into_inner()?; - let Some((index, vault)) = (if let Ok(index) = parsed_index { - index - .checked_sub(1) - .and_then(|zeroindex| vaults.get_mut(zeroindex).map(|v| (index, v))) - } else { - vaults - .iter_mut() - .enumerate() - .find(|(_, v)| v.name == index_or_name) - }) else { - return Err(LprsError::Other(format!( - "There is no vault with the given {} `{}`", - if parsed_index.is_ok() { - "index" - } else { - "name" - }, - index_or_name, - ))); - }; - Ok((index, vault)) + Ok(( + idx, + vaults.get_mut(idx).ok_or_else(|| { + LprsError::Other(format!("There is no vault with the given index `{idx}`")) + })?, + )) }