From 3059766c2419d345c1f4345f922aba927b1e3657 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:26:53 +0100 Subject: [PATCH 01/13] Feat(args.rs): Added Clear Cache Argument --- src/args.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/args.rs b/src/args.rs index b6b2df9..43c84f1 100644 --- a/src/args.rs +++ b/src/args.rs @@ -18,5 +18,9 @@ pub struct SandboxArgs { /// Search for Environment #[clap(short = 'I', long, default_value = "")] pub install: String, + + /// Clear the Install Cache + #[clap(short = 'C', long)] + pub clearcache: bool, } From 666a4c6855e077d130d39e57927c014944ab2781 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:27:08 +0100 Subject: [PATCH 02/13] Feat(cache.rs): Caching Support --- src/cache.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 src/cache.rs diff --git a/src/cache.rs b/src/cache.rs new file mode 100644 index 0000000..c0bef2d --- /dev/null +++ b/src/cache.rs @@ -0,0 +1,25 @@ +use tokio::fs; +use colored::Colorize; + +use crate::get_cache_path; + +pub async fn ensure_installed() { + let cache_path = get_cache_path(); + + fs::create_dir_all(cache_path).await.unwrap(); +} + +pub async fn clear_cache() { + let cache_path = get_cache_path(); + + let cache_folder_is_empty = fs::read_dir(&cache_path).await.unwrap().next_entry().await.unwrap().is_none(); + + if cache_folder_is_empty { + println!("The Install Cache is {}!", "Empty".bright_green()) + } else { + fs::remove_dir_all(&cache_path).await.unwrap(); + fs::create_dir(&cache_path).await.unwrap(); + + println!("{} Cleared The Install Cache!", "Successfully".bright_green()) + } +} From 8b5c21ededcac35f907be33a0dfb5f4eed1ec692 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:27:29 +0100 Subject: [PATCH 03/13] Refactor(download.rs): Opt to use get_beaches_path --- src/download.rs | 115 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 39 deletions(-) diff --git a/src/download.rs b/src/download.rs index 0bb081f..e813d2c 100644 --- a/src/download.rs +++ b/src/download.rs @@ -5,7 +5,6 @@ use std::path::Path; use std::thread; use std::time::Duration; use std::fs; -use std::env; use std::{cmp::min, fmt::Write}; @@ -15,66 +14,104 @@ use tar::Archive; use indicatif::{ProgressBar, ProgressState, ProgressStyle}; use colored::Colorize; +use crate::get_beaches_path; +use crate::get_cache_path; use crate::get_path; +use crate::cache; pub async fn install(id: String) -> Result<(), Box> { - let base_path = match env::consts::OS { - "windows" => { - let appdata = std::env::var("appdata").unwrap(); - let beaches_path = format!("{}/sandbox/beaches/", appdata); - beaches_path - } - _ => "/usr/share/sandbox/beaches/".to_string() - }; - + let base_path = get_beaches_path(); let environment_path = get_path(id.clone()).await; let download_url = format!("https://github.com/the-sandbox-project/sandbox-templates/raw/master/{}", environment_path); let download_path = format!("{}{}", base_path, environment_path); - let client = Client::new(); + let tar_name = environment_path.split('/').last().unwrap(); + - let response = client.get(download_url).send().await?; - - if response.status().is_success() { - let language_path = Path::new(&download_path).parent().unwrap().to_str().unwrap(); - fs::create_dir_all(language_path)?; + cache::ensure_installed().await; + let cache_path = get_cache_path(); - let mut file = File::create(&download_path)?; + let formatted_cache_path = format!("{}{}", cache_path, tar_name); - let mut downloaded = 0; - let total_size = response.content_length().unwrap(); + let tar_in_cache = Path::new(&formatted_cache_path).exists(); + if tar_in_cache { + println!("{} found in {}! Installing from {}...", id.blue(), "Cache".bright_green(), "Cache".bright_green()); - let pb = ProgressBar::new(total_size); - pb.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})") - .unwrap() - .with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()) - .progress_chars("#>-")); + let language_path = Path::new(&download_path).parent().unwrap().to_str().unwrap(); - while downloaded < total_size { - let new = min(downloaded + 223211, total_size); - downloaded = new; - pb.set_position(new); - thread::sleep(Duration::from_millis(12)); - } - - pb.finish_with_message("downloaded"); + let unzip_path = format!("{}/{}", language_path, id); - let content = response.bytes().await?; + fs::create_dir_all(&language_path)?; - io::copy(&mut content.as_ref(), &mut file)?; - - let unzip_path = format!("{}/{}", language_path, id); + fs::copy(&formatted_cache_path, &download_path)?; let tar_gz = File::open(&download_path)?; let tar = GzDecoder::new(tar_gz); let mut archive = Archive::new(tar); archive.unpack(&unzip_path)?; + + File::create(&formatted_cache_path)?; + + fs::copy(&download_path, &formatted_cache_path)?; + fs::remove_file(&download_path)?; - println!("Installed {}! Test it out with: sandbox --new {}", id.bright_green(), id.bright_green()) - } - Ok(()) + println!("Installed {}! Test it out with: sandbox --new {}", id.bright_green(), id.bright_green()); + + Ok(()) + } else { + let client = Client::new(); + + let response = client.get(download_url).send().await?; + + if response.status().is_success() { + let language_path = Path::new(&download_path).parent().unwrap().to_str().unwrap(); + + fs::create_dir_all(language_path)?; + + let mut file = File::create(&download_path)?; + + let mut downloaded = 0; + let total_size = response.content_length().unwrap(); + + let pb = ProgressBar::new(total_size); + pb.set_style(ProgressStyle::with_template("{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({eta})") + .unwrap() + .with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap()) + .progress_chars("#>-")); + + while downloaded < total_size { + let new = min(downloaded + 223211, total_size); + downloaded = new; + pb.set_position(new); + thread::sleep(Duration::from_millis(12)); + } + + pb.finish_with_message("downloaded"); + + let content = response.bytes().await?; + + io::copy(&mut content.as_ref(), &mut file)?; + + let unzip_path = format!("{}/{}", language_path, id); + + let tar_gz = File::open(&download_path)?; + let tar = GzDecoder::new(tar_gz); + let mut archive = Archive::new(tar); + + archive.unpack(&unzip_path)?; + + File::create(&formatted_cache_path)?; + + fs::copy(&download_path, &formatted_cache_path)?; + + fs::remove_file(&download_path)?; + + println!("Installed {}! Test it out with: sandbox --new {}", id.bright_green(), id.bright_green()) + } + Ok(()) + } } From 71be7c3d3a1118ce667b0c9ab3e46d97c749b126 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:27:38 +0100 Subject: [PATCH 04/13] Feat(lib.rs): Support for Caching --- src/lib.rs | 41 +++++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9b060fb..c68584f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ mod search; mod install; mod uninstall; mod download; +mod cache; mod new; use std::error::Error; @@ -17,6 +18,7 @@ use search::search; use install::install_environment; use uninstall::uninstall_environment; use new::create_new_environment; +use cache::clear_cache; use clap::Parser; use serde_yaml::{Value, Mapping}; @@ -40,6 +42,10 @@ pub async fn run() { if !args.uninstall.is_empty() { uninstall_environment(args.uninstall).await; } + + if args.clearcache { + clear_cache().await; + } } pub async fn get_templates_mapping() -> Result> { @@ -140,14 +146,7 @@ pub async fn id_is_valid(id: impl Into) -> bool{ pub async fn in_system(id: impl Into) -> bool { let id = id.into(); - let base_path = match env::consts::OS { - "windows" => { - let appdata = std::env::var("appdata").unwrap(); - let beaches_path = format!("{}/sandbox/beaches/", appdata); - beaches_path - } - _ => "/usr/share/sandbox/beaches/".to_string(), - }; + let base_path = get_beaches_path(); let path = get_path(id.clone()).await; let environment_path = path.split("/").collect::>()[0].to_owned() + "/" + &id; @@ -161,3 +160,29 @@ pub async fn in_system(id: impl Into) -> bool { false } } + +pub fn get_beaches_path() -> String { + match env::consts::OS { + "windows" => { + let appdata = env::var("APPDATA").unwrap(); + let beaches_path = format!("{}/sandbox/beaches/", appdata); + beaches_path + } + _ => "/usr/share/sandbox/beaches/".to_string(), + } +} + +pub fn get_cache_path() -> String { + match env::consts::OS { + "windows" => { + let appdata = env::var("LOCALAPPDATA").unwrap(); + let beaches_path = format!("{}/Temp/sandbox/", appdata); + beaches_path + } + _ => { + let home_path = env::var("HOME").unwrap(); + let cache_path = format!("{}/.cache/sandbox/", home_path); + cache_path + } + } +} From 771b6957efb27642bb5d0352386d7926ab496a63 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:27:56 +0100 Subject: [PATCH 05/13] Feat(uninstall.rs): Opt to use get_beaches_path --- src/uninstall.rs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/uninstall.rs b/src/uninstall.rs index a0ca21f..f9174b2 100644 --- a/src/uninstall.rs +++ b/src/uninstall.rs @@ -1,7 +1,6 @@ -use std::env; use std::io::{stdin, stdout, Write}; -use crate::{get_path, id_is_valid, in_system}; +use crate::{get_path, get_beaches_path, id_is_valid, in_system}; use colored::Colorize; use tokio::fs; @@ -28,14 +27,7 @@ pub async fn uninstall_environment(environment: impl Into) { pub async fn uninstall(environment: impl Into) { let environment = environment.into(); - let base_path = match env::consts::OS { - "windows" => { - let appdata = std::env::var("appdata").unwrap(); - let beaches_path = format!("{}/sandbox/beaches/", appdata); - beaches_path - } - _ => "/usr/share/sandbox/beaches/".to_string(), - }; + let base_path = get_beaches_path(); let path = get_path(environment.clone()).await; let environment_path = path.split("/").collect::>()[0].to_owned() + "/" + &environment; From b2c885698462ac5415c32f5755c32aeaeb8eb44f Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:47:02 +0100 Subject: [PATCH 06/13] Feat(reinstall.rs): Temporary Reinstall Solution --- src/reinstall.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/reinstall.rs diff --git a/src/reinstall.rs b/src/reinstall.rs new file mode 100644 index 0000000..94a9e61 --- /dev/null +++ b/src/reinstall.rs @@ -0,0 +1,22 @@ +use crate::id_is_valid; +use crate::download::install; +use crate::uninstall::uninstall; + +use colored::Colorize; + +pub async fn reinstall_environment(id: impl Into) { + let id = id.into(); + + if id_is_valid(&id).await { + reinstall(&id).await; + } else { + println!("The environment ({}) does {} exist! You can search for an environment with\nsandbox --search {}", id.bright_green(), "not".red(), id.bright_green()); + } +} + +pub async fn reinstall(id: impl Into) { + let id = id.into(); + + uninstall(&id).await; + install(&id).await.unwrap(); +} From 8351914b5778ca2ec3b879f8c20ef92b740551fd Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:47:26 +0100 Subject: [PATCH 07/13] Reinstall(uninstall.rs): Impl for String Fn Arguments --- src/uninstall.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uninstall.rs b/src/uninstall.rs index f9174b2..60e3163 100644 --- a/src/uninstall.rs +++ b/src/uninstall.rs @@ -29,7 +29,7 @@ pub async fn uninstall(environment: impl Into) { let base_path = get_beaches_path(); - let path = get_path(environment.clone()).await; + let path = get_path(&environment).await; let environment_path = path.split("/").collect::>()[0].to_owned() + "/" + &environment; let formatted_path = format!("{}{}", base_path, environment_path); From f821728b07ccd5025cd729f59a7f301fa8ad5339 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:47:34 +0100 Subject: [PATCH 08/13] Feat(lib.rs): Reinstall Implementation --- src/lib.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index c68584f..4ad21b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ mod environment; mod search; mod install; mod uninstall; +mod reinstall; mod download; mod cache; mod new; @@ -17,6 +18,7 @@ use args::SandboxArgs; use search::search; use install::install_environment; use uninstall::uninstall_environment; +use reinstall::reinstall_environment; use new::create_new_environment; use cache::clear_cache; @@ -43,6 +45,10 @@ pub async fn run() { uninstall_environment(args.uninstall).await; } + if !args.reinstall.is_empty() { + reinstall_environment(args.reinstall).await; + } + if args.clearcache { clear_cache().await; } @@ -148,7 +154,7 @@ pub async fn in_system(id: impl Into) -> bool { let base_path = get_beaches_path(); - let path = get_path(id.clone()).await; + let path = get_path(&id).await; let environment_path = path.split("/").collect::>()[0].to_owned() + "/" + &id; let formatted_path = format!("{}{}", base_path, environment_path); From fa22b2f32e31c603b54dbf1710dec0838801664e Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:47:52 +0100 Subject: [PATCH 09/13] Refactor(environment.rs): Reinstall Implementation --- src/environment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/environment.rs b/src/environment.rs index df3eb25..f291db8 100644 --- a/src/environment.rs +++ b/src/environment.rs @@ -7,7 +7,7 @@ use crate::get_path; pub async fn open_environment(environment: String) { let editor = get_editor(); - let path = get_path(environment.clone()).await; + let path = get_path(&environment).await; let environment_path = path.split("/").collect::>()[0].to_owned() + "/" + &environment; let beaches_path = match env::consts::OS { From e6213f8dd4f784fbfb14bd7073b64861a30c8f82 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:48:04 +0100 Subject: [PATCH 10/13] Feat(args.rs): Reinstall Argument --- src/args.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/args.rs b/src/args.rs index 43c84f1..d3a519e 100644 --- a/src/args.rs +++ b/src/args.rs @@ -7,10 +7,6 @@ pub struct SandboxArgs { #[clap(short, long, default_value = "")] pub new: String, - /// Create a New Environment - #[clap(short = 'U', long, default_value = "")] - pub uninstall: String, - /// Search for Environment #[clap(short = 'S', long, default_value = "")] pub search: String, @@ -19,8 +15,17 @@ pub struct SandboxArgs { #[clap(short = 'I', long, default_value = "")] pub install: String, + /// Create a New Environment + #[clap(short = 'U', long, default_value = "")] + pub uninstall: String, + + /// Reinstall an Environment + #[clap(short = 'R', long)] + pub reinstall: String, + /// Clear the Install Cache #[clap(short = 'C', long)] pub clearcache: bool, + } From 8256d5a09babf0ce21a6aa4d6abb0e0477de1b4b Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:48:17 +0100 Subject: [PATCH 11/13] Feat(cache.rs): Cache Declaration --- src/cache.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/cache.rs b/src/cache.rs index c0bef2d..946d66f 100644 --- a/src/cache.rs +++ b/src/cache.rs @@ -1,7 +1,9 @@ +use std::path::Path; + use tokio::fs; use colored::Colorize; -use crate::get_cache_path; +use crate::{get_path, get_cache_path}; pub async fn ensure_installed() { let cache_path = get_cache_path(); @@ -23,3 +25,17 @@ pub async fn clear_cache() { println!("{} Cleared The Install Cache!", "Successfully".bright_green()) } } + +pub async fn in_cache(id: impl Into) -> bool { + let id = id.into(); + + let cache_path = get_cache_path(); + + let environment_path = get_path(&id).await; + let tar_name = environment_path.split('/').last().unwrap(); + + let formatted_cache_path = format!("{}{}", cache_path, tar_name); + let tar_in_cache = Path::new(&formatted_cache_path).exists(); + + tar_in_cache +} From 3fab04a18318ca919521da97e0b5becd7f3374b5 Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:48:33 +0100 Subject: [PATCH 12/13] Refactor(download.rs): Impl for Fn Arguments --- src/download.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/download.rs b/src/download.rs index e813d2c..f5b5a08 100644 --- a/src/download.rs +++ b/src/download.rs @@ -17,25 +17,25 @@ use colored::Colorize; use crate::get_beaches_path; use crate::get_cache_path; use crate::get_path; -use crate::cache; +use crate::cache::{self, in_cache}; + +pub async fn install(id: impl Into) -> Result<(), Box> { + let id = id.into(); -pub async fn install(id: String) -> Result<(), Box> { let base_path = get_beaches_path(); - let environment_path = get_path(id.clone()).await; + let environment_path = get_path(&id).await; let download_url = format!("https://github.com/the-sandbox-project/sandbox-templates/raw/master/{}", environment_path); let download_path = format!("{}{}", base_path, environment_path); let tar_name = environment_path.split('/').last().unwrap(); - cache::ensure_installed().await; let cache_path = get_cache_path(); let formatted_cache_path = format!("{}{}", cache_path, tar_name); - let tar_in_cache = Path::new(&formatted_cache_path).exists(); - if tar_in_cache { + if in_cache(&id).await { println!("{} found in {}! Installing from {}...", id.blue(), "Cache".bright_green(), "Cache".bright_green()); let language_path = Path::new(&download_path).parent().unwrap().to_str().unwrap(); From e056aa16e3ba94d3405ef723c19e4b58dfc3b79a Mon Sep 17 00:00:00 2001 From: WillKirkmanM Date: Wed, 3 May 2023 20:54:04 +0100 Subject: [PATCH 13/13] Ver(Cargo): 0.1.1 => 0.2.1 --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3d3e189..2edf008 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,13 +1,13 @@ [package] name = "sandbox" -version = "0.1.1" +version = "0.2.1" edition = "2021" authors = ["WillKirkmanM "] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -clap = { version = "4.2.4", features = ["derive"] } +clap = { version = "4.2.7", features = ["derive"] } colored = "2.0.0" flate2 = "1.0.26" indicatif = "0.17.3"