From 8206cc61055b4d8cc36586cfedf3026a84e8cdd2 Mon Sep 17 00:00:00 2001 From: Fries Date: Sat, 1 Jul 2023 18:27:03 -0700 Subject: [PATCH] make the cli more portable, and add logging the cli now uses a new module in the shared crate, called directories which is a module that has functions for directory stuff, mainly, it uses the directories crate to have a portable way to have directories for the application like data directories and config directories. i also added logging to the shared and cli crates, so you can see debug stuff with the RUST_LOG environment variable. --- .vscode/launch.json | 24 +++--- Cargo.lock | 174 ++++++++++++++++++++++++++++++++++---- cli/Cargo.toml | 5 ++ cli/src/arguments.rs | 4 +- cli/src/commands.rs | 32 ++++--- cli/src/main.rs | 31 +++++-- shared/Cargo.toml | 2 + shared/src/directories.rs | 35 ++++++++ shared/src/errors.rs | 18 ++-- shared/src/lib.rs | 1 + shared/src/names.rs | 46 +++++++++- 11 files changed, 319 insertions(+), 53 deletions(-) create mode 100644 shared/src/directories.rs diff --git a/.vscode/launch.json b/.vscode/launch.json index 10efcb2..abb9e2b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,13 +4,17 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ - { - "type": "lldb", - "request": "launch", - "name": "Debug", - "program": "${workspaceFolder}/", - "args": [], - "cwd": "${workspaceFolder}" - } - ] -} \ No newline at end of file + { + "type": "lldb", + "request": "launch", + "name": "run meowy-cli", + "program": "${workspaceFolder}/target/debug/meowy-cli", + "args": ["print"], + "cwd": "${workspaceFolder}", + "sourceMap": {}, + "sourceLanguages": [ + "rust" + ], + } + ] +} diff --git a/Cargo.lock b/Cargo.lock index d7d739a..2361b82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,7 +53,7 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b" dependencies = [ - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -63,7 +63,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" dependencies = [ "anstyle", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -253,9 +253,11 @@ name = "cli" version = "0.1.0" dependencies = [ "clap", + "log", "serde", "serde_json", "shared", + "simple_logger", ] [[package]] @@ -337,6 +339,27 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "directories" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a49173b84e034382284f27f1af4dcbbd231ffa358c0fe316541a7337f376a35" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys 0.48.0", +] + [[package]] name = "either" version = "1.8.1" @@ -366,7 +389,7 @@ checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" dependencies = [ "errno-dragonfly", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -653,7 +676,7 @@ checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ "hermit-abi 0.3.1", "libc", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -665,7 +688,7 @@ dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", "rustix", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -790,7 +813,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "wasi", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -858,6 +881,12 @@ version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "overload" version = "0.1.1" @@ -882,7 +911,7 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", "windows-targets", ] @@ -995,6 +1024,15 @@ dependencies = [ "getrandom", ] +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "redox_syscall" version = "0.3.5" @@ -1004,6 +1042,17 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall 0.2.16", + "thiserror", +] + [[package]] name = "ref-cast" version = "1.0.16" @@ -1187,7 +1236,7 @@ dependencies = [ "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1287,6 +1336,8 @@ dependencies = [ name = "shared" version = "0.1.0" dependencies = [ + "directories", + "log", "serde", "serde_json", ] @@ -1300,6 +1351,16 @@ dependencies = [ "libc", ] +[[package]] +name = "simple_logger" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2230cd5c29b815c9b699fb610b49a5ed65588f3509d9f0108be3a885da629333" +dependencies = [ + "log", + "windows-sys 0.42.0", +] + [[package]] name = "slab" version = "0.4.8" @@ -1375,9 +1436,29 @@ dependencies = [ "autocfg", "cfg-if", "fastrand", - "redox_syscall", + "redox_syscall 0.3.5", "rustix", - "windows-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1432,7 +1513,7 @@ dependencies = [ "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys", + "windows-sys 0.48.0", ] [[package]] @@ -1707,6 +1788,21 @@ dependencies = [ "windows-targets", ] +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1722,51 +1818,93 @@ version = "0.48.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.0" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index a79600c..58e580d 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" [dependencies] serde = "1.0" serde_json = "1.0" +log = "0.4" [dependencies.clap] version = "4" @@ -14,6 +15,10 @@ features = ["derive"] [dependencies.shared] path = "../shared" +[dependencies.simple_logger] +version = "4" +default-features = false + [[bin]] name = "meowy-cli" path = "src/main.rs" diff --git a/cli/src/arguments.rs b/cli/src/arguments.rs index 952da36..713c70b 100644 --- a/cli/src/arguments.rs +++ b/cli/src/arguments.rs @@ -3,8 +3,8 @@ use clap::{arg, command, Args, Parser, Subcommand}; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] pub(crate) struct Arguments { - #[arg(help = "the path to the names.json file")] - pub(crate) path: String, + #[arg(help = "the path to the names.json file", long, short)] + pub(crate) path: Option, #[command(subcommand)] pub(crate) command: Commands, } diff --git a/cli/src/commands.rs b/cli/src/commands.rs index e2cdebb..4668d71 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use shared::{ errors::{Error, ErrorStatus}, names::Site, @@ -5,50 +7,58 @@ use shared::{ use crate::arguments::PrintGroup; -fn read_names(path: &String) -> Result, Error> { - match std::fs::read_to_string(path) { +fn read_names(path: &Path) -> Result, Error> { + match shared::names::read_names_file(path) { Ok(names) => { return shared::names::load_names(names); } Err(err) => Err(Error { status: ErrorStatus::IOError, - data: err.to_string(), + data: err.data, }), } } -pub(crate) fn print(path: &String, group: &PrintGroup) -> Result<(), Error> { +pub(crate) fn print(path: &Path, group: &PrintGroup) -> Result<(), Error> { let names = read_names(path)?; Ok(for site in names { if group.name { - println!("{}", site.name.unwrap_or_default()); + log::info!("{}", site.name.unwrap_or_default()); continue; } if group.url { - println!("{}", site.url); + log::info!("{}", site.url); continue; } - println!("{:?}", site); + log::info!("{:?}", site); }) } -pub(crate) fn add(path: &String, url: &String, name: &Option) -> Result<(), Error> { +pub(crate) fn add(path: &Path, url: &String, name: &Option) -> Result<(), Error> { let mut names = read_names(path)?; let site = Site { url: url.to_string(), name: name.to_owned(), }; - names.push(site); + 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: &String, url: &String) -> Result<(), Error> { +pub(crate) fn remove(path: &Path, url: &String) -> Result<(), Error> { let mut names = read_names(path)?; - names.retain(|site| &site.url != url); + 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(()) } diff --git a/cli/src/main.rs b/cli/src/main.rs index 621e6b3..98f76fd 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -1,18 +1,39 @@ +use std::path::Path; + use arguments::{Arguments, Commands}; use clap::Parser; use commands::{add, print, remove}; -use shared::errors::Error; +use log::LevelFilter; +use shared::{ + directories, + errors::{Error, ErrorStatus}, +}; +use simple_logger::SimpleLogger; mod arguments; mod commands; -fn main() -> Result<(), Error> { +fn main() -> Result<(), Error> { + if let Err(err) = SimpleLogger::new().with_level(LevelFilter::Info).env().init() { + return Err(Error { + status: ErrorStatus::LoggerInitializationError, + data: err.to_string(), + }); + } + + let directory = directories::get_project_dir()?; let args = Arguments::parse(); + let default_path = directories::get_file_from_directory(directory.data_dir(), "names.json")?; + + let path = match &args.path { + Some(path) => Path::new(path), + None => &default_path, + }; match &args.command { - Commands::Print { group } => print(&args.path, &group)?, - Commands::Add { url, name } => add(&args.path, url, name)?, - Commands::Remove { url } => remove(&args.path, url)?, + Commands::Print { group } => print(path, &group)?, + Commands::Add { url, name } => add(path, url, name)?, + Commands::Remove { url } => remove(path, url)?, }; Ok(()) diff --git a/shared/Cargo.toml b/shared/Cargo.toml index aa08613..aba26a9 100644 --- a/shared/Cargo.toml +++ b/shared/Cargo.toml @@ -5,6 +5,8 @@ edition = "2021" [dependencies] serde_json = "1.0" +directories = "5.0" +log = "0.4" [dependencies.serde] version = "1.0" diff --git a/shared/src/directories.rs b/shared/src/directories.rs new file mode 100644 index 0000000..195cf46 --- /dev/null +++ b/shared/src/directories.rs @@ -0,0 +1,35 @@ +use std::path::{Path, PathBuf}; + +use directories::ProjectDirs; + +use crate::errors::{Error, ErrorStatus, DIRECTORIES_ERROR_MESSAGE}; + +pub fn get_project_dir() -> Result { + match ProjectDirs::from("moe", "solarpunk", "meowy-webring") { + Some(project) => Ok(project), + None => Err(Error { + status: ErrorStatus::DirectoriesError, + data: DIRECTORIES_ERROR_MESSAGE.into(), + }), + } +} + +pub fn get_file_from_directory(path: &Path, filename: &str) -> Result { + if !path.exists() { + create_directory(path)?; + } + Ok(path.join(filename)) +} + +fn create_directory(path: &Path) -> Result<(), Error> { + match std::fs::create_dir_all(path) { + Ok(_) => { + log::debug!("created the directory {}", path.display()); + Ok(()) + } + Err(err) => Err(Error { + status: ErrorStatus::IOError, + data: err.to_string(), + }), + } +} diff --git a/shared/src/errors.rs b/shared/src/errors.rs index 8a033d5..22d62ef 100644 --- a/shared/src/errors.rs +++ b/shared/src/errors.rs @@ -1,16 +1,24 @@ #[derive(Debug)] pub enum ErrorStatus { IOError, - ParsingError + ParsingError, + DirectoriesError, + LoggerInitializationError } pub struct Error { pub status: ErrorStatus, - pub data: String + pub data: String, } +pub(crate) static DIRECTORIES_ERROR_MESSAGE: &str = "could not retreive a valid home path from the operating system. maybe try to define the HOME enviroment variable if you\'re on a unix or unix like operating system."; + impl core::fmt::Debug for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "A {:?} error has occured.\nDetails: {}", self.status, self.data) - } + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "A {:?} error has occured.\nDetails: {}", + self.status, self.data + ) + } } diff --git a/shared/src/lib.rs b/shared/src/lib.rs index c986a43..cc9af96 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -1,2 +1,3 @@ pub mod names; pub mod errors; +pub mod directories; diff --git a/shared/src/names.rs b/shared/src/names.rs index 6408d6c..3683914 100644 --- a/shared/src/names.rs +++ b/shared/src/names.rs @@ -1,8 +1,10 @@ +use std::path::Path; + use serde::{Deserialize, Serialize}; use crate::errors::{Error, ErrorStatus}; -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct Site { pub url: String, pub name: Option, @@ -10,10 +12,50 @@ pub struct Site { pub fn load_names(names: String) -> Result, Error> { match serde_json::from_str::>(&names) { - Ok(content) => Ok(content), + Ok(content) => { + log::debug!("successfully parsed names.json."); + Ok(content) + } Err(err) => Err(Error { status: ErrorStatus::ParsingError, data: err.to_string(), }), } } + +pub fn read_names_file(path: &Path) -> Result { + if !path.exists() { + log::debug!( + "the names.json file does not exist at {}. creating names.json", + path.display() + ); + create_names_file(path)? + } + + match std::fs::read_to_string(path) { + Ok(data) => { + log::debug!( + "successfully read the names.json file at {}", + path.display() + ); + Ok(data) + } + Err(err) => Err(Error { + status: ErrorStatus::IOError, + data: err.to_string(), + }), + } +} + +fn create_names_file(path: &Path) -> Result<(), Error> { + match std::fs::write(path, "[]") { + Ok(_) => { + log::debug!("created a names.json file at {}", path.display()); + Ok(()) + } + Err(err) => Err(Error { + status: ErrorStatus::IOError, + data: err.to_string(), + }), + } +}