make printing less complicated and refactor cli #5

Merged
Fries merged 2 commits from improvements into main 2023-07-03 23:20:54 +00:00
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.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "run meowy-cli",
"name": "meowy-cli (Print)",
"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}",
"sourceMap": {},
"sourceLanguages": [

View file

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

View file

@ -5,6 +5,12 @@ use clap::{arg, command, Args, Parser, Subcommand};
pub(crate) struct Arguments {
#[arg(help = "the path to the names.json file", long, short)]
pub(crate) path: Option<String>,
#[arg(
long,
short,
help = "a separator string to seperate the url from the name. defaults to : with a space after that."
)]
pub(crate) separator: Option<String>,
#[command(subcommand)]
pub(crate) command: Commands,
}
@ -17,20 +23,11 @@ pub(crate) enum Commands {
filter: Option<String>,
#[command(flatten)]
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(
long,
short,
conflicts_with = "url",
conflicts_with = "name",
conflicts_with = "seperator",
help = "print the data out as a json string"
)]
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>,
separator: &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, separator)
);
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,
separator: &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, separator, group);
}
for site in names {
if json {
json_printing(&site)?;
continue;
}
printing(separator, &site, group);
}
Ok(())
}
fn filter_site(
site: &Site,
json: bool,
separator: &String,
group: &PrintGroup,
) -> Result<(), Error> {
if json {
json_printing(site)?;
return Ok(());
}
return Ok(printing(separator, 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(separator: &String, site: &Site, group: &PrintGroup) {
let string = site_string(site, print_group_to_options(group), separator);
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, separator: &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, separator)
);
}
&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, separator: &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!("{}{}", separator, name)
} else {
string += name;
}
}
return string;
}

View file

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