diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..dc7a348 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,14 @@ +[alias] # command aliases +b = "build" +br = "build --release" +c = "check" +t = "test" +r = "run" +rr = "run --release" +w = "clippy -- -D warnings" +recursive_example = "rr --example recursions" +space_example = ["run", "--release", "--", "\"command list\""] + +[future-incompat-report] +frequency = 'always' # when to display a notification about a future incompat report + diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index bc26909..cc3d268 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -20,3 +20,5 @@ jobs: run: cargo build --verbose - name: Run tests run: cargo test --verbose + - name: Lint + run: cargo clippy -- -D warnings diff --git a/Cargo.lock b/Cargo.lock index 193e885..37d5c9b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,9 +49,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" [[package]] name = "block-buffer" @@ -88,9 +88,9 @@ checksum = "2e93abca9e28e0a1b9877922aacb20576e05d4679ffa78c3d6dc22a26a216659" [[package]] name = "cc" -version = "1.2.17" +version = "1.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fcb57c740ae1daf453ae85f16e37396f672b039e00d9d866e07ddb24e328e3a" +checksum = "d0fc897dc1e865cc67c0e05a836d9d3f1df3cbe442aa4a9473b18e12624a4951" dependencies = [ "shlex", ] @@ -103,9 +103,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.40" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" +checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" dependencies = [ "android-tzdata", "iana-time-zone", @@ -241,9 +241,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" [[package]] name = "heck" @@ -253,9 +253,9 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "iana-time-zone" -version = "0.1.62" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2fd658b06e56721792c5df4475705b6cda790e9298d19d2f8af083457bcd127" +checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -277,9 +277,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.8.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" dependencies = [ "equivalent", "hashbrown", @@ -291,7 +291,7 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fddf93031af70e75410a2511ec04d49e758ed2f26dad3404a934e0fb45cc12a" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", "crossterm", "dyn-clone", "fuzzy-matcher", @@ -326,15 +326,15 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.171" +version = "0.2.172" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" +checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa" [[package]] name = "lock_api" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" +checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" dependencies = [ "autocfg", "scopeguard", @@ -415,7 +415,7 @@ dependencies = [ [[package]] name = "nyx" -version = "2.8.0" +version = "2.10.2" dependencies = [ "bincode", "chrono", @@ -434,9 +434,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.1" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75b0bedcc4fe52caa0e03d9f1151a323e4aa5e2d78ba3580400cd3c9e2bc4bc" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" [[package]] name = "papergrid" @@ -451,9 +451,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" +checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" dependencies = [ "lock_api", "parking_lot_core", @@ -461,9 +461,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" +checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" dependencies = [ "cfg-if", "libc", @@ -502,9 +502,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.94" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] @@ -520,11 +520,11 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.10" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" +checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af" dependencies = [ - "bitflags 2.9.0", + "bitflags 2.9.1", ] [[package]] @@ -558,9 +558,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustversion" -version = "1.0.20" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" +checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" [[package]] name = "ryu" @@ -634,9 +634,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" dependencies = [ "libc", "signal-hook-registry", @@ -655,24 +655,24 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" dependencies = [ "libc", ] [[package]] name = "smallvec" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" +checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" [[package]] name = "syn" -version = "2.0.100" +version = "2.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" dependencies = [ "proc-macro2", "quote", @@ -753,9 +753,9 @@ checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" [[package]] name = "toml" -version = "0.8.20" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" +checksum = "05ae329d1f08c4d17a59bed7ff5b5a769d062e64a62d34a3261b219e62cd5aae" dependencies = [ "serde", "serde_spanned", @@ -765,26 +765,33 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" +checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.24" +version = "0.22.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" +checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e" dependencies = [ "indexmap", "serde", "serde_spanned", "toml_datetime", + "toml_write", "winnow", ] +[[package]] +name = "toml_write" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfb942dfe1d8e29a7ee7fcbde5bd2b9a25fb89aa70caea2eba3bee836ff41076" + [[package]] name = "typenum" version = "1.18.0" @@ -909,11 +916,37 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.52.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" dependencies = [ - "windows-targets 0.52.6", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -922,6 +955,24 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" +[[package]] +name = "windows-result" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +dependencies = [ + "windows-link", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -1063,9 +1114,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.7.4" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index c919896..6e80df3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nyx" -version = "2.8.0" +version = "2.10.2" edition = "2021" authors = ["Elouan DA COSTA PEIXOTO "] description = "A CLI tool for managing your projects." diff --git a/src/cleanup/mod.rs b/src/cleanup/mod.rs index 93546c0..cbfc5f1 100644 --- a/src/cleanup/mod.rs +++ b/src/cleanup/mod.rs @@ -4,16 +4,14 @@ use crate::{nxfs::nxs, utils}; use inquire::{InquireError, Select}; use lrncore::usage_exit::command_usage; -pub fn cleanup_help() -> String { - let usage = r" +pub fn cleanup_help() -> &'static str{ + (r" Usage: nyx cleanup Options: -h, --help Show this help message -"; - - usage.to_string() +") as _ } pub fn choose_cleanup() { @@ -21,10 +19,10 @@ pub fn choose_cleanup() { if let Some(arg) = args.iter().last() { match arg.as_str().trim() { "-h" => { - command_usage(&cleanup_help()); + command_usage(cleanup_help()); } "--help" => { - command_usage(&cleanup_help()); + command_usage(cleanup_help()); } _ => {} } @@ -61,7 +59,7 @@ fn prune_docker_unused() { if !confirm { return; } - let mut prune_throbber = utils::custom_throbber("Prune all unused docker files".to_string()); + let mut prune_throbber = utils::custom_throbber("Prune all unused docker files"); prune_throbber.start(); // docker builder let mut docker_builder = Command::new("docker") @@ -75,7 +73,7 @@ fn prune_docker_unused() { .wait() .expect("Failed to wait the docker builder command"); if !wait_docker_builder.success() { - prune_throbber.fail("Error prune the docker builder cache".to_string()); + prune_throbber.fail("Error prune the docker builder cache".to_owned()); panic!(); } // docker volumes @@ -90,7 +88,7 @@ fn prune_docker_unused() { .wait() .expect("Failed to wait the docker volume prune command"); if !wait_docker_volumes.success() { - prune_throbber.fail("Error prune the unused docker volume".to_string()); + prune_throbber.fail("Error prune the unused docker volume".to_owned()); panic!(); } // docker images @@ -105,16 +103,16 @@ fn prune_docker_unused() { .wait() .expect("Failed to wait the docker image prune command"); if !wait_docker_images.success() { - prune_throbber.fail("Error prune the unused docker image".to_string()); + prune_throbber.fail("Error prune the unused docker image".to_owned()); panic!(); } - prune_throbber.success("Successfully prune all unused docker files".to_string()); + prune_throbber.success("Successfully prune all unused docker files".to_owned()); prune_throbber.end(); } -// this function remove all build cache, -// node_modules, bin folder content of the -// project managed by nyx +/// This function removes all build cache, +/// node_modules, bin folder content of the +/// project managed by nyx fn prune_project_unused() { let confirm = utils::prompt::confirm_prompt( "Are you sure you want to prune all project dependency/build related files", @@ -128,22 +126,22 @@ fn prune_project_unused() { println!("Cleaning up all projects by removing dependency folders (node_modules), compiled files (dist), and executable binaries (bin) that are no longer needed."); for i in &projects { // Node.js - let node_module_path = i.location.to_string() + "/node_modules"; - let nodejs_dist_path = i.location.to_string() + "/dist"; + let node_module_path = i.location.to_owned() + "/node_modules"; + let nodejs_dist_path = i.location.to_owned() + "/dist"; lrncore::path::change_work_dir(&i.location); if lrncore::path::path_exists(&node_module_path) { - utils::fsys::rm_command(node_module_path); - utils::fsys::rm_command(nodejs_dist_path); + utils::fsys::rm_command(&node_module_path); + utils::fsys::rm_command(&nodejs_dist_path); } // Golang - let bin_folder = i.location.to_string() + "/bin/"; + let bin_folder = i.location.to_owned() + "/bin/"; if lrncore::path::path_exists(&bin_folder) { - utils::fsys::rm_command(bin_folder); + utils::fsys::rm_command(&bin_folder); } // Rust - let target_folder = i.location.to_string() + "/target"; + let target_folder = i.location.to_owned() + "/target"; if lrncore::path::path_exists(&target_folder) { - utils::fsys::rm_command(target_folder); + utils::fsys::rm_command(&target_folder); } } } diff --git a/src/doctor/helper.rs b/src/doctor/helper.rs deleted file mode 100644 index 8f7b3fa..0000000 --- a/src/doctor/helper.rs +++ /dev/null @@ -1,16 +0,0 @@ -use colored::Colorize; - -pub fn not_installed(msg: &str) { - let not_installed = "[✘]".truecolor(255, 0, 0); - println!("\t{} {}", not_installed, msg); -} - -pub fn installed(msg: &str) { - let installed = "[✔]".truecolor(0, 255, 0); - println!("\t{} {}", installed, msg); -} - -pub fn warning(msg: &str) { - let warning = "[⚠]".truecolor(255, 155, 0); - println!("\t{} {}", warning, msg); -} diff --git a/src/doctor/mod.rs b/src/doctor/mod.rs index 1a9a3fb..47c74c2 100644 --- a/src/doctor/mod.rs +++ b/src/doctor/mod.rs @@ -1,8 +1,5 @@ use std::env; use std::process::Command; -mod helper; - -use helper::{installed, not_installed, warning}; use crate::logs; use crate::nxfs; @@ -11,16 +8,16 @@ use crate::utils::log; use crate::vec_of_strings; use lrncore::usage_exit::command_usage; -pub fn doctor_help() -> String { - let usage = r" +use logs::{installed, not_installed, warning}; + +pub fn doctor_help() -> &'static str{ + (r" Usage: nyx doctor [options] Options: -h, --help Show this help message -"; - - usage.to_string() +") as _ } pub fn doctor_health() { @@ -28,10 +25,10 @@ pub fn doctor_health() { if let Some(arg) = args.iter().last() { match arg.as_str().trim() { "-h" => { - command_usage(&doctor_help()); + command_usage(doctor_help()); } "--help" => { - command_usage(&doctor_help()); + command_usage(doctor_help()); } _ => {} } @@ -81,7 +78,7 @@ fn check_gh() { fn check_tech() { let tech_vec = vec_of_strings!("Git", "cargo"); for tech in tech_vec { - match Command::new(tech.clone()) + match Command::new(&tech) .stdout(std::process::Stdio::null()) .stderr(std::process::Stdio::null()) .spawn() @@ -100,7 +97,7 @@ fn check_var() { let env_var_vec = vec_of_strings!("NYX", "RUSTUP_HOME"); for var in env_var_vec { let env_command = Command::new("printenv") - .arg(var.clone()) + .arg(&var) .stderr(std::process::Stdio::null()) .output() .expect("Failed to call the printenv command"); diff --git a/src/gh/mod.rs b/src/gh/mod.rs index b1cabda..2a51cf3 100644 --- a/src/gh/mod.rs +++ b/src/gh/mod.rs @@ -1,9 +1,9 @@ use crate::git; use std::process::Command; -pub fn create_new_repo(name: String, visibility: String) { +pub fn create_new_repo(name: &str, visibility: &str) { git::git_init(); - let repo_visibility = "--".to_string() + &visibility; + let repo_visibility = "--".to_owned() + visibility; let source = "--source=."; let mut gh_repo = Command::new("gh") .arg("repo") diff --git a/src/git/mod.rs b/src/git/mod.rs index 9d33e44..b2843b7 100644 --- a/src/git/mod.rs +++ b/src/git/mod.rs @@ -5,8 +5,8 @@ use crate::utils; use lrncore::usage_exit::command_usage; -fn git_help() -> String { - let usage = r" +fn git_help() -> &'static str { + (r" Usage: nyx git [subcommand] [arguments] [options] Subcommands: @@ -18,15 +18,13 @@ Subcommands: Options: -h, --help Show this help message -"; - - usage.to_string() +") as _ } pub fn git_command() { let args: Vec = env::args().collect(); if args.len() <= 2 { - command_usage(&git_help()); + command_usage(git_help()); } match args[2].as_str() { "stash" => nyx_git_stash(), @@ -35,16 +33,13 @@ pub fn git_command() { "all-commit" => show_all_commit(), "last-commit" => show_last_commit_with_stat(), _ => { - command_usage(&git_help()); + command_usage(git_help()); } } } fn nyx_git_stash() { - let message = utils::prompt_message( - "Enter stash message: ".to_string(), - "Failed to read stash message".to_string(), - ); + let message = utils::prompt_message("Enter stash message: ", "Failed to read stash message"); let mut stash = Command::new("git") .arg("stash") .arg("push") @@ -59,10 +54,7 @@ fn nyx_git_stash() { } fn nyx_git_tag() { - let name = utils::prompt_message( - "Enter new tag name:".to_string(), - "Failed to read tag name".to_string(), - ); + let name = utils::prompt_message("Enter new tag name:", "Failed to read tag name"); let mut new_tag = Command::new("git") .arg("tag") .arg(name) @@ -114,7 +106,7 @@ fn show_all_commit() { .arg("--no-merges") .output() .expect("Failed to call the git shortlog command"); - println!("{}", String::from_utf8_lossy(&shortlog.stdout)); + println!("{}", str::from_utf8(&shortlog.stdout).unwrap()); } fn show_last_commit_with_stat() { @@ -124,7 +116,7 @@ fn show_last_commit_with_stat() { .arg("--stat") .output() .expect("Failed to call the git log command"); - println!("{}", String::from_utf8_lossy(&commits.stdout)); + println!("{}", str::from_utf8(&commits.stdout).unwrap()); } fn show_all_branch() { @@ -132,7 +124,7 @@ fn show_all_branch() { .arg("branch") .output() .expect("Failed to call the git shortlog command"); - println!("{}", String::from_utf8_lossy(&branches.stdout)); + println!("{}", str::from_utf8(&branches.stdout).unwrap()); } fn show_stash() { @@ -141,5 +133,5 @@ fn show_stash() { .arg("list") .output() .expect("Failed to call the git shortlog command"); - println!("{}", String::from_utf8_lossy(&list.stdout)); + println!("{}", str::from_utf8(&list.stdout).unwrap()); } diff --git a/src/health/mod.rs b/src/health/mod.rs new file mode 100644 index 0000000..256bdf1 --- /dev/null +++ b/src/health/mod.rs @@ -0,0 +1,84 @@ +use std::{ + env, + process::{exit, Command}, +}; + +use lrncore::usage_exit::command_usage; + +use crate::{ + logs, + nxfs::{ + self, + config::{LogLevel, UserHealthEntryCategory}, + }, + utils::log::log_from_log_level, +}; + +pub fn health_help() -> &'static str { + (r" +Usage: nyx hello [options] + +Options: + + -h, --help Show this help message +") as _ +} + +pub fn health_command() { + let args: Vec = env::args().collect(); + if args.len() <= 2 { + user_env_health(); + exit(0); + } + match args[2].as_str() { + "-h" => { + command_usage(health_help()); + } + "--help" => { + command_usage(health_help()); + } + _ => { + command_usage(health_help()); + } + } +} + +fn user_env_health() { + log_from_log_level(LogLevel::Warn, "Caution: You are about to execute a command from your configuration file. Make sure the command is safe and does not include potentially harmful operations."); + let config = nxfs::config::parse_config_file().expect("Failed to get the config file"); + logs::nyx_log("User environment health status:"); + println!("[System]"); + for each in &config.user.health_list { + if each.category == UserHealthEntryCategory::System { + match Command::new(&each.command) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .spawn() + { + Ok(_) => { + logs::installed(&each.command); + } + Err(_) => { + logs::not_installed(&each.command); + } + } + } + } + println!("[Network]"); + for each in config.user.health_list { + if each.category == UserHealthEntryCategory::Network { + match Command::new(&each.command) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .spawn() + { + Ok(_) => { + logs::installed(&each.command); + } + Err(_) => { + logs::not_installed(&each.command); + } + } + } + } +} diff --git a/src/hello/helper.rs b/src/hello/helper.rs index 4edee58..a8a855f 100644 --- a/src/hello/helper.rs +++ b/src/hello/helper.rs @@ -1,6 +1,10 @@ use std::process::Command; pub fn folder_size(path: &str) -> String { - let du = Command::new("du").arg("-sh").arg(path).output().expect("Failed to execute du command"); - format!("{}", String::from_utf8_lossy(&du.stdout)) + let du = Command::new("du") + .arg("-sh") + .arg(path) + .output() + .expect("Failed to execute du command"); + str::from_utf8(&du.stdout).unwrap().to_string() } diff --git a/src/hello/mod.rs b/src/hello/mod.rs index 4e50a60..905bf31 100644 --- a/src/hello/mod.rs +++ b/src/hello/mod.rs @@ -9,16 +9,15 @@ use crate::{ nxfs::{self}, utils, }; -pub fn hello_help() -> String { - let usage = r" + +pub fn hello_help() -> &'static str{ + (r" Usage: nyx hello [options] Options: -h, --help Show this help message -"; - - usage.to_string() +") as _ } pub fn hello_command() { @@ -29,13 +28,13 @@ pub fn hello_command() { } match args[2].as_str() { "-h" => { - command_usage(&hello_help()); + command_usage(hello_help()); } "--help" => { - command_usage(&hello_help()); + command_usage(hello_help()); } _ => { - command_usage(&hello_help()); + command_usage(hello_help()); } } } @@ -68,14 +67,14 @@ fn hello() { let sys = System::new(); match sys.load_average() { Ok(loadavg) => println!("\tSystem load average: {}", loadavg.one), - Err(x) => println!("\tSystem load average: error: {}", x), + Err(x) => println!("\tSystem load average: error: {x}"), } match sys.mount_at("/") { Ok(mount) => { print!("\tUsage of /:\t"); println!("{} of {}", mount.avail, mount.total); } - Err(x) => println!("\tMount at /: error: {}", x), + Err(x) => println!("\tMount at /: error: {x}"), } match sys.memory() { Ok(mem) => println!( @@ -83,7 +82,7 @@ fn hello() { saturating_sub_bytes(mem.total, mem.free), mem.total ), - Err(x) => println!("\tMemory: error: {}", x), + Err(x) => println!("\tMemory: error: {x}"), } match sys.swap() { Ok(swap) => println!( @@ -91,23 +90,23 @@ fn hello() { saturating_sub_bytes(swap.total, swap.free), swap.total ), - Err(x) => println!("\tSwap: error: {}", x), + Err(x) => println!("\tSwap: error: {x}"), } match sys.cpu_temp() { - Ok(cpu_temp) => println!("\tCPU temp: {}", cpu_temp), - Err(x) => println!("\tCPU temp: {}", x), + Ok(cpu_temp) => println!("\tCPU temp: {cpu_temp}"), + Err(x) => println!("\tCPU temp: {x}"), } println!("\nNXFS information: "); - let nyx_path = utils::env::get_nyx_env_var(); - let nxfs_path = nyx_path.clone() + "/.nxfs/"; + let nyx_path: String = utils::env::get_nyx_env_var(); + let nxfs_path = nyx_path.to_owned() + "/.nxfs/"; print!("\tNxfs directory size: {}", helper::folder_size(&nxfs_path)); - let nxfs_projects_path = nyx_path.clone() + "/.nxfs/projects/"; + let nxfs_projects_path = nyx_path.to_owned() + "/.nxfs/projects/"; print!( "\tProjects directory size: {}", helper::folder_size(&nxfs_projects_path) ); - let nxfs_temp_path = nyx_path.clone() + "/.nxfs/tmp/"; + let nxfs_temp_path = nyx_path.to_owned() + "/.nxfs/tmp/"; print!( "\tTemp directory size: {}", helper::folder_size(&nxfs_temp_path) diff --git a/src/logs.rs b/src/logs.rs index bd230a9..18d84bd 100644 --- a/src/logs.rs +++ b/src/logs.rs @@ -1,31 +1,46 @@ use colored::Colorize; -pub fn info_log(msg: String) { +pub fn info_log(msg: &str) { let info = "[INFO]".truecolor(0, 255, 0); - println!("{} {}", info, msg); + println!("{info} {msg}"); } -pub fn error_log(msg: String) { +pub fn error_log(msg: &str) { let info = "[ERROR]".truecolor(255, 0, 0); - println!("{} {}", info, msg); + println!("{info} {msg}"); } -pub fn error_log_with_code(msg: String, error: String) { +pub fn error_log_with_code(msg: &str, error: &str) { let info = "[ERROR]".truecolor(255, 0, 0); - println!("{} {} {}", info, msg, error); + println!("{info} {msg} {error}"); } pub fn active_log(msg: &str) { let active = "active".truecolor(0, 255, 0); - println!("{} {}", msg, active); + println!("{msg} {active}"); } pub fn inactive_log(msg: &str) { let inactive = "inactive".truecolor(255, 0, 0); - println!("{} {}", msg, inactive); + println!("{msg} {inactive}"); } pub fn nyx_log(msg: &str) { let log = "[NYX]".truecolor(138, 43, 226); - println!("{} {}", log, msg); + println!("{log} {msg}"); +} + +pub fn not_installed(msg: &str) { + let not_installed = "[✘]".truecolor(255, 0, 0); + println!("\t{not_installed} {msg}"); +} + +pub fn installed(msg: &str) { + let installed = "[✔]".truecolor(0, 255, 0); + println!("\t{installed} {msg}"); +} + +pub fn warning(msg: &str) { + let warning = "[⚠]".truecolor(255, 155, 0); + println!("\t{warning} {msg}"); } diff --git a/src/main.rs b/src/main.rs index d42143d..be6b4ac 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,24 @@ mod cleanup; +mod doctor; pub mod gh; mod git; -mod doctor; pub mod logs; pub mod macros; mod projects; mod update; +mod upgrade; mod utils; use crate::projects::todo; use lrncore::usage_exit::command_usage; pub mod nxfs; use std::env; +mod health; mod hello; // Current version of NYX // if modified and then running update command it will replace // your current nyx installation with the newer version -const VERSION: &str = "2.8.0"; -#[derive(Debug, Clone)] +const VERSION: &str = "2.10.2"; enum Commands { Init, CatNxs, @@ -26,9 +27,11 @@ enum Commands { Cleanup, Git, Doctor, + Health, Hello, Update, Config, + Upgrade, Help, Version, } @@ -47,8 +50,10 @@ Commands: cleanup Cleanup all unused files git Git command wrapped in a simplified interface doctor Display current NYX system health + health Display current user configure environment health + update Execute all specified user configuration commands to update multiple tools at once hello Display helpful information about today - update Update the current version of NYX + upgrade Update the current version of NYX config Manage nyx configuration help Show this help message @@ -84,9 +89,11 @@ fn main() { Some("cleanup") => Commands::Cleanup, Some("git") => Commands::Git, Some("doctor") => Commands::Doctor, + Some("health") => Commands::Health, Some("hello") => Commands::Hello, - Some("config") => Commands::Config, Some("update") => Commands::Update, + Some("config") => Commands::Config, + Some("upgrade") => Commands::Upgrade, Some("help") => Commands::Help, Some("version") => Commands::Version, _ => { @@ -98,20 +105,21 @@ fn main() { match command { Commands::Init => nxfs::nxs::create_data(), Commands::CatNxs => nxfs::nxs::cat_nxs(), - Commands::CatNxp { hash } => nxfs::nxp::cat_nxp(hash), + Commands::CatNxp { hash } => nxfs::nxp::cat_nxp(hash.as_deref()), Commands::Project => projects::project_command(), Commands::Cleanup => cleanup::choose_cleanup(), Commands::Git => git::git_command(), Commands::Doctor => doctor::doctor_health(), + Commands::Health => health::health_command(), Commands::Hello => hello::hello_command(), Commands::Config => nxfs::config::config_command(), - Commands::Update => update::update_bin(), + Commands::Update => update::update_command(), + Commands::Upgrade => upgrade::upgrade_bin(), Commands::Help => command_usage(nyx_usage()), Commands::Version => command_usage(&nyx_version()), } } pub fn nyx_version() -> String { - let usage = format!("nyx {VERSION}"); - usage + format!("nyx {VERSION}") } diff --git a/src/nxfs/config.rs b/src/nxfs/config.rs index f1b4848..49c090f 100644 --- a/src/nxfs/config.rs +++ b/src/nxfs/config.rs @@ -11,8 +11,8 @@ use std::fmt::Debug; use std::{env, fs}; use toml::de::Error as toml_error; -fn config_help() -> String { - let usage = r" +fn config_help() -> &'static str { + (r" Usage: nyx config [subcommand] [arguments] [options] Subcommands: @@ -24,10 +24,10 @@ Subcommands: Options: -h, --help Show this help message - "; - usage.to_string() + ") as _ } -#[derive(Debug, Deserialize, Serialize)] + +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct Config { pub config: ConfigHeader, pub user: ConfigUser, @@ -38,31 +38,53 @@ pub struct Config { pub security: ConfigSecure, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct ConfigHeader { pub format: String, pub version: String, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct ConfigUser { pub name: String, + pub health_list: Vec, + pub update_list: Vec, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct UserUpdateEntry { + pub command: String, + pub sub_command: String, +} + +#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)] +pub enum UserHealthEntryCategory { + System, + Network, +} + +#[derive(Debug, Deserialize, Serialize, Clone)] +pub struct UserHealthEntry { + pub category: UserHealthEntryCategory, + pub command: String, + pub sub_command: String, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct ConfigGit { pub profile_url: String, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct ConfigBehavior { pub default_editor: String, pub auto_update: bool, pub ask_confirmation: bool, pub log_level: LogLevel, + pub save_logs: bool, } -#[derive(Debug, Deserialize, Serialize, PartialEq, PartialOrd)] +#[derive(Debug, Deserialize, Serialize, PartialEq, PartialOrd, Clone)] pub enum LogLevel { Error, Warn, @@ -71,28 +93,30 @@ pub enum LogLevel { Trace, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct ConfigUi {} -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct ConfigInternPath { pub data: String, pub logs: String, pub cache: String, } -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, Deserialize, Serialize, Clone)] pub struct ConfigSecure { pub secure_mode: bool, } -fn config_template() -> String { - let template = r"[config] +fn config_template() -> &'static str { + (r"[config] format = 'nxs_config' -version = '0.1.0' +version = '0.4.0' [user] name = '' +health_list = [] +update_list = [] [git] profile_url = '' @@ -102,6 +126,7 @@ default_editor = 'vim' auto_update = false ask_confirmation = true log_level = 'Info' +save_logs = false [ui] @@ -112,15 +137,14 @@ cache = '' [security] secure_mode = false - "; - template.to_string() + ") as _ } pub fn config_command() { change_work_dir(&utils::env::get_nyx_env_var()); let args: Vec = env::args().collect(); if args.len() <= 2 { - command_usage(&config_help()); + command_usage(config_help()); } match args[2].as_str() { "init" => init_config(), @@ -128,45 +152,40 @@ pub fn config_command() { "cat" => cat_config(), _ => { - command_usage(&config_help()); + command_usage(config_help()); } } } fn init_config() { - let config_path = ".nxfs/config.toml".to_string(); + let config_path = ".nxfs/config.toml"; let mut config_file = match File::create_new(config_path) { Ok(f) => f, Err(e) => { log_from_log_level( LogLevel::Error, - &format!("Failed to initialize config file: {}", e), + &format!("Failed to initialize config file: {e}"), ); return; } }; let template = config_template(); - let mut config: Config = match toml::from_str(&template) { + let mut config: Config = match toml::from_str(template) { Ok(c) => c, Err(e) => { log_from_log_level( LogLevel::Error, - &format!("Failed to deserialize config template: {}", e), + &format!("Failed to deserialize config template: {e}"), ); return; } }; - let ask_username = utils::prompt_message( - "Enter a username:".to_string(), - "Failed to get user input".to_string(), - ); - let ask_github_profile = utils::prompt_message( - "Enter your github profile url:".to_string(), - "Failed to get user input".to_string(), - ); + let ask_username = utils::prompt_message("Enter a username:", "Failed to get user input"); + let ask_github_profile = + utils::prompt_message("Enter your github profile url:", "Failed to get user input"); let data_dir = format!("{}/.nxfs/", utils::env::get_nyx_env_var()); - let log_dir = data_dir.clone() + "logs/"; - let cache_dir = data_dir.clone() + "cache/"; + let log_dir = data_dir.to_owned() + "logs/"; + let cache_dir = data_dir.to_owned() + "cache/"; config.user.name = ask_username; config.git.profile_url = ask_github_profile; config.internal_path.data = data_dir; @@ -180,7 +199,7 @@ fn init_config() { Err(e) => { log_from_log_level( LogLevel::Error, - &format!("Failed to write the config file: {}", e), + &format!("Failed to write the config file: {e}"), ); exit(50); } @@ -190,16 +209,13 @@ fn init_config() { pub fn parse_config_file() -> Result { change_work_dir(&utils::env::get_nyx_env_var()); - let config_path = ".nxfs/config.toml".to_string(); + let config_path = ".nxfs/config.toml"; let file = - std::fs::read_to_string(&config_path).expect("Failed to read the config file to string"); + std::fs::read_to_string(config_path).expect("Failed to read the config file to string"); let config: Config = match toml::from_str(&file) { Ok(c) => c, Err(e) => { - log_from_log_level( - LogLevel::Error, - &format!("Failed to parse the config file: {}", e), - ); + println!("Failed to parse the configuration file: {e:?}"); return Err(e); } }; @@ -235,5 +251,5 @@ fn cat_config() { .stdout(Stdio::inherit()) .output() .expect("Failed to execute cat command"); - println!("{}", String::from_utf8_lossy(&cat.stdout)); + println!("{}", str::from_utf8(&cat.stdout).unwrap()); } diff --git a/src/nxfs/mod.rs b/src/nxfs/mod.rs index da67cb2..2ff1160 100644 --- a/src/nxfs/mod.rs +++ b/src/nxfs/mod.rs @@ -1,3 +1,3 @@ +pub mod config; pub mod nxp; pub mod nxs; -pub mod config; diff --git a/src/nxfs/nxp.rs b/src/nxfs/nxp.rs index b6bd6a7..0b4926b 100644 --- a/src/nxfs/nxp.rs +++ b/src/nxfs/nxp.rs @@ -67,16 +67,16 @@ pub fn create_new_nxp(content: NXPContent) { let mut new_hash = Sha1::new(); new_hash.update(&content.name); let hash_result = new_hash.finalize(); - let folder_hash = format!("{:#x}", hash_result); + let folder_hash = format!("{hash_result:#x}"); let (file_hash, _) = folder_hash.split_at(11); // content let content: NXPContent = NXPContent { - name: content.name.to_string(), - tech: content.tech.to_string(), - location: content.location.to_string(), - repository: content.repository.to_string(), - github_project: content.github_project.to_string(), - version: content.version.to_string(), + name: content.name, + tech: content.tech, + location: content.location, + repository: content.repository, + github_project: content.github_project, + version: content.version, }; let content_buff = bincode::serialize(&content).expect("Failed to serialize content buffer"); // header @@ -97,15 +97,15 @@ pub fn create_new_nxp(content: NXPContent) { let mut file_buff: Vec = Vec::new(); file_buff.extend_from_slice(&header_buff); file_buff.extend_from_slice(&content_buff); - let file_path = format!(".nxfs/projects/{}/content", file_hash); - let folder_path = format!(".nxfs/projects/{}", file_hash); + let file_path = format!(".nxfs/projects/{file_hash}/content"); + let folder_path = format!(".nxfs/projects/{file_hash}"); utils::fsys::create_dir(&folder_path); let mut nxs_file: File = match File::create(file_path) { Ok(f) => f, Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to create nxp file: {}", e), + &format!("Failed to create nxp file: {e}"), ); return; } @@ -115,7 +115,7 @@ pub fn create_new_nxp(content: NXPContent) { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to write buffer in nxp file: {}", e), + &format!("Failed to write buffer in nxp file: {e}"), ); } }; @@ -156,26 +156,26 @@ pub fn parse_nxp_file(path: &str, nxp_ref: &mut NXP) { let file = match File::open(path) { Ok(f) => f, Err(e) => { - log::log_from_log_level(LogLevel::Error, &format!("Failed to open nxp file: {}", e)); + log::log_from_log_level(LogLevel::Error, &format!("Failed to open nxp file: {e}")); return; } }; - // initialize NXPHeader size from structure and buffer + // Initialize NXPHeader size from structure and buffer let header_size = std::mem::size_of::(); let buffer = BufReader::new(file); - // vector containing the whole NXP file + // Vector containing the whole NXP file let mut bytes_vec: Vec = Vec::new(); for byte_or_error in buffer.bytes() { match byte_or_error { Ok(byte) => bytes_vec.push(byte), Err(e) => { - log::log_from_log_level(LogLevel::Error, &format!("Failed to read bytes: {}", e)); + log::log_from_log_level(LogLevel::Error, &format!("Failed to read bytes: {e}")); return; } } } - // extract a slice of bytes from the `bytes_vec` vector to represent the NXPHeader section of the NXS file. + // Extract a slice of bytes from the `bytes_vec` vector to represent the NXPHeader section of the NXS file. // &bytes_vec[0 to NXPHeader_size] let header_bytes = &bytes_vec[..header_size]; // convert into the NXPHeader struct @@ -193,7 +193,7 @@ pub fn parse_nxp_file(path: &str, nxp_ref: &mut NXP) { nxp_ref.content = nxp.content; } -pub fn cat_nxp(hash: Option) { +pub fn cat_nxp(hash: Option<&str>) { lrncore::path::change_work_dir(&utils::env::get_nyx_env_var()); let mut nxp: NXP = NXP { header: NXPHeader { @@ -216,7 +216,7 @@ pub fn cat_nxp(hash: Option) { &format!(".nxfs/projects/{}/content", hash.unwrap()), &mut nxp, ); - println!("id: {:?}\n name: {:?}\n tech: {:?}\n location: {:?}\n repository: {:?}\n github project: {:?}\n version: {:?}", String::from_utf8_lossy(&nxp.header.project_id), nxp.content.name, nxp.content.tech, nxp.content.location, nxp.content.repository, nxp.content.github_project, nxp.content.version); + println!("id: {:?}\n name: {:?}\n tech: {:?}\n location: {:?}\n repository: {:?}\n github project: {:?}\n version: {:?}", str::from_utf8(&nxp.header.project_id).unwrap(), nxp.content.name, nxp.content.tech, nxp.content.location, nxp.content.repository, nxp.content.github_project, nxp.content.version); } pub fn update_nxp(hash: &str, update_nxp: Vec) { @@ -238,7 +238,7 @@ pub fn update_nxp(hash: &str, update_nxp: Vec) { version: String::new(), }, }; - let file_path = format!(".nxfs/projects/{}/content", hash); + let file_path = format!(".nxfs/projects/{hash}/content"); parse_nxp_file(&file_path, &mut nxp); let header_buff = bincode::serialize(&nxp.header).expect("Failed to serialize header buffer"); let mut file_buff: Vec = Vec::new(); @@ -249,7 +249,7 @@ pub fn update_nxp(hash: &str, update_nxp: Vec) { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to create nxp file: {}", e), + &format!("Failed to create nxp file: {e}"), ); return; } @@ -259,7 +259,7 @@ pub fn update_nxp(hash: &str, update_nxp: Vec) { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to write buffer in nxp file: {}", e), + &format!("Failed to write buffer in nxp file: {e}"), ); } }; @@ -268,12 +268,12 @@ pub fn update_nxp(hash: &str, update_nxp: Vec) { pub fn delete_nxp(hash: &str) { lrncore::path::change_work_dir(&utils::env::get_nyx_env_var()); - match fs::remove_dir_all(format!(".nxfs/projects/{}/", hash)) { + match fs::remove_dir_all(format!(".nxfs/projects/{hash}/")) { Ok(_) => { log::log_from_log_level(LogLevel::Info, "Successfully remove project file"); } Err(e) => { - log::log_from_log_level(LogLevel::Error, &format!("Failed to delete file: {}", e)); + log::log_from_log_level(LogLevel::Error, &format!("Failed to delete file: {e}")); } } } diff --git a/src/nxfs/nxs.rs b/src/nxfs/nxs.rs index 9bd0ba4..021fa62 100644 --- a/src/nxfs/nxs.rs +++ b/src/nxfs/nxs.rs @@ -33,33 +33,35 @@ NXS file structure /// Properties: /// /// * `NXSHeader`: The `NXSHeader` property in the `NXS` struct is of type `NXSHeader`. It likely contains -/// information about the overall structure or metadata of the NXS data. +/// information about the overall structure or metadata of the NXS data. /// * `projects`: The `projects` property in the `NXS` struct is of type `ProjectList`. It likely -/// represents a list of projects within the NXS structure. +/// represents a list of projects within the NXS structure. #[derive(Debug, Deserialize, Clone, Serialize)] pub struct NXS { pub header: NXSHeader, pub projects: ProjectList, } -/// The `NXSHeader` struct in Rust represents a data structure with fields for magic number, format -/// version, project count, and a reserved value. -/// -/// Properties: -/// -/// * `magic_number`: The `magic_number` field in the `NXSHeader` struct is an array of 4 unsigned 8-bit -/// integers (`u8`). It is typically used to identify the file format or type by storing a specific -/// sequence of bytes that can be checked when reading the file to ensure it is of the expected -/// * `format_version`: The `format_version` property in the `NXSHeader` struct is an array of 6 unsigned -/// 8-bit integers (`[u8; 6]`). This array is used to store the version information of the format being -/// used. Each element in the array represents a part of the version number. -/// * `project_count`: The `project_count` property in the `NXSHeader` struct represents the number of -/// projects stored in the data structure. It is of type `u8`, which means it can hold values from 0 to -/// 255. -/// * `reserved`: The `reserved` field in the `NXSHeader` struct is a 32-bit unsigned integer that is -/// currently marked with `#[allow(dead_code)]`. This attribute is used to suppress the compiler warning -/// about unused code, indicating that the field is intentionally left unused or reserved for future -/// use. +/** +The `NXSHeader` struct in Rust represents a data structure with fields for magic number, format +version, project count, and a reserved value. + +Properties: + +* `magic_number`: The `magic_number` field in the `NXSHeader` struct is an array of 4 unsigned 8-bit + integers (`u8`). It is typically used to identify the file format or type by storing a specific + sequence of bytes that can be checked when reading the file to ensure it is of the expected +* `format_version`: The `format_version` property in the `NXSHeader` struct is an array of 6 unsigned + 8-bit integers (`[u8; 6]`). This array is used to store the version information of the format being + used. Each element in the array represents a part of the version number. +* `project_count`: The `project_count` property in the `NXSHeader` struct represents the number of + projects stored in the data structure. It is of type `u8`, which means it can hold values from 0 to +255. +* `reserved`: The `reserved` field in the `NXSHeader` struct is a 32-bit unsigned integer that is + currently marked with `#[allow(dead_code)]`. This attribute is used to suppress the compiler warning + about unused code, indicating that the field is intentionally left unused or reserved for future + use. +*/ #[derive(Debug, Deserialize, Clone, Serialize)] #[repr(C, packed)] pub struct NXSHeader { @@ -75,7 +77,7 @@ pub struct NXSHeader { /// Properties: /// /// * `entries`: The `entries` property in the `ProjectList` struct is a vector of `ProjectEntry` -/// instances. It represents a list of project entries within the project list. +/// instances. It represents a list of project entries within the project list. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProjectList { pub entries: Vec, @@ -86,13 +88,13 @@ pub struct ProjectList { /// Properties: /// /// * `project_hash`: The `project_hash` property in the `ProjectEntry` struct is defined as an array of -/// 20 unsigned 8-bit integers (bytes). This array represents a hash value typically used to uniquely -/// identify a project. +/// 20 unsigned 8-bit integers (bytes). This array represents a hash value typically used to uniquely +/// identify a project. /// * `project_name`: The `project_name` property in the `ProjectEntry` struct is a vector of unsigned 8-bit -/// integers (`Vec`). It is used to store the unique identifier for a project. +/// integers (`Vec`). It is used to store the unique identifier for a project. /// * `project_size`: The `project_size` property in the `ProjectEntry` struct represents the size of -/// the project in bytes. It is of type `u32`, which means it can hold unsigned integer values ranging -/// from 0 to 2^32 - 1. This property indicates the amount of storage space the +/// the project in bytes. It is of type `u32`, which means it can hold unsigned integer values ranging +/// from 0 to 2^32 - 1. This property indicates the amount of storage space the #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ProjectEntry { pub project_name: String, @@ -101,7 +103,7 @@ pub struct ProjectEntry { } /// The `create_data` function initializes a data folder, removes any existing data directory, -/// creates a new data directory, and parses a NXS file. +/// creates a new data directory, and parses an NXS file. pub fn create_data() { lrncore::path::change_work_dir(&utils::env::get_nyx_env_var()); if Path::new(".nxfs").exists() { @@ -117,7 +119,7 @@ pub fn create_data() { if let Err(e) = remove_dir { log_from_log_level( LogLevel::Error, - &format!("Failed to remove existing .nxfs directory: {}", e), + &format!("Failed to remove existing .nxfs directory: {e}"), ); } } @@ -175,7 +177,7 @@ fn create_nxs_file() { Err(e) => { log_from_log_level( LogLevel::Error, - &format!("Failed to create nxs file: {}", e), + &format!("Failed to create nxs file: {e}"), ); return; } @@ -185,7 +187,7 @@ fn create_nxs_file() { Err(e) => { log_from_log_level( LogLevel::Error, - &format!("Failed to write buffer in nxs file: {}", e), + &format!("Failed to write buffer in nxs file: {e}"), ); } }; @@ -196,25 +198,25 @@ fn create_nxs_file() { // refactor to return a structure instead of a ref fn parse_nxs_file(nxs_ref: &mut NXS) { lrncore::path::change_work_dir(&utils::env::get_nyx_env_var()); - // open NXS file and match result + // Open NXS file and match result let file = match File::open(".nxfs/nxs") { Ok(f) => f, Err(e) => { - log_from_log_level(LogLevel::Error, &format!("Failed to open nxs file: {}", e)); + log_from_log_level(LogLevel::Error, &format!("Failed to open nxs file: {e}")); return; } }; - // initialize NXSHeader size from structure and buffer + // Initialize NXSHeader size from structure and buffer let header_size = std::mem::size_of::(); let buffer = BufReader::new(file); - // vector containing the whole NXS file + // Vector containing the whole NXS file let mut bytes_vec: Vec = Vec::new(); for byte_or_error in buffer.bytes() { let byte = byte_or_error.unwrap(); bytes_vec.push(byte); } - // extract a slice of bytes from the `bytes_vec` vector to represent the NXSHeader section of the NXS file. + // Extract a slice of bytes from the `bytes_vec` vector to represent the NXSHeader section of the NXS file. // &bytes_vec[0 to NXSHeader_size] let header_bytes = &bytes_vec[..header_size]; @@ -226,7 +228,7 @@ fn parse_nxs_file(nxs_ref: &mut NXS) { let project_list: ProjectList = bincode::deserialize(project_list_byte).expect("Failed to deserialize project list"); let nxs: NXS = NXS { - header: header, + header, projects: project_list, }; nxs_ref.header = nxs.header; @@ -262,7 +264,7 @@ pub fn update_nxs_file(nxp_ref: &mut NXP) { { Ok(f) => f, Err(e) => { - log_from_log_level(LogLevel::Error, &format!("Failed to open nxs file: {}", e)); + log_from_log_level(LogLevel::Error, &format!("Failed to open nxs file: {e}")); return; } }; @@ -271,7 +273,7 @@ pub fn update_nxs_file(nxp_ref: &mut NXP) { Err(e) => { log_from_log_level( LogLevel::Error, - &format!("Failed to write buffer in nxs file: {}", e), + &format!("Failed to write buffer in nxs file: {e}"), ); } }; @@ -291,7 +293,7 @@ pub fn update_project_entries(nxs_ref: &mut NXS, vec: Vec) { { Ok(f) => f, Err(e) => { - log_from_log_level(LogLevel::Error, &format!("Failed to open nxs file: {}", e)); + log_from_log_level(LogLevel::Error, &format!("Failed to open nxs file: {e}")); return; } }; @@ -300,16 +302,16 @@ pub fn update_project_entries(nxs_ref: &mut NXS, vec: Vec) { Err(e) => { log_from_log_level( LogLevel::Error, - &format!("Failed to write buffer in nxs file: {}", e), + &format!("Failed to write buffer in nxs file: {e}"), ); } }; log_from_log_level(LogLevel::Info, "NXS file updated"); } -fn new_project_entry(hash: &[u8; 11], id: &String, size: u32) -> ProjectEntry { +fn new_project_entry(hash: &[u8; 11], id: &str, size: u32) -> ProjectEntry { let new: ProjectEntry = ProjectEntry { - project_name: id.clone(), + project_name: id.to_owned(), project_hash: *hash, project_size: size, }; @@ -339,7 +341,7 @@ NXS: println!( "name: {:?}\n hash: {:?}\n size: {:?}\n", each.project_name, - String::from_utf8_lossy(&each.project_hash), + str::from_utf8(&each.project_hash).unwrap(), each.project_size ); } @@ -379,7 +381,7 @@ pub fn get_all_project_entries() -> Vec { parse_nxp_file( &format!( ".nxfs/projects/{}/content", - String::from_utf8_lossy(&each.project_hash) + str::from_utf8(&each.project_hash).unwrap() ), &mut nxp, ); @@ -422,7 +424,7 @@ pub fn get_all_short_project() -> Vec { parse_nxp_file( &format!( ".nxfs/projects/{}/content", - String::from_utf8_lossy(&each.project_hash) + str::from_utf8(&each.project_hash).unwrap() ), &mut nxp, ); diff --git a/src/projects/copy/mod.rs b/src/projects/copy/mod.rs index a556284..ae2dbfe 100644 --- a/src/projects/copy/mod.rs +++ b/src/projects/copy/mod.rs @@ -14,8 +14,8 @@ use crate::{ utils::{self, env::get_nyx_env_var, log::log_from_log_level}, }; -pub fn copy_help() -> String { - let usage = r" +pub fn copy_help() -> &'static str { + (r" Usage: copy [subcommand] [arguments] [options] Subcommands: @@ -24,46 +24,52 @@ Subcommands: Options: -h, --help Show this help message - "; - - usage.to_string() + ") as _ } pub fn copy_command() { change_work_dir(&get_nyx_env_var()); let args: Vec = env::args().collect(); if args.len() <= 3 { - command_usage(©_help()); + command_usage(copy_help()); return; } if args.len() > 1 && (args[3] == "-h" || args[3] == "--help") { - command_usage(©_help()); + let usage = ©_help(); + command_usage(usage); return; } if let Some(arg) = args.get(3) { let get_project = get_project_content(); match arg.as_str().trim() { - "path" => copy_field(get_project.location), - "repo" => copy_field(get_project.repository), + "path" => copy_field(&get_project.location), + "repo" => copy_field(&get_project.repository), _ => { log_from_log_level(LogLevel::Error, "Unknown copy command"); - command_usage(©_help()); + command_usage(copy_help()); } } } } -fn copy_field(param: String) { - let pbcopy = Command::new("pbcopy") +fn copy_field(param: &str) { + let mut pbcopy = Command::new("pbcopy") .stdin(Stdio::piped()) .spawn() .expect("Failed to spawn pbcopy command"); - Command::new("echo") - .arg(param) - .stdout(pbcopy.stdin.unwrap()) - .output() - .expect("Failed to execute echo command"); + if let Some(mut stdin) = pbcopy.stdin.take() { + use std::io::Write; + stdin + .write_all(param.as_bytes()) + .expect("Failed to write to pbcopy stdin"); + } else { + log_from_log_level(LogLevel::Error, "Failed to open pbcopy stdin"); + } + let wait_pbcopy = pbcopy.wait().expect("Failed to wait pbcopy command"); + if !wait_pbcopy.success() { + log_from_log_level(LogLevel::Error, "Failed to execute pbcopy command"); + } log_from_log_level(LogLevel::Info, "Project field copied in clipboard"); } @@ -71,8 +77,8 @@ fn get_project_content() -> NXPContent { let mut projects = nxs::get_all_project(); inquire::set_global_render_config(utils::get_render_config()); let app_name = utils::prompt_message( - "Enter project name:".to_string(), - "Error with the project name referred".to_string(), + "Enter project name:", + "Error with the project name referred", ); let project_hash: [u8; 11]; if let Some(pos) = projects.iter().position(|app| app.project_name == app_name) { @@ -100,7 +106,7 @@ fn get_project_content() -> NXPContent { version: String::new(), }, }; - let hash = String::from_utf8_lossy(&project_hash); + let hash = str::from_utf8(&project_hash).unwrap(); nxp::parse_nxp_file(&format!(".nxfs/projects/{}/content", &hash), &mut nxp); let project_content: NXPContent = nxp.content; project_content diff --git a/src/projects/delete/mod.rs b/src/projects/delete/mod.rs index df4b325..b36dda3 100644 --- a/src/projects/delete/mod.rs +++ b/src/projects/delete/mod.rs @@ -11,16 +11,14 @@ use std::{env, process::Command}; use crate::utils::{self, log}; -pub fn project_delete_help() -> String { - let usage = r" +pub fn project_delete_help() -> &'static str { + (r" Usage: nyx project-delete [options] Options: -h, --help Show this help message -"; - - usage.to_string() +") as _ } pub fn select_remove_project() { @@ -28,10 +26,10 @@ pub fn select_remove_project() { if let Some(arg) = args.iter().last() { match arg.as_str().trim() { "-h" => { - command_usage(&project_delete_help()); + command_usage(project_delete_help()); } "--help" => { - command_usage(&project_delete_help()); + command_usage(project_delete_help()); } _ => {} } @@ -74,11 +72,12 @@ fn remove_project_from_list() { return; } // if an index match the given data, remove it from the vector - let mut hash: String = String::new(); - if let Some(pos) = projects.iter().position(|x| x.project_name == app_name) { - let app = projects.remove(pos); - hash = String::from_utf8_lossy(&app.project_hash).to_string(); - } + let hash: String = if let Some(pos) = projects.iter().position(|x| x.project_name == app_name) { + let app: nxs::ProjectEntry = projects.remove(pos); + String::from_utf8_lossy(&app.project_hash).into_owned() + } else { + String::new() + }; let mut nxs: NXS = NXS { header: NXSHeader { magic_number: [0u8; 4], @@ -106,11 +105,13 @@ fn remove_project_from_storage() { if !confirm { return; } - let mut hash: String = String::new(); - if let Some(pos) = projects.iter().position(|app| app.project_name == app_name) { - let app = projects.remove(pos); - hash = String::from_utf8_lossy(&app.project_hash).to_string(); - } + // if an index match the given data, remove it from the vector + let hash: String = if let Some(pos) = projects.iter().position(|x| x.project_name == app_name) { + let app: nxs::ProjectEntry = projects.remove(pos); + String::from_utf8_lossy(&app.project_hash).into_owned() + } else { + String::new() + }; let mut nxp: NXP = NXP { header: NXPHeader { magic_number: [0; 4], diff --git a/src/projects/list/mod.rs b/src/projects/list/mod.rs index aade379..8239e45 100644 --- a/src/projects/list/mod.rs +++ b/src/projects/list/mod.rs @@ -3,9 +3,8 @@ use crate::nxfs; use crate::nxfs::config::LogLevel; use crate::nxfs::nxs; use crate::utils; +use crate::utils::get_select_project_option; use crate::utils::log; -use crate::vec_of_strings; -use inquire::{error::InquireError, Select}; use lrncore::usage_exit::command_usage; use std::env; use std::process::exit; @@ -14,17 +13,15 @@ use tabled::Table; use super::nxp::{self, NXPContent}; -pub fn project_list_help() -> String { - let usage = r" +pub fn project_list_help() -> &'static str { + (r" Usage: nyx project-list [options] Options: -s, --short List all project without Github and version data -h, --help Show this help message -"; - - usage.to_string() +") as _ } pub fn list_projects() { @@ -42,24 +39,22 @@ pub fn list_projects() { builder = Table::builder(&projects_short).index().name(None); } "-h" => { - command_usage(&project_list_help()); + command_usage(project_list_help()); } "--help" => { - command_usage(&project_list_help()); + command_usage(project_list_help()); } _ => {} } } let mut table = builder.build(); table.with(Style::modern()); - println!("{}", table); + println!("{table}"); } pub fn add_existing_project_to_list() { inquire::set_global_render_config(utils::get_render_config()); - let options = utils::get_tech_option(); - let ans: std::result::Result = - Select::new("Which tech your project is using ?", options).prompt(); + let ans = get_select_project_option("Which tech your project is using ?"); match ans { Ok(choice) => create_repo_or_not(&choice), Err(_) => println!("There was an error, please try again"), @@ -68,9 +63,9 @@ pub fn add_existing_project_to_list() { pub fn create_repo_or_not(tech: &str) { inquire::set_global_render_config(utils::get_render_config()); - let choice: Vec = vec_of_strings!["Yes".to_string(), "No".to_string()]; + let choice: Vec<&str> = vec!["Yes", "No"]; let options = utils::get_select_option( - "Do you want to create a new repository ?".to_string(), + "Do you want to create a new repository ?", choice, ) .unwrap(); @@ -88,38 +83,38 @@ pub fn add_project_to_list(tech: &str) { let app_name = current_dir.split("/").last().unwrap().to_lowercase(); let mut repository_user_input: String; repository_user_input = utils::prompt_message( - "Enter the url of the github's repository of the project: ".to_string(), - "Failed to get the user input".to_string(), + "Enter the url of the github's repository of the project: ", + "Failed to get the user input", ); if repository_user_input.is_empty() { - repository_user_input = "No repository specified".to_string() + repository_user_input = "No repository specified".to_owned() } let mut github_project: String; github_project = utils::prompt_message( - "Enter the url of the github project: ".to_string(), - "Error getting the user input".to_string(), + "Enter the url of the github project: ", + "Error getting the user input", ); if github_project.is_empty() { - github_project = "No github project specified".to_string() + github_project = "No github project specified".to_owned() } let mut version: String; version = utils::prompt_message( - "Enter the version of the project: ".to_string(), - "Error getting the user input".to_string(), + "Enter the version of the project: ", + "Error getting the user input", ); if version.is_empty() { - version = "0.1.0".to_string(); + version = "0.1.0".to_owned(); } let new_app: nxp::NXPContent = nxp::NXPContent { - name: (app_name.to_string()), - tech: (tech.to_string()), + name: (app_name.to_owned()), + tech: (tech.to_owned()), location: (current_dir), repository: repository_user_input, github_project, @@ -131,41 +126,44 @@ pub fn add_project_to_list(tech: &str) { fn create_repo_add_to_list(tech: &str) { let current_dir = lrncore::path::get_current_path(); let app_name = current_dir.split("/").last().unwrap(); - let choice = vec_of_strings!["public", "private", "internal"]; + let choice = vec!["public", "private", "internal"]; let repository_visibility: String = - utils::get_select_option("Select the repository visibility:".to_string(), choice).unwrap(); - gh::create_new_repo(app_name.to_string(), repository_visibility); + utils::get_select_option("Select the repository visibility:", choice).unwrap(); + gh::create_new_repo(app_name, &repository_visibility); let mut github_project: String; let config = nxfs::config::parse_config_file().expect("Failed to parse the nyx config file"); let user_github_url = config.git.profile_url; if user_github_url.is_empty() { - log::log_from_log_level(LogLevel::Error, "No github url was specified. Please enter one in config file."); + log::log_from_log_level( + LogLevel::Error, + "No github url was specified. Please enter one in config file.", + ); exit(4); } let repository: String = user_github_url + app_name; github_project = utils::prompt_message( - "Enter the url of the github project: ".to_string(), - "Error getting the user input".to_string(), + "Enter the url of the github project: ", + "Error getting the user input", ); if github_project.is_empty() { - github_project = "No github project specified".to_string() + github_project = "No github project specified".to_owned() } let mut version: String; version = utils::prompt_message( - "Enter the version of the project: ".to_string(), - "Error getting the user input".to_string(), + "Enter the version of the project: ", + "Error getting the user input", ); if version.is_empty() { - version = "0.1.0".to_string(); + version = "0.1.0".to_owned(); } let new_app: NXPContent = NXPContent { - name: (app_name.to_string()), - tech: (tech.to_string()), + name: (app_name.to_owned()), + tech: (tech.to_owned()), location: (current_dir), repository, github_project, diff --git a/src/projects/mod.rs b/src/projects/mod.rs index 8ba5a63..a1b47c0 100644 --- a/src/projects/mod.rs +++ b/src/projects/mod.rs @@ -17,13 +17,13 @@ pub mod delete; use crate::nxfs; use lrncore::usage_exit::command_usage; use nxfs::{nxp, nxs}; +mod copy; pub mod open; pub mod todo; -mod copy; use open::open_editor; -pub fn project_help() -> String { - let usage = r" +pub fn project_help() -> &'static str{ + (r" Usage: nyx project [subcommand] [arguments] [options] Subcommands: @@ -38,9 +38,7 @@ Subcommands: Options: -h, --help Show this help message - "; - - usage.to_string() + ") as _ } #[derive(Deserialize, Serialize, Debug, Tabled, Clone, PartialEq)] @@ -56,6 +54,7 @@ pub struct Project { } #[derive(Tabled)] +#[allow(dead_code)] pub struct ProjectShort { pub id: String, pub name: String, @@ -71,7 +70,7 @@ pub struct Data { pub fn project_command() { let args: Vec = env::args().collect(); if args.len() <= 2 { - command_usage(&project_help()); + command_usage(project_help()); } match args[2].as_str() { "new" => { @@ -80,12 +79,12 @@ pub fn project_command() { exit(4); } let project_name = &args[3]; - new_project(project_name.to_string()); + new_project(project_name); } "open" => { let project_name: String; if args.len() <= 3 { - project_name = "".to_string(); + project_name = "".to_owned(); open_editor(&project_name); } else { project_name = args[3].clone(); @@ -99,21 +98,21 @@ pub fn project_command() { "todo" => choose_todo(), "copy" => copy_command(), _ => { - command_usage(&project_help()); + command_usage(project_help()); } } } // new project -fn new_project(name: String) { +fn new_project(name: &str) { let args: Vec = env::args().collect(); if let Some(arg) = args.iter().last() { match arg.as_str().trim() { "-h" => { - command_usage(&project_help()); + command_usage(project_help()); } "--help" => { - command_usage(&project_help()); + command_usage(project_help()); } _ => {} } @@ -121,20 +120,20 @@ fn new_project(name: String) { inquire::set_global_render_config(utils::get_render_config()); let option_select = - utils::get_select_project_option("Which tech do you want to use ?".to_string()); + utils::get_select_project_option("Which tech do you want to use ?"); - match fs::create_dir(name.clone()) { + match fs::create_dir(name) { Ok(_) => println!("Directory created successfully"), - Err(e) => println!("Failed to create directory: {}", e), + Err(e) => println!("Failed to create directory: {e}"), } - lrncore::path::change_work_dir(&name); + lrncore::path::change_work_dir(name); match option_select { - Ok(choice) => new_project_by_choice(&choice, &name), + Ok(choice) => new_project_by_choice(&choice, name), Err(_) => println!("There was an error, please try again"), } } -fn new_project_by_choice(tech: &String, name: &str) { +fn new_project_by_choice(tech: &str, name: &str) { match tech { tech if tech == "Node.js" => new_nodejs_project(tech), tech if tech == "Python" => new_python_project(tech), diff --git a/src/projects/open/mod.rs b/src/projects/open/mod.rs index d2fa956..bb79fc6 100644 --- a/src/projects/open/mod.rs +++ b/src/projects/open/mod.rs @@ -9,8 +9,8 @@ use std::process::Command; use super::nxs; -pub fn open_help() -> String { - let usage = r" +pub fn open_help() -> &'static str{ + (r" Usage: nyx project open [args] Arguments: @@ -19,9 +19,7 @@ Arguments: Options: -h, --help Show this help message - "; - - usage.to_string() + ") as _ } pub fn open_editor(project: &str) { @@ -30,10 +28,10 @@ pub fn open_editor(project: &str) { if let Some(arg) = args.iter().last() { match arg.as_str().trim() { "-h" => { - command_usage(&open_help()); + command_usage(open_help()); } "--help" => { - command_usage(&open_help()); + command_usage(open_help()); } _ => {} } @@ -41,8 +39,8 @@ pub fn open_editor(project: &str) { let mut user_input_project = project.to_string(); if project.is_empty() { let app_name = utils::prompt_message( - "Enter project name:".to_string(), - "Failed to get user input".to_string(), + "Enter project name:", + "Failed to get user input", ); user_input_project = app_name; } diff --git a/src/projects/templates/mod.rs b/src/projects/templates/mod.rs index a5c3dd9..9bb2eed 100644 --- a/src/projects/templates/mod.rs +++ b/src/projects/templates/mod.rs @@ -350,7 +350,7 @@ Cargo.lock #.idea/ "#; -pub fn new_gitignore(tech: &str) -> String { +pub fn new_gitignore(tech: &str) -> &'static str{ let file_template: &str = match tech { "Node.js" => NODEJS_GITIGNORE_TEMPLATE, "Python" => PYTHON_GITIGNORE_TEMPLATE, @@ -358,12 +358,12 @@ pub fn new_gitignore(tech: &str) -> String { "Rust" => RUST_GITIGNORE_TEMPLATE, _ => "", }; - let template = format!("{}", &file_template); + let template = &file_template; let mut file = match fs::File::create(".gitignore") { Ok(file) => file, - Err(e) => panic!("Failed to create file: {}", e), + Err(e) => panic!("Failed to create file: {e}"), }; file.write_all(template.as_bytes()) .expect("Failed to write to file"); - return template; + template } diff --git a/src/projects/todo/helpers.rs b/src/projects/todo/helpers.rs index aada710..d78e414 100644 --- a/src/projects/todo/helpers.rs +++ b/src/projects/todo/helpers.rs @@ -10,23 +10,18 @@ use crate::utils::log; use std::io::Read; use std::io::Write; -use lrncore::vec_of_strings; - -pub fn add_new_todo(mut todo_vec: Vec, new_todo: &str) -> Vec { - let deserial_todo_vec: Vec = todo_vec.clone(); - let id: u8; - if !deserial_todo_vec.is_empty() { - id = deserial_todo_vec.last().clone().unwrap().id + 1; +pub fn add_new_todo(todo_vec: &mut Vec, new_todo: &str) { + let id: u8 = if !todo_vec.is_empty() { + todo_vec.last().unwrap().id + 1 } else { - id = 1; - } + 1 + }; let new_todo_inst: Todo = Todo { - id: id, - status: "".to_string(), - note: new_todo.to_string(), + id, + status: "".to_owned(), + note: new_todo.to_owned(), }; todo_vec.push(new_todo_inst); - todo_vec } pub fn create_todo_file(hash: &str) { @@ -52,14 +47,11 @@ pub fn create_todo_file(hash: &str) { let mut file_buff: Vec = Vec::new(); file_buff.extend_from_slice(&header_buff); file_buff.extend_from_slice(&content_buff); - let file_path = format!(".nxfs/projects/{}/todo", hash); + let file_path = format!(".nxfs/projects/{hash}/todo"); let mut todo_file: File = match File::create(file_path) { Ok(f) => f, Err(e) => { - log::log_from_log_level( - LogLevel::Error, - &format!("Failed to create todo file: {}", e), - ); + log::log_from_log_level(LogLevel::Error, &format!("Failed to create todo file: {e}")); return; } }; @@ -68,7 +60,7 @@ pub fn create_todo_file(hash: &str) { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to write buffer in todo file: {}", e), + &format!("Failed to write buffer in todo file: {e}"), ); } } @@ -76,23 +68,23 @@ pub fn create_todo_file(hash: &str) { } pub fn parse_todo_file(hash: &str) -> TodoFile { - let file = match File::open(format!(".nxfs/projects/{}/todo", hash)) { + let file = match File::open(format!(".nxfs/projects/{hash}/todo")) { Ok(f) => f, Err(e) => { - log::log_from_log_level(LogLevel::Error, &format!("Failed to open todo file: {}", e)); + log::log_from_log_level(LogLevel::Error, &format!("Failed to open todo file: {e}")); exit(51); } }; - // initialize TodoHeader size from structure and buffer + // Initialize TodoHeader size from structure and buffer let header_size = std::mem::size_of::(); let buffer = BufReader::new(file); - // vector containing the whole todo file + // Vector containing the whole todo file let mut bytes_vec: Vec = Vec::new(); for byte_or_error in buffer.bytes() { match byte_or_error { Ok(byte) => bytes_vec.push(byte), Err(e) => { - log::log_from_log_level(LogLevel::Error, &format!("Failed to read byte: {}", e)); + log::log_from_log_level(LogLevel::Error, &format!("Failed to read byte: {e}")); exit(50) } } @@ -107,14 +99,14 @@ pub fn parse_todo_file(hash: &str) -> TodoFile { let todo_content: TodoContent = bincode::deserialize(todo_content_bytes).expect("Failed to deserialize todo content"); let todo: TodoFile = TodoFile { - header: header, + header, content: todo_content, }; todo } pub fn update_todo_file(hash: &str, vec: Vec, todo: TodoFile) { - let file_path = format!(".nxfs/projects/{}/todo", hash); + let file_path = format!(".nxfs/projects/{hash}/todo"); let update_todo: TodoFile = TodoFile { header: todo.header, content: TodoContent { todos: vec }, @@ -124,10 +116,7 @@ pub fn update_todo_file(hash: &str, vec: Vec, todo: TodoFile) { let mut todo_file: File = match File::create(file_path) { Ok(f) => f, Err(e) => { - log::log_from_log_level( - LogLevel::Error, - &format!("Failed to update todo file: {}", e), - ); + log::log_from_log_level(LogLevel::Error, &format!("Failed to update todo file: {e}")); return; } }; @@ -136,7 +125,7 @@ pub fn update_todo_file(hash: &str, vec: Vec, todo: TodoFile) { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to write buffer in todo file: {}", e), + &format!("Failed to write buffer in todo file: {e}"), ); return; } @@ -144,7 +133,7 @@ pub fn update_todo_file(hash: &str, vec: Vec, todo: TodoFile) { log::log_from_log_level(LogLevel::Info, "Successfully update todo file"); } -pub fn todos_status_list() -> Vec { - let vec = vec_of_strings!("pending", "done", "wip"); +pub fn todos_status_list() -> Vec<&'static str> { + let vec = vec!["pending", "done", "wip"]; vec } diff --git a/src/projects/todo/mod.rs b/src/projects/todo/mod.rs index 28fcad1..2a3e081 100644 --- a/src/projects/todo/mod.rs +++ b/src/projects/todo/mod.rs @@ -16,8 +16,8 @@ use lrncore::usage_exit::command_usage; use crate::nxfs::config::LogLevel; use crate::projects::nxs; -use crate::utils::log; use crate::utils; +use crate::utils::log; use std::fs::{self}; #[derive(Debug, Deserialize, Serialize)] @@ -51,8 +51,8 @@ pub struct Todo { pub id: u8, } -pub fn todo_help() -> String { - let usage = r" +pub fn todo_help() -> &'static str { + (r" Usage: nyx project-todo Options: @@ -63,9 +63,7 @@ Options: -r, --remove Remove one todo by id -u, --update Update one todo -h, --help Show this help message -"; - - usage.to_string() +") as _ } pub fn choose_todo() { @@ -115,10 +113,10 @@ pub fn choose_todo() { } "-h" => { - command_usage(&todo_help()); + command_usage(todo_help()); } "--help" => { - command_usage(&todo_help()); + command_usage(todo_help()); } _ => {} } @@ -154,13 +152,10 @@ fn which_todo(choice: &str) { fn update_todo_list() { let app_name = utils::prompt_message( - "Enter project name:".to_string(), - "Error with the project name referred".to_string(), - ); - let new_todo = utils::prompt_message( - "Enter new todo:".to_string(), - "Error getting user input".to_string(), + "Enter project name:", + "Error with the project name referred", ); + let new_todo = utils::prompt_message("Enter new todo:", "Error getting user input"); let mut projects = nxs::get_all_project(); #[allow(unused_assignments)] let mut project_hash: [u8; 11] = [0u8; 11]; @@ -172,23 +167,23 @@ fn update_todo_list() { exit(10); } - let project_hash_str = String::from_utf8_lossy(&project_hash); - let todo_file = format!(".nxfs/projects/{}/todo", project_hash_str); + let project_hash_str = str::from_utf8(&project_hash).unwrap(); + let todo_file = format!(".nxfs/projects/{project_hash_str}/todo"); if !Path::new(&todo_file).exists() { - create_todo_file(&project_hash_str); + create_todo_file(project_hash_str); } - let todo: TodoFile = parse_todo_file(&project_hash_str); - let todo_vec: Vec = todo.content.todos.clone(); - let todo_vec_update = add_new_todo(todo_vec, &new_todo); - update_todo_file(&project_hash_str, todo_vec_update, todo); + let todo: TodoFile = parse_todo_file(project_hash_str); + let mut todo_vec: Vec = todo.content.todos.clone(); + add_new_todo(&mut todo_vec, &new_todo); + update_todo_file(project_hash_str, todo_vec, todo); } fn display_todo_list() { // get todos from project name let mut projects = nxs::get_all_project(); let app_name = utils::prompt_message( - "Enter project name:".to_string(), - "Error with the project name referred".to_string(), + "Enter project name:", + "Error with the project name referred", ); #[allow(unused_assignments)] let mut project_hash: [u8; 11] = [0u8; 11]; @@ -199,22 +194,19 @@ fn display_todo_list() { log::log_from_log_level(LogLevel::Error, "Project not found"); exit(10); } - let project_hash_str = String::from_utf8_lossy(&project_hash); - let todo: TodoFile = parse_todo_file(&project_hash_str); - let todo_vec: Vec = todo.content.todos.clone(); + let project_hash_str = str::from_utf8(&project_hash).unwrap(); + let todo: TodoFile = parse_todo_file(project_hash_str); + let todo_vec: Vec = todo.content.todos; // display todos let builder = Table::builder(&todo_vec).index().name(None); let mut table = builder.build(); table.with(Style::modern()); - println!("{}", table); + println!("{table}"); } fn prune_todo() { let mut projects = nxs::get_all_project(); - let project_name = utils::prompt_message( - "Enter project name:".to_string(), - "Error with the user input".to_string(), - ); + let project_name = utils::prompt_message("Enter project name:", "Error with the user input"); #[allow(unused_assignments)] let mut project_hash: [u8; 11] = [0u8; 11]; if let Some(pos) = projects @@ -227,7 +219,7 @@ fn prune_todo() { log::log_from_log_level(LogLevel::Error, "Project not found"); exit(10); } - let project_hash_str = String::from_utf8_lossy(&project_hash); + let project_hash_str = str::from_utf8(&project_hash).unwrap(); let confirm = utils::prompt::confirm_prompt( "Are you sure you want to prune the todo list ?", @@ -237,16 +229,13 @@ fn prune_todo() { return; } - let file_path = format!(".nxfs/projects/{}/todo", project_hash_str); + let file_path = format!(".nxfs/projects/{project_hash_str}/todo"); match fs::remove_file(file_path) { Ok(_) => { log::log_from_log_level(LogLevel::Info, "Successfully remove todo file"); } Err(e) => { - log::log_from_log_level( - LogLevel::Error, - &format!("Failed to remove todo file: {}", e), - ); + log::log_from_log_level(LogLevel::Error, &format!("Failed to remove todo file: {e}")); } }; log::log_from_log_level(LogLevel::Info, "To-do list cleared successfully"); @@ -254,13 +243,10 @@ fn prune_todo() { fn remove_todo() { let mut projects = nxs::get_all_project(); - let project_name = utils::prompt_message( - "Enter project name:".to_string(), - "Error getting user input".to_string(), - ); + let project_name = utils::prompt_message("Enter project name:", "Error getting user input"); let ask_id = utils::prompt_message( - "Enter todo id you want to delete:".to_string(), - "Failed to get the user input".to_string(), + "Enter todo id you want to delete:", + "Failed to get the user input", ); let project_hash: [u8; 11]; if let Some(pos) = projects @@ -274,28 +260,21 @@ fn remove_todo() { exit(10); } - let project_hash_str = String::from_utf8_lossy(&project_hash); - let todo: TodoFile = parse_todo_file(&project_hash_str); + let project_hash_str = str::from_utf8(&project_hash).unwrap(); + let todo: TodoFile = parse_todo_file(project_hash_str); let mut todo_vec: Vec = todo.content.todos.clone(); let todo_id_stdi = ask_id.parse::().expect("Failed to parse todo id to u8"); if let Some(todo) = todo_vec.iter().position(|todo| todo.id == todo_id_stdi) { todo_vec.remove(todo); }; - update_todo_file(&project_hash_str, todo_vec, todo); + update_todo_file(project_hash_str, todo_vec, todo); log::log_from_log_level(LogLevel::Info, "Successfully remove the to-do"); } fn update_todo_status() { - let project_name = utils::prompt_message( - "Enter project name:".to_string(), - "Error getting user input".to_string(), - ); - let ask_todo_id = utils::prompt_message( - "Enter todo id:".to_string(), - "Error getting user input".to_string(), - ); - let new_status = - utils::get_select_option("Select new status:".to_string(), todos_status_list()); + let project_name = utils::prompt_message("Enter project name:", "Error getting user input"); + let ask_todo_id = utils::prompt_message("Enter todo id:", "Error getting user input"); + let new_status = utils::get_select_option("Select new status:", todos_status_list()); let mut projects = nxs::get_all_project(); let mut project_hash: [u8; 11] = [0u8; 11]; if let Some(pos) = projects @@ -305,9 +284,9 @@ fn update_todo_status() { let app = projects.remove(pos); project_hash = app.project_hash; } - let project_hash_str = String::from_utf8_lossy(&project_hash); - let todo: TodoFile = parse_todo_file(&project_hash_str); - let mut todo_vec: Vec = todo.content.todos.clone(); + let project_hash_str = str::from_utf8(&project_hash).unwrap(); + let todo: TodoFile = parse_todo_file(project_hash_str); + let mut todo_vec: Vec = todo.content.todos; let todo_id_stdi = ask_todo_id .parse::() .expect("Failed to parse todo id to u8"); @@ -321,9 +300,9 @@ fn update_todo_status() { updated_todo.id = find_todo.id; updated_todo.note = find_todo.note; }; - let todo: TodoFile = parse_todo_file(&project_hash_str); + let todo: TodoFile = parse_todo_file(project_hash_str); updated_todo.status = new_status.expect("Failed to get the updated status"); todo_vec.push(updated_todo); - update_todo_file(&project_hash_str, todo_vec, todo); + update_todo_file(project_hash_str, todo_vec, todo); log::log_from_log_level(LogLevel::Info, "Successfully update the to-do"); } diff --git a/src/projects/update/mod.rs b/src/projects/update/mod.rs index 22eb063..cc6cb4a 100644 --- a/src/projects/update/mod.rs +++ b/src/projects/update/mod.rs @@ -33,16 +33,14 @@ use crate::{ }; use lrncore::usage_exit::command_usage; -pub fn project_update_help() -> String { - let usage = r" +pub fn project_update_help() -> &'static str{ + (r" Usage: nyx project-update Options: -h, --help Show this help message -"; - - return usage.to_string(); +") as _ } pub fn update_project_properties() { @@ -50,10 +48,10 @@ pub fn update_project_properties() { if let Some(arg) = args.iter().last() { match arg.as_str().trim() { "-h" => { - command_usage(&project_update_help()); + command_usage(project_update_help()); } "--help" => { - command_usage(&project_update_help()); + command_usage(project_update_help()); } _ => {} } @@ -61,8 +59,8 @@ pub fn update_project_properties() { let mut projects = nxs::get_all_project(); inquire::set_global_render_config(utils::get_render_config()); let app_name = utils::prompt_message( - "Enter project name:".to_string(), - "Error with the project name referred".to_string(), + "Enter project name:", + "Error with the project name referred", ); let mut current_project: ProjectEntry = ProjectEntry { @@ -73,9 +71,9 @@ pub fn update_project_properties() { if let Some(pos) = projects.iter().position(|app| app.project_name == app_name) { log_from_log_level(LogLevel::Info, "Project found"); let app = projects.remove(pos); - current_project.project_hash = app.project_hash.clone(); - current_project.project_name = app.project_name.clone(); - current_project.project_size = app.project_size.clone(); + current_project.project_hash = app.project_hash; + current_project.project_name = app.project_name; + current_project.project_size = app.project_size; } else { log_from_log_level(LogLevel::Error, "Project not found"); exit(10); @@ -97,7 +95,7 @@ pub fn update_project_properties() { version: String::new(), }, }; - let hash = String::from_utf8_lossy(¤t_project.project_hash); + let hash = str::from_utf8(¤t_project.project_hash).unwrap(); nxp::parse_nxp_file(&format!(".nxfs/projects/{}/content", &hash), &mut nxp); let project_content: NXPContent = nxp.content; let buffer = update_editor(project_content); @@ -123,5 +121,5 @@ pub fn update_project_properties() { }; nxs::update_project_entries(&mut update_nxs, projects); } - nxp::update_nxp(&hash, buffer); + nxp::update_nxp(hash, buffer); } diff --git a/src/update/mod.rs b/src/update/mod.rs index 1b70cde..f2c9883 100644 --- a/src/update/mod.rs +++ b/src/update/mod.rs @@ -1,74 +1,88 @@ -use crate::utils; +use std::{ + env, + process::{exit, Command, Stdio}, + thread::{self, JoinHandle}, +}; -use colored::Colorize; -use lrncore::path::change_work_dir; -use std::process::{Command, Stdio}; -use throbber::Throbber; +use lrncore::usage_exit::command_usage; -/// Check if there's a new version of nyx and if so update the current one -pub fn update_bin() { - change_work_dir(&utils::env::get_nyx_env_var()); - let nyx_art = utils::nyx_ascii_art(); - // throbber - let mut building_throbber = Throbber::new() - .message("Building latest NYX binary...".to_string()) - .frames(&throbber::ROTATE_F); - let mut update_throbber = Throbber::new() - .message("Updating NYX...".to_string()) - .frames(&throbber::ROTATE_F); - println!("{}", nyx_art.truecolor(138, 43, 226)); - building_throbber.start(); +use crate::{ + logs::nyx_log, + nxfs::config::{parse_config_file, LogLevel}, + utils::log::log_from_log_level, +}; - // nyx version - let nyx_current_version = Command::new("nyx") - .arg("version") - .output() - .expect("Failed to get the current version of NYX"); - let nyx_target_build_location = utils::env::get_nyx_env_var() + "/target/release"; - lrncore::path::change_work_dir(&nyx_target_build_location); - let mut build_target = Command::new("cargo") - .arg("build") - .arg("--release") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn() - .expect("Failed to build the target binary"); - let wait_build_target = build_target - .wait() - .expect("Failed to wait the cargo build command"); - if !wait_build_target.success() { - building_throbber.fail("Error building latest binary".to_string()); - panic!(); +fn update_help() -> &'static str { + (r" +Usage: nyx update [subcommand] [arguments] [options] + +Subcommands: + update Update the command specified in configuration file + +Options: + -h, --help Show this help message + + ") as _ +} + +pub fn update_command() { + let args: Vec = env::args().collect(); + if args.len() <= 2 { + update_all_commands(); + exit(0); } - building_throbber.success("Successfully build latest binary".to_string()); - building_throbber.end(); - let nyx_latest_version = Command::new("./nyx") - .arg("version") - .output() - .expect("Failed to get the current version of NYX"); - if String::from_utf8(nyx_latest_version.stdout) != String::from_utf8(nyx_current_version.stdout) - { - println!("A new version of NYX has been found"); - update_throbber.start(); - lrncore::path::change_work_dir(&utils::env::get_nyx_env_var()); - let mut cargo_install = Command::new("cargo") - .arg("install") - .arg("--path") - .arg(".") - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn() - .expect("Failed to update to the latest version"); - let wait_cargo_install = cargo_install - .wait() - .expect("Failed to wait the cargo install command"); - if !wait_cargo_install.success() { - update_throbber.fail("Failed to update NYX to the latest version".to_string()); - panic!("Failed to update NYX"); + match args[2].as_str() { + "" => (), + + _ => { + command_usage(update_help()); } - update_throbber.success("Successfully update NYX".to_string()); - update_throbber.end(); + } +} + +fn update_all_commands() { + let config = parse_config_file().expect("Failed to parse config file"); + let safe_mode = config.security.secure_mode; + if safe_mode { + nyx_log("Secure mode enabled. You cannot execute this operation."); + exit(11); + } else { + log_from_log_level(LogLevel::Warn, "Secure mode disabled."); + log_from_log_level(LogLevel::Warn, "Caution: You are about to execute a command from your configuration file. Make sure the command is safe and does not include potentially harmful operations."); + } + log_from_log_level(LogLevel::Info, "Starting updating all specified command."); + // Contains all spawned threads + let mut handlers: Vec> = Vec::new(); + // Spawn a thread per command to update + for each in config.user.update_list { + let thread = thread::Builder::new() + .name(each.command.to_owned()) + .spawn(move || { + execute_update_command(&each.command, &each.sub_command); + }) + .expect("Failed to create thread"); + handlers.push(thread); + } + // Join all threads + for handle in handlers { + handle.join().expect("Failed to join the thread"); + } + log_from_log_level( + LogLevel::Info, + "Successfully updated all specified command!", + ); +} + +fn execute_update_command(cmd: &str, subcmd: &str) { + let mut command = Command::new(cmd) + .arg(subcmd) + .stdout(Stdio::null()) + .spawn() + .unwrap_or_else(|_| panic!("Failed to execute the command: {cmd}")); + let wait_command = command.wait().expect("Failed to wait the command"); + if !wait_command.success() { + log_from_log_level(LogLevel::Error, "Failed to execute the command"); } else { - println!("You already have the latest version of NYX!"); + log_from_log_level(LogLevel::Info, &format!("Successfully updated {cmd}")); } } diff --git a/src/upgrade/mod.rs b/src/upgrade/mod.rs new file mode 100644 index 0000000..e71f8ad --- /dev/null +++ b/src/upgrade/mod.rs @@ -0,0 +1,74 @@ +use crate::utils; + +use colored::Colorize; +use lrncore::path::change_work_dir; +use std::process::{Command, Stdio}; +use throbber::Throbber; + +/// Check if there's a new version of nyx and if so update the current one +pub fn upgrade_bin() { + change_work_dir(&utils::env::get_nyx_env_var()); + let nyx_art = utils::nyx_ascii_art(); + // throbber + let mut building_throbber = Throbber::new() + .message("Building latest NYX binary...".to_owned()) + .frames(&throbber::ROTATE_F); + let mut update_throbber = Throbber::new() + .message("Updating NYX...".to_owned()) + .frames(&throbber::ROTATE_F); + println!("{}", nyx_art.truecolor(138, 43, 226)); + building_throbber.start(); + + // nyx version + let nyx_current_version = Command::new("nyx") + .arg("version") + .output() + .expect("Failed to get the current version of NYX"); + let nyx_target_build_location = utils::env::get_nyx_env_var() + "/target/release"; + lrncore::path::change_work_dir(&nyx_target_build_location); + let mut build_target = Command::new("cargo") + .arg("build") + .arg("--release") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("Failed to build the target binary"); + let wait_build_target = build_target + .wait() + .expect("Failed to wait the cargo build command"); + if !wait_build_target.success() { + building_throbber.fail("Error building latest binary".to_owned()); + panic!(); + } + building_throbber.success("Successfully build latest binary".to_owned()); + building_throbber.end(); + let nyx_latest_version = Command::new("./nyx") + .arg("version") + .output() + .expect("Failed to get the current version of NYX"); + if str::from_utf8(&nyx_latest_version.stdout).unwrap() != str::from_utf8(&nyx_current_version.stdout).unwrap() + { + println!("A new version of NYX has been found"); + update_throbber.start(); + lrncore::path::change_work_dir(&utils::env::get_nyx_env_var()); + let mut cargo_install = Command::new("cargo") + .arg("install") + .arg("--path") + .arg(".") + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .spawn() + .expect("Failed to update to the latest version"); + let wait_cargo_install = cargo_install + .wait() + .expect("Failed to wait the cargo install command"); + if !wait_cargo_install.success() { + update_throbber.fail("Failed to upgrade NYX to the latest version".to_owned()); + panic!("Failed to upgrade NYX"); + } + update_throbber.success("Successfully upgrade NYX".to_owned()); + update_throbber.end(); + } else { + println!("You already have the latest version of NYX!"); + } +} diff --git a/src/utils/editor.rs b/src/utils/editor.rs index c412115..a2bfd80 100644 --- a/src/utils/editor.rs +++ b/src/utils/editor.rs @@ -25,7 +25,7 @@ pub fn update_editor(content: NXPContent) -> Vec { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to parse config file: {}", e), + &format!("Failed to parse config file: {e}"), ); return vec![]; } @@ -36,7 +36,7 @@ pub fn update_editor(content: NXPContent) -> Vec { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to create temp file: {}", e), + &format!("Failed to create temp file: {e}"), ); return vec![]; } @@ -46,7 +46,7 @@ pub fn update_editor(content: NXPContent) -> Vec { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to parse project content to JSON: {}", e), + &format!("Failed to parse project content to JSON: {e}"), ); return vec![]; } @@ -56,7 +56,7 @@ pub fn update_editor(content: NXPContent) -> Vec { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to write current project buffer to temp file: {}", e), + &format!("Failed to write current project buffer to temp file: {e}"), ); return vec![]; } @@ -73,7 +73,7 @@ pub fn update_editor(content: NXPContent) -> Vec { { Ok(_) => (), Err(e) => { - log::log_from_log_level(LogLevel::Error, &format!("Failed to open temp file: {}", e)); + log::log_from_log_level(LogLevel::Error, &format!("Failed to open temp file: {e}")); return vec![]; } } @@ -82,7 +82,7 @@ pub fn update_editor(content: NXPContent) -> Vec { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to write JSON str to struct: {}", e), + &format!("Failed to write JSON str to struct: {e}"), ); return vec![]; } @@ -99,7 +99,7 @@ pub fn open_new_editor(path: &str) { Err(e) => { log::log_from_log_level( LogLevel::Error, - &format!("Failed to parse config file: {}", e), + &format!("Failed to parse config file: {e}"), ); "vim".to_owned() } diff --git a/src/utils/env.rs b/src/utils/env.rs index 0a0e023..ad256b7 100644 --- a/src/utils/env.rs +++ b/src/utils/env.rs @@ -8,8 +8,7 @@ use std::env; pub fn get_nyx_env_var() -> String { let env_var = "NYX"; match env::var(env_var) { - Ok(v) => return v, - Err(e) => panic!("${} is not set ({})", env_var, e), + Ok(v) => v, + Err(e) => panic!("${env_var} is not set ({e})"), } } - diff --git a/src/utils/fsys.rs b/src/utils/fsys.rs index faf4bcc..d119695 100644 --- a/src/utils/fsys.rs +++ b/src/utils/fsys.rs @@ -23,7 +23,7 @@ pub fn create_dir(path: &str) { } } -pub fn rm_command(path: String) { +pub fn rm_command(path: &str) { if path.is_empty() { log::log_from_log_level(LogLevel::Error, "Path is empty"); exit(4) @@ -31,7 +31,7 @@ pub fn rm_command(path: String) { let forbidden_names = ["/", ".", ".."]; let forbidden_patterns = ['*', '?', '&', ';', '|', '`']; - if forbidden_names.contains(&path.as_str()) { + if forbidden_names.contains(&path) { log::log_from_log_level(LogLevel::Error, "Input contains forbidden names."); exit(2) }; diff --git a/src/utils/log.rs b/src/utils/log.rs index f472b76..551db3e 100644 --- a/src/utils/log.rs +++ b/src/utils/log.rs @@ -1,3 +1,6 @@ +use chrono::Utc; +use std::fs::OpenOptions; +use std::io::Write; use std::process::exit; use lrncore::logs; @@ -6,7 +9,30 @@ use crate::nxfs::{self, config::LogLevel}; pub fn log_from_log_level(log_level: LogLevel, log_msg: &str) { let config = nxfs::config::parse_config_file(); - let config_log_level = config.unwrap().behavior.log_level; + let unwrapped_config = config.unwrap(); + let config_log_level = unwrapped_config.behavior.log_level; + let save_file = unwrapped_config.behavior.save_logs; + + if save_file { + let timestamp = Utc::now(); + let log = format!( + "{} {}", + timestamp.format("%d-%m-%Y %H:%M:%S"), + log_msg + ); + let log_path = unwrapped_config.internal_path.logs; + // log file path by day + let daily_log_path = format!("{}{}", log_path, timestamp.format("%d-%m-%Y")); + let mut file = OpenOptions::new() + .create(true) + .append(true) + .open(daily_log_path) + .unwrap(); + + if let Err(e) = writeln!(file, "{log}") { + eprintln!("Couldn't write to file: {e}"); + } + } if log_level <= config_log_level { match log_level { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index da7b398..b073747 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -19,8 +19,8 @@ use throbber::Throbber; pub mod editor; pub mod env; pub mod fsys; -pub mod prompt; pub mod log; +pub mod prompt; pub fn get_render_config() -> RenderConfig<'static> { let mut render_config = RenderConfig::default(); @@ -46,43 +46,44 @@ pub fn get_render_config() -> RenderConfig<'static> { render_config } -pub fn get_tech_option() -> Vec { - let options: Vec = vec![ - "Node.js".to_string(), - "Python".to_string(), - "Golang".to_string(), - "Rust".to_string(), - "C++".to_string(), - "Other".to_string(), +pub fn get_tech_option() -> Vec<&'static str> { + let options: Vec<&str> = vec![ + "Node.js", + "Python", + "Golang", + "Rust", + "C++", + "Other", ]; options } -pub fn get_select_project_option(prompt: String) -> std::result::Result { - let options = get_tech_option(); +pub fn get_select_project_option(prompt: &str) -> std::result::Result { + let options = get_tech_option().into_iter().map(|s| s.to_owned()).collect(); - let ans: std::result::Result = Select::new(&prompt, options).prompt(); + let ans: std::result::Result = Select::new(prompt, options).prompt(); ans } pub fn get_select_option( - prompt: String, - option: Vec, + prompt: &str, + option: Vec<&str>, ) -> std::result::Result { - let ans: std::result::Result = Select::new(&prompt, option).prompt(); + let options: Vec = option.into_iter().map(|s| s.to_string()).collect(); + let ans: std::result::Result = Select::new(prompt, options).prompt(); ans } -pub fn prompt_message(message: String, error_message: String) -> String { +pub fn prompt_message(message: &str, error_message: &str) -> String { inquire::set_global_render_config(get_render_config()); - let message = Text::new(&message).prompt().expect(&error_message); + let message = Text::new(message).prompt().expect(error_message); message.to_lowercase() } -pub fn nyx_ascii_art() -> String { - let ascii_art = r" +pub fn nyx_ascii_art() -> &'static str{ + (r" _ ( ( /||\ /||\ /| | \ ( |( \ / )( \ / ) @@ -92,12 +93,9 @@ pub fn nyx_ascii_art() -> String { | ) \ | | | ( / \ ) |/ )_) \_/ |/ \| -"; - - ascii_art.to_string() +") as _ } -pub fn custom_throbber(message: String) -> Throbber { - let custom_throbber = Throbber::new().message(message).frames(&throbber::ROTATE_F); - return custom_throbber; +pub fn custom_throbber(message: &str) -> Throbber { + Throbber::new().message(message.to_owned()).frames(&throbber::ROTATE_F) } diff --git a/src/utils/prompt.rs b/src/utils/prompt.rs index 9a45d7c..18bbf8d 100644 --- a/src/utils/prompt.rs +++ b/src/utils/prompt.rs @@ -17,6 +17,7 @@ pub fn confirm_prompt(message: &str, help_message: &str) -> bool { true } +// if secure mode is enabled, ask user confirmation. Else return always true pub fn confirm_prompt_safe_mode(message: &str, help_message: &str) -> bool { let config = nxfs::config::parse_config_file().expect("Failed to parse NYX config file"); if config.security.secure_mode {