make printing less complicated and refactor cli

i made printing less complicated by making printing both the name and
the url with the seperator the default option and using both those flags
at the same time should do the same thing as just printing without any
flags.

i also refactored commands into their own module folder with each
command getting their own file module.
This commit is contained in:
Fries 2023-07-02 19:46:19 -07:00
parent df86523df2
commit 82e8f68862
10 changed files with 261 additions and 162 deletions

61
.vscode/launch.json vendored
View file

@ -1,15 +1,62 @@
{ {
// Use IntelliSense to learn about possible attributes. // Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes. // Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0", "version": "0.2.0",
"configurations": [ "configurations": [
{ {
"type": "lldb", "type": "lldb",
"request": "launch", "request": "launch",
"name": "run meowy-cli", "name": "meowy-cli (Print)",
"program": "${workspaceFolder}/target/debug/meowy-cli", "program": "${workspaceFolder}/target/debug/meowy-cli",
"args": ["print"], "args": [
"print"
],
"cwd": "${workspaceFolder}",
"sourceMap": {},
"sourceLanguages": [
"rust"
],
},
{
"type": "lldb",
"request": "launch",
"name": "meowy-cli (Print) json",
"program": "${workspaceFolder}/target/debug/meowy-cli",
"args": [
"print",
"--json"
],
"cwd": "${workspaceFolder}",
"sourceMap": {},
"sourceLanguages": [
"rust"
],
},
{
"type": "lldb",
"request": "launch",
"name": "meowy-cli (Print) only url",
"program": "${workspaceFolder}/target/debug/meowy-cli",
"args": [
"print",
"--url"
],
"cwd": "${workspaceFolder}",
"sourceMap": {},
"sourceLanguages": [
"rust"
],
},
{
"type": "lldb",
"request": "launch",
"name": "meowy-cli (Print) only name",
"program": "${workspaceFolder}/target/debug/meowy-cli",
"args": [
"print",
"--name"
],
"cwd": "${workspaceFolder}", "cwd": "${workspaceFolder}",
"sourceMap": {}, "sourceMap": {},
"sourceLanguages": [ "sourceLanguages": [

View file

@ -9,7 +9,7 @@ serde_json = "1.0"
log = "0.4" log = "0.4"
[dependencies.clap] [dependencies.clap]
version = "4" version = "4"
features = ["derive"] features = ["derive"]
[dependencies.shared] [dependencies.shared]
@ -18,6 +18,7 @@ path = "../shared"
[dependencies.simple_logger] [dependencies.simple_logger]
version = "4" version = "4"
default-features = false default-features = false
features = ["stderr"]
[[bin]] [[bin]]
name = "meowy-cli" name = "meowy-cli"

View file

@ -5,6 +5,12 @@ use clap::{arg, command, Args, Parser, Subcommand};
pub(crate) struct Arguments { pub(crate) struct Arguments {
#[arg(help = "the path to the names.json file", long, short)] #[arg(help = "the path to the names.json file", long, short)]
pub(crate) path: Option<String>, pub(crate) path: Option<String>,
#[arg(
long,
short,
help = "a seperator string to seperate the url from the name. defaults to : with a space after that."
)]
pub(crate) seperator: Option<String>,
#[command(subcommand)] #[command(subcommand)]
pub(crate) command: Commands, pub(crate) command: Commands,
} }
@ -17,20 +23,11 @@ pub(crate) enum Commands {
filter: Option<String>, filter: Option<String>,
#[command(flatten)] #[command(flatten)]
group: PrintGroup, group: PrintGroup,
#[arg(
long,
short,
help = "a seperator character to seperate the url from the name. defaults to ,",
requires = "url",
requires = "name"
)]
seperator: Option<char>,
#[arg( #[arg(
long, long,
short, short,
conflicts_with = "url", conflicts_with = "url",
conflicts_with = "name", conflicts_with = "name",
conflicts_with = "seperator",
help = "print the data out as a json string" help = "print the data out as a json string"
)] )]
json: bool, json: bool,

View file

@ -1,141 +0,0 @@
use std::path::Path;
use shared::errors::ErrorStatus;
use shared::names;
use shared::{errors::Error, names::Site};
use crate::arguments::PrintGroup;
fn group_printing(seperator: &Option<char>, site: &Site, group: &PrintGroup) {
let mut string = String::new();
let delimiter = seperator.unwrap_or(',');
if group.url {
string += &site.url;
}
if group.name {
if !string.is_empty() {
string += &format!(
"{}{}",
delimiter,
site.name.as_ref().unwrap_or(&"None".into())
)
} else {
string += &site.name.as_ref().unwrap_or(&"None".into());
}
}
log::info!("{}", string);
}
fn json_printing(site: &Site) -> Result<(), Error> {
match serde_json::to_string(&site) {
Ok(json) => {
log::info!("{}", json);
Ok(())
}
Err(err) => Err(Error {
status: ErrorStatus::ParsingError,
data: err.to_string(),
}),
}
}
fn filter_site(
site: &Site,
json: bool,
seperator: &Option<char>,
group: &PrintGroup,
) -> Result<(), Error> {
if json {
json_printing(site)?;
return Ok(());
}
if !group.url && !group.name {
log::info!("{:?}", site);
return Ok(());
}
return Ok(group_printing(seperator, site, group));
}
pub(crate) fn print(
path: &Path,
filter: &Option<String>,
group: &PrintGroup,
seperator: &Option<char>,
json: bool,
) -> Result<(), Error> {
let names_file = names::read_names_file(path)?;
let mut names = names::load_names(names_file)?;
if let Some(filter) = filter {
names.retain(|f| &f.url == filter);
if names.len() == 0 {
return Err(Error {
status: ErrorStatus::NotFoundError,
data: "this url was not found in names.json".into(),
});
}
return filter_site(&names[0], json, seperator, group);
}
for site in names {
if json {
json_printing(&site)?;
continue;
}
if !group.url && !group.name {
log::info!("{:?}", site);
continue;
}
group_printing(seperator, &site, group);
}
Ok(())
}
pub(crate) fn add(path: &Path, url: &String, name: &Option<String>) -> Result<(), Error> {
let names_file = names::read_names_file(path)?;
let mut names = names::load_names(names_file)?;
if names.iter().any(|site| site.url.contains(url)) {
return Err(Error {
status: ErrorStatus::AlreadyExistsError,
data:
"this url already exists in names.json. you can't have more then 1 of the same url."
.into(),
});
}
let site = Site {
url: url.to_string(),
name: name.to_owned(),
};
log::debug!("adding {:?} to {}", site, path.display());
names.push(site.clone());
let json = serde_json::to_string(&names).unwrap();
std::fs::write(path, json).unwrap();
log::info!("added {:?} to names.json", site);
Ok(())
}
pub(crate) fn remove(path: &Path, url: &String) -> Result<(), Error> {
let names_file = names::read_names_file(path)?;
let mut names = names::load_names(names_file)?;
names.retain(|site| {
if &site.url == url {
log::info!("removing {:?} from names.json", site);
}
&site.url != url
});
let json = serde_json::to_string(&names).unwrap();
std::fs::write(path, json).unwrap();
Ok(())
}

43
cli/src/commands/add.rs Normal file
View file

@ -0,0 +1,43 @@
use shared::{
errors::{Error, ErrorStatus},
names::{self, Site},
};
use std::path::Path;
use crate::commands::utils::{site_string, PrintOptions};
pub(crate) fn add(
path: &Path,
url: &String,
name: &Option<String>,
seperator: &String,
) -> Result<(), Error> {
let names_file = names::read_names_file(path)?;
let mut names = names::load_names(names_file)?;
if names.iter().any(|site| site.url.contains(url)) {
return Err(Error {
status: ErrorStatus::AlreadyExistsError,
data:
"this url already exists in names.json. you can't have more then 1 of the same url."
.into(),
});
}
let site = Site {
url: url.to_string(),
name: name.to_owned(),
};
log::debug!("adding {:?} to {}", site, path.display());
names.push(site.clone());
let json = serde_json::to_string(&names).unwrap();
std::fs::write(path, json).unwrap();
println!(
"added {} to names.json",
site_string(&site, PrintOptions::All, seperator)
);
Ok(())
}

8
cli/src/commands/mod.rs Normal file
View file

@ -0,0 +1,8 @@
mod add;
mod print;
mod remove;
mod utils;
pub(crate) use add::add;
pub(crate) use print::print;
pub(crate) use remove::remove;

88
cli/src/commands/print.rs Normal file
View file

@ -0,0 +1,88 @@
use crate::{arguments::PrintGroup, commands::utils::site_string};
use shared::{
errors::{Error, ErrorStatus},
names::{self, Site},
};
use std::path::Path;
use super::utils::PrintOptions;
pub(crate) fn print(
path: &Path,
filter: &Option<String>,
group: &PrintGroup,
seperator: &String,
json: bool,
) -> Result<(), Error> {
let names_file = names::read_names_file(path)?;
let mut names = names::load_names(names_file)?;
if let Some(filter) = filter {
names.retain(|f| &f.url == filter);
if names.len() == 0 {
return Err(Error {
status: ErrorStatus::NotFoundError,
data: "this url was not found in names.json".into(),
});
}
return filter_site(&names[0], json, seperator, group);
}
for site in names {
if json {
json_printing(&site)?;
continue;
}
printing(seperator, &site, group);
}
Ok(())
}
fn filter_site(
site: &Site,
json: bool,
seperator: &String,
group: &PrintGroup,
) -> Result<(), Error> {
if json {
json_printing(site)?;
return Ok(());
}
return Ok(printing(seperator, site, group));
}
fn json_printing(site: &Site) -> Result<(), Error> {
match serde_json::to_string(&site) {
Ok(json) => {
println!("{}", json);
Ok(())
}
Err(err) => Err(Error {
status: ErrorStatus::ParsingError,
data: err.to_string(),
}),
}
}
fn printing(seperator: &String, site: &Site, group: &PrintGroup) {
let string = site_string(site, print_group_to_options(group), seperator);
println!("{}", string);
}
fn print_group_to_options(group: &PrintGroup) -> PrintOptions {
match group {
PrintGroup {
url: true,
name: false,
} => PrintOptions::Url,
PrintGroup {
url: false,
name: true,
} => PrintOptions::Name,
_ => PrintOptions::All,
}
}

View file

@ -0,0 +1,23 @@
use shared::{errors::Error, names};
use std::path::Path;
use crate::commands::utils::{site_string, PrintOptions};
pub(crate) fn remove(path: &Path, url: &String, seperator: &String) -> Result<(), Error> {
let names_file = names::read_names_file(path)?;
let mut names = names::load_names(names_file)?;
names.retain(|site| {
if &site.url == url {
println!(
"removing {} from names.json",
site_string(&site, PrintOptions::All, seperator)
);
}
&site.url != url
});
let json = serde_json::to_string(&names).unwrap();
std::fs::write(path, json).unwrap();
Ok(())
}

28
cli/src/commands/utils.rs Normal file
View file

@ -0,0 +1,28 @@
use shared::names::Site;
pub(super) enum PrintOptions {
Url,
Name,
All,
}
pub(super) fn site_string(site: &Site, options: PrintOptions, seperator: &String) -> String {
let mut string = String::new();
if matches!(options, PrintOptions::Url) || matches!(options, PrintOptions::All) {
string += &site.url;
}
if let Some(name) = &site.name {
if matches!(options, PrintOptions::Url) {
return string;
}
if !string.is_empty() {
string += &format!("{}{}", seperator, name)
} else {
string += name;
}
}
return string;
}

View file

@ -1,8 +1,8 @@
use std::path::Path;
use arguments::{Arguments, Commands}; use arguments::{Arguments, Commands};
use clap::Parser; use clap::Parser;
use commands::{add, print, remove}; use commands::{add, print, remove};
use shared::{directories, errors::Error}; use shared::{directories, errors::Error};
use std::path::Path;
mod arguments; mod arguments;
mod commands; mod commands;
@ -13,6 +13,7 @@ fn main() -> Result<(), Error> {
let default_path = directories::get_names_path()?; let default_path = directories::get_names_path()?;
let args = Arguments::parse(); let args = Arguments::parse();
let seperator = args.seperator.unwrap_or(": ".into());
let path = match &args.path { let path = match &args.path {
Some(path) => Path::new(path), Some(path) => Path::new(path),
@ -20,9 +21,13 @@ fn main() -> Result<(), Error> {
}; };
match &args.command { match &args.command {
Commands::Print { filter, group, seperator, json, } => print(path, filter, group, seperator, *json)?, Commands::Print {
Commands::Add { url, name } => add(path, url, name)?, filter,
Commands::Remove { url } => remove(path, url)?, group,
json,
} => print(path, filter, group, &seperator, *json)?,
Commands::Add { url, name } => add(path, url, name, &seperator)?,
Commands::Remove { url } => remove(path, url, &seperator)?,
}; };
Ok(()) Ok(())