From fc0c3408f6006ae345131ddc3a0e01c77b9013b5 Mon Sep 17 00:00:00 2001 From: brokenbyte Date: Tue, 8 Feb 2022 21:58:00 -0700 Subject: [PATCH 1/8] fix(node): use right cfg options for node use --- src/commands/node.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/node.rs b/src/commands/node.rs index a19570e2..d436587b 100644 --- a/src/commands/node.rs +++ b/src/commands/node.rs @@ -160,10 +160,10 @@ pub struct NodeUse { #[async_trait] impl VoltCommand for NodeUse { async fn exec(self, config: VoltConfig) -> Result<()> { - #[cfg(target_os = "windows")] + #[cfg(target_family = "windows")] use_windows(self.version).await; - #[cfg(target_os = "unix")] + #[cfg(target_family = "unix")] { let node_path = get_node_path(&self.version); From 26a7f6a625e8ba51dd5d904b422bbf109c3680a4 Mon Sep 17 00:00:00 2001 From: brokenbyte Date: Thu, 10 Feb 2022 16:45:08 -0700 Subject: [PATCH 2/8] wip(node): basic progress indicators --- src/commands/node.rs | 55 +++++++++++++++++++++++++++++++++----------- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/src/commands/node.rs b/src/commands/node.rs index d436587b..5bfbc4be 100644 --- a/src/commands/node.rs +++ b/src/commands/node.rs @@ -24,13 +24,16 @@ use std::{ path::{Path, PathBuf}, process::Command, str, + time::Duration, }; use async_trait::async_trait; use base64::decode; use clap::Parser; use clap::{ArgMatches, Subcommand}; +use colored::Colorize; use futures::io; +use indicatif::{ProgressBar, ProgressStyle}; use miette::Result; use node_semver::{Range, Version}; use serde::{Deserialize, Deserializer}; @@ -249,6 +252,14 @@ impl VoltCommand for NodeInstall { for v in self.versions { let mut download_url = format!("{}/", mirror); + let bar = ProgressBar::new_spinner() + .with_style(ProgressStyle::default_spinner().template("{spinner:.cyan} {msg}")); + bar.set_message(format!( + "{:10} {}", + String::from("Installing"), + v.truecolor(125, 125, 125) + )); + bar.enable_steady_tick(10); let version: Option = if let Ok(ver) = v.parse() { if cfg!(all(unix, target_arch = "X86")) && ver >= Version::parse("10.0.0").unwrap() @@ -290,12 +301,20 @@ impl VoltCommand for NodeInstall { max_ver } else { - println!("Unable to download {} -- not a valid version!", v); + bar.finish_with_message(format!( + "{:10} {} ✗", + String::from("Invalid"), + v.to_string().truecolor(255, 000, 000) + )); continue; }; if version.is_none() { - println!("Unable to find version {}!", v); + bar.finish_with_message(format!( + "{:10} {} ✗", + String::from("Not found"), + v.to_string().truecolor(255, 000, 000) + )); continue; } @@ -312,9 +331,9 @@ impl VoltCommand for NodeInstall { ) }; - println!("\n------------\n{}\n------------\n", download_url); + //println!("\n------------\n{}\n------------\n", download_url); - println!("Got final URL '{}'", download_url); + //println!("Got final URL '{}'", download_url); let node_path = { let datadir = dirs::data_dir().unwrap().join("volt").join("node"); @@ -325,7 +344,12 @@ impl VoltCommand for NodeInstall { }; if node_path.join(version.to_string()).exists() { - println!("Node.js v{} is already installed, nothing to do!", version); + //println!("Node.js v{} is already installed, nothing to do!", version); + bar.finish_with_message(format!( + "{:10} {} ✓", + String::from("Present"), + version.to_string().truecolor(000, 255, 000) + )); continue; } @@ -334,8 +358,8 @@ impl VoltCommand for NodeInstall { // The name of the file we're downloading from the mirror let fname = download_url.split('/').last().unwrap().to_string(); - println!("Installing version {} from {} ", version, download_url); - println!("file to download: '{}'", fname); + //println!("Installing version {} from {} ", version, download_url); + //println!("file to download: '{}'", fname); let response = reqwest::get(&download_url).await.unwrap(); @@ -343,7 +367,7 @@ impl VoltCommand for NodeInstall { #[cfg(target_family = "windows")] { - println!("Installing node.exe"); + //println!("Installing node.exe"); std::fs::create_dir_all(&node_path).unwrap(); let mut dest = File::create(node_path.join(&fname)).unwrap(); dest.write_all(&content).unwrap(); @@ -354,9 +378,9 @@ impl VoltCommand for NodeInstall { // Path to write the decompressed tarball to let tarpath = &dir.path().join(&fname.strip_suffix(".xz").unwrap()); - println!("Unzipping..."); - - println!("Tar path: {:?}", tarpath); + //println!("Unzipping..."); + //println!("Tar path: {:?}", tarpath); + //println!("HELLO WORLD"); // Decompress the tarball let mut tarball = File::create(tarpath).unwrap(); @@ -370,7 +394,7 @@ impl VoltCommand for NodeInstall { // Have to reopen it for reading, File::create() opens for write only let tarball = File::open(&tarpath).unwrap(); - println!("Unpacking..."); + //println!("Unpacking..."); // Unpack the tarball let mut w = tar::Archive::new(tarball); @@ -394,8 +418,11 @@ impl VoltCommand for NodeInstall { // to just the version number std::fs::rename(from, to); } - - println!("Done!"); + bar.finish_with_message(format!( + "{:10} {} ✓", + String::from("Installed"), + version.to_string().truecolor(000, 255, 000) + )); } Ok(()) } From 00ac8d5b39bfdf34a7313f76e4af6855d843fcdc Mon Sep 17 00:00:00 2001 From: RamenN00dlez Date: Thu, 10 Feb 2022 18:16:05 -0700 Subject: [PATCH 3/8] fix: node install (windows) folder name = version --- src/commands/node.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/node.rs b/src/commands/node.rs index 5bfbc4be..b50d6c99 100644 --- a/src/commands/node.rs +++ b/src/commands/node.rs @@ -367,6 +367,7 @@ impl VoltCommand for NodeInstall { #[cfg(target_family = "windows")] { + let node_path = node_path.join(&version.to_string()); //println!("Installing node.exe"); std::fs::create_dir_all(&node_path).unwrap(); let mut dest = File::create(node_path.join(&fname)).unwrap(); From 800f62ddf5cd6ba02f05de9d2c88a03f92dc8b2d Mon Sep 17 00:00:00 2001 From: RamenN00dlez Date: Thu, 10 Feb 2022 20:08:25 -0700 Subject: [PATCH 4/8] feature: node list now functional (os independent) --- src/commands/node.rs | 95 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 73 insertions(+), 22 deletions(-) diff --git a/src/commands/node.rs b/src/commands/node.rs index b50d6c99..3f119244 100644 --- a/src/commands/node.rs +++ b/src/commands/node.rs @@ -40,7 +40,10 @@ use serde::{Deserialize, Deserializer}; use tempfile::tempdir; use tokio::fs; -use crate::cli::{VoltCommand, VoltConfig}; +use crate::{ + cli::{VoltCommand, VoltConfig}, + core::utils::extensions::PathExtensions, +}; const PLATFORM: Os = if cfg!(target_os = "windows") { Os::Windows @@ -142,8 +145,49 @@ impl VoltCommand for Node { NodeCommand::Use(x) => x.exec(config).await, NodeCommand::Install(x) => x.exec(config).await, NodeCommand::Remove(x) => x.exec(config).await, + NodeCommand::List(x) => x.exec(config).await, + } + } +} + +#[derive(Debug, Parser)] +pub struct NodeList {} + +fn sort_versions(a: &String, b: &String) -> std::cmp::Ordering { + let a: Vec = a.split(".").map(|term| term.parse().unwrap()).collect(); + let b: Vec = b.split(".").map(|term| term.parse().unwrap()).collect(); + for ab in a.iter().zip(b.iter()) { + let (ai, bi) = ab; + let c = bi.cmp(ai); + if c == std::cmp::Ordering::Equal { + continue; + } else { + return c; } } + return std::cmp::Ordering::Equal; +} + +#[async_trait] +impl VoltCommand for NodeList { + async fn exec(self, config: VoltConfig) -> Result<()> { + let node_path = dirs::data_dir().unwrap().join("volt").join("node"); + let mut versions: Vec = std::fs::read_dir(node_path) + .unwrap() + .map(|dir| match dir { + Ok(_) => dir.unwrap().path().file_name_as_string().unwrap(), + Err(_) => "ERROR".to_string(), + }) + .collect(); + + versions.sort_by(|a, b| sort_versions(a, b)); + println!("Installed versions:"); + for version in versions { + println!("\t{}", version.truecolor(250, 150, 100)); + } + + Ok(()) + } } #[derive(Debug, Subcommand)] @@ -151,6 +195,7 @@ pub enum NodeCommand { Use(NodeUse), Install(NodeInstall), Remove(NodeRemove), + List(NodeList), } /// Switch current node version @@ -447,12 +492,7 @@ pub struct NodeRemove { #[async_trait] impl VoltCommand for NodeRemove { async fn exec(self, config: VoltConfig) -> Result<()> { - let usedversion = { - let vfpath = dirs::data_dir().unwrap().join("volt").join("current"); - let vfpath = Path::new(&vfpath); - let version = std::fs::read_to_string(vfpath).unwrap(); - version - }; + let used_version = ""; //get_current_version(); for version in self.versions { let node_path = get_node_path(&version); @@ -469,16 +509,14 @@ impl VoltCommand for NodeRemove { ); } - if usedversion == version { + if used_version == version { if PLATFORM == Os::Windows { - let link_file = dirs::data_dir() + let used_file = dirs::data_dir() .unwrap() .join("volt") .join("bin") .join("node.exe"); - let link_file = Path::new(&link_file); - - std::fs::remove_file(link_file); + std::fs::remove_file(used_file); } } } @@ -486,15 +524,32 @@ impl VoltCommand for NodeRemove { Ok(()) } } +/* +async fn get_current_version() -> String { + let path = { + if PLATFORM == Os::Windows { + dirs::data_dir() + .unwrap() + .join("volt") + .join("bin") + .join("node.exe") + } else { + dirs::home_dir().unwrap().join(".local").join("bin") + } + }; + if path.exists() { + let meta = std::os::windows::fs::metadata(path) + .unwrap() + .file_attributes(); + } else { + return ""; + } +} +*/ #[cfg(target_os = "windows")] async fn use_windows(version: String) { - let node_path = dirs::data_dir() - .unwrap() - .join("volt") - .join("node") - .join(&version) - .join("node.exe"); + let node_path = get_node_path(&version).join("node.exe"); let path = Path::new(&node_path); if path.exists() { @@ -529,10 +584,6 @@ async fn use_windows(version: String) { } } - let vfpath = dirs::data_dir().unwrap().join("volt").join("current"); - let vfpath = Path::new(&vfpath); - let vfile = std::fs::write(vfpath, version); - let path = env::var("PATH").unwrap(); if !path.contains(&link_dir) { let command = format!("[Environment]::SetEnvironmentVariable('Path', [Environment]::GetEnvironmentVariable('Path', 'User') + '{}', 'User')", &link_dir); From f14c02442585031a205387ac899de01804d93fce Mon Sep 17 00:00:00 2001 From: RamenN00dlez Date: Fri, 11 Feb 2022 17:07:14 -0700 Subject: [PATCH 5/8] feature: node list functional --- src/commands/node.rs | 55 ++++++++++++++++++++++++-------------------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/src/commands/node.rs b/src/commands/node.rs index 3f119244..ec4bddad 100644 --- a/src/commands/node.rs +++ b/src/commands/node.rs @@ -181,6 +181,10 @@ impl VoltCommand for NodeList { .collect(); versions.sort_by(|a, b| sort_versions(a, b)); + println!( + "Used version:\n\t{}", + get_current_version().await.truecolor(250, 150, 100) + ); println!("Installed versions:"); for version in versions { println!("\t{}", version.truecolor(250, 150, 100)); @@ -492,7 +496,7 @@ pub struct NodeRemove { #[async_trait] impl VoltCommand for NodeRemove { async fn exec(self, config: VoltConfig) -> Result<()> { - let used_version = ""; //get_current_version(); + let used_version = get_current_version().await; for version in self.versions { let node_path = get_node_path(&version); @@ -509,44 +513,45 @@ impl VoltCommand for NodeRemove { ); } - if used_version == version { - if PLATFORM == Os::Windows { - let used_file = dirs::data_dir() - .unwrap() - .join("volt") - .join("bin") - .join("node.exe"); - std::fs::remove_file(used_file); - } + if used_version == version && PLATFORM == Os::Windows { + let used_file = dirs::data_dir() + .unwrap() + .join("volt") + .join("bin") + .join("node.exe"); + std::fs::remove_file(used_file); } } Ok(()) } } -/* + async fn get_current_version() -> String { - let path = { + let command = format!("node -v"); + let output = { if PLATFORM == Os::Windows { - dirs::data_dir() - .unwrap() - .join("volt") - .join("bin") - .join("node.exe") + Command::new("Powershell") + .args(&["-Command", &command]) + .output() } else { - dirs::home_dir().unwrap().join(".local").join("bin") + Command::new("sh").args(&["-c", &command]).output() } }; - if path.exists() { - let meta = std::os::windows::fs::metadata(path) - .unwrap() - .file_attributes(); - } else { - return ""; + let mut v = match output { + Ok(_) => String::from_utf8(output.unwrap().stdout).unwrap(), + Err(_) => String::from("Hidden\r\n"), + }; + + if v == "" { + v = String::from("vNone\r\n"); } + + //trim leading 'v' and ending '/r/n' to leave only version number as a String + return v[1..v.len() - 2].to_string(); } -*/ + #[cfg(target_os = "windows")] async fn use_windows(version: String) { let node_path = get_node_path(&version).join("node.exe"); From b39818dc098537044dbb9ed168761bb9d9782871 Mon Sep 17 00:00:00 2001 From: RamenN00dlez Date: Fri, 11 Feb 2022 22:22:31 -0700 Subject: [PATCH 6/8] test: node list works on linux --- src/commands/node.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/commands/node.rs b/src/commands/node.rs index ec4bddad..18e62b48 100644 --- a/src/commands/node.rs +++ b/src/commands/node.rs @@ -541,15 +541,23 @@ async fn get_current_version() -> String { let mut v = match output { Ok(_) => String::from_utf8(output.unwrap().stdout).unwrap(), - Err(_) => String::from("Hidden\r\n"), + Err(_) => String::from("vHidden (check file permissions)"), }; - + for ch in v.chars() { + println!("t:{}", ch as u32); + } if v == "" { - v = String::from("vNone\r\n"); + v = String::from("vNone"); } - - //trim leading 'v' and ending '/r/n' to leave only version number as a String - return v[1..v.len() - 2].to_string(); + //trim trailing \r?\n (\r is windows only so this is an if statement) + if v.ends_with('\n') { + v.pop(); + if v.ends_with('\r') { + v.pop(); + } + } + //trim leading 'v' + return v[1..v.len()].to_string(); } #[cfg(target_os = "windows")] From b8bddcff2165918147da508bebb97cfc35a8892f Mon Sep 17 00:00:00 2001 From: RamenN00dlez Date: Fri, 11 Feb 2022 22:27:14 -0700 Subject: [PATCH 7/8] feature: node list functional on linux --- src/commands/node.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/commands/node.rs b/src/commands/node.rs index 18e62b48..6cc57790 100644 --- a/src/commands/node.rs +++ b/src/commands/node.rs @@ -178,6 +178,7 @@ impl VoltCommand for NodeList { Ok(_) => dir.unwrap().path().file_name_as_string().unwrap(), Err(_) => "ERROR".to_string(), }) + .filter(|x| x != "current") .collect(); versions.sort_by(|a, b| sort_versions(a, b)); @@ -543,12 +544,11 @@ async fn get_current_version() -> String { Ok(_) => String::from_utf8(output.unwrap().stdout).unwrap(), Err(_) => String::from("vHidden (check file permissions)"), }; - for ch in v.chars() { - println!("t:{}", ch as u32); - } + if v == "" { v = String::from("vNone"); } + //trim trailing \r?\n (\r is windows only so this is an if statement) if v.ends_with('\n') { v.pop(); @@ -556,6 +556,7 @@ async fn get_current_version() -> String { v.pop(); } } + //trim leading 'v' return v[1..v.len()].to_string(); } From 1a5cec79b4492d7b38fffab681b1d6f3d5d967ff Mon Sep 17 00:00:00 2001 From: RamenN00dlez Date: Fri, 11 Feb 2022 22:29:30 -0700 Subject: [PATCH 8/8] merge voltpkg/volt to RamenN00dlez/volt --- Cargo.toml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 89e580ab..aa072b5c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ rand = "0.8.4" regex = "1.5.4" reqwest = { version = "0.11.4", features = [ "json", - "rustls-tls", + "rustls-tls", ], default-features = false } node-semver = "2.0.0" cacache = "9.0.0" @@ -68,15 +68,15 @@ rust-lzma = "0.5.1" [target.'cfg(windows)'.dependencies] winapi = { version = "0.3.9", features = [ "errhandlingapi", - "fileapi", - "guiddef", - "handleapi", - "ioapiset", - "processthreadsapi", - "securitybaseapi", - "winbase", - "winioctl", - "winnt", + "fileapi", + "guiddef", + "handleapi", + "ioapiset", + "processthreadsapi", + "securitybaseapi", + "winbase", + "winioctl", + "winnt", ] } junction = "0.2.0" scopeguard = "1.1.0"