make printing less complicated and refactor cli #5
10 changed files with 261 additions and 162 deletions
61
.vscode/launch.json
vendored
61
.vscode/launch.json
vendored
|
@ -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": [
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
43
cli/src/commands/add.rs
Normal 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
8
cli/src/commands/mod.rs
Normal 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
88
cli/src/commands/print.rs
Normal 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,
|
||||
}
|
||||
}
|
23
cli/src/commands/remove.rs
Normal file
23
cli/src/commands/remove.rs
Normal 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
28
cli/src/commands/utils.rs
Normal 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;
|
||||
}
|
|
@ -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(())
|
||||
|
|
Loading…
Reference in a new issue