From ad0d3d3ba3d3a488dcd09816cda57dfa66ee1547 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 22 Dec 2022 23:04:11 +0100 Subject: [PATCH 1/4] refactor the file name function --- Cargo.lock | 138 ++++++++++++++++++++++++++++++++++++++++-- Cargo.toml | 1 + src/main.rs | 4 +- src/node_version.rs | 63 +++++++++++-------- tests/install_test.rs | 18 +++--- 5 files changed, 185 insertions(+), 39 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1ef79e..dd18815 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -416,6 +416,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "generic-array" version = "0.14.5" @@ -675,6 +681,75 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" +[[package]] +name = "num" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" +dependencies = [ + "num-integer", + "num-traits", + "rand 0.4.6", + "rustc-serialize", +] + +[[package]] +name = "num-complex" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b288631d7878aaf59442cffd36910ea604ecd7745c36054328595114001c9656" +dependencies = [ + "num-traits", + "rustc-serialize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee314c74bd753fc86b4780aa9475da469155f3848473a261d2d18e35245a784e" +dependencies = [ + "num-bigint", + "num-integer", + "num-traits", + "rustc-serialize", +] + [[package]] name = "num-traits" version = "0.2.14" @@ -709,6 +784,7 @@ dependencies = [ "predicates", "serde", "serde_json", + "spectral", "tar", "ureq", "zip", @@ -739,7 +815,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.3", "subtle", ] @@ -845,6 +921,19 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.4" @@ -853,7 +942,7 @@ checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.3", "rand_hc", ] @@ -864,9 +953,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.3", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.3" @@ -882,7 +986,16 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core", + "rand_core 0.6.3", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", ] [[package]] @@ -951,6 +1064,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-serialize" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" + [[package]] name = "rustix" version = "0.36.5" @@ -1055,6 +1174,15 @@ dependencies = [ "digest", ] +[[package]] +name = "spectral" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3c15181f4b14e52eeaac3efaeec4d2764716ce9c86da0c934c3e318649c5ba" +dependencies = [ + "num", +] + [[package]] name = "spin" version = "0.5.2" @@ -1103,7 +1231,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ "cfg-if", "libc", - "rand", + "rand 0.8.4", "redox_syscall", "remove_dir_all", "winapi", diff --git a/Cargo.toml b/Cargo.toml index 2b40c96..2487672 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ itertools = "0.10.5" node-semver = "2.1.0" serde = { version = "1.0.151", features = ["derive"] } serde_json = "1.0.91" +spectral = "0.6.0" ureq = { version = "2.5.0", features = ["json"] } [target.'cfg(unix)'.dependencies] diff --git a/src/main.rs b/src/main.rs index 1d2382c..b3ed40f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,9 @@ use std::{ path::{Path, PathBuf}, }; -use anyhow::{bail, Result}; +#[cfg(windows)] +use anyhow::bail; +use anyhow::Result; use clap::{Parser, ValueHint}; use crate::subcommand::{ diff --git a/src/node_version.rs b/src/node_version.rs index 98a1e21..e7c0d39 100644 --- a/src/node_version.rs +++ b/src/node_version.rs @@ -12,6 +12,27 @@ use serde::Deserialize; use crate::{utils, Config}; +#[cfg(target_os = "windows")] +const PLATFORM: &str = "win"; +#[cfg(target_os = "macos")] +const PLATFORM: &str = "darwin"; +#[cfg(target_os = "linux")] +const PLATFORM: &str = "linux"; + +#[cfg(target_os = "windows")] +const EXT: &str = ".zip"; +#[cfg(target_os = "macos")] +const EXT: &str = ".tar.gz"; +#[cfg(target_os = "linux")] +const EXT: &str = ".tar.gz"; + +#[cfg(target_arch = "x86_64")] +const ARCH: &str = "x64"; +#[cfg(target_arch = "x86")] +const ARCH: &str = "x86"; +#[cfg(target_arch = "aarch64")] +const ARCH: &str = "arm64"; + pub trait NodeVersion { fn version(&self) -> &Version; } @@ -104,30 +125,8 @@ impl OnlineNodeVersion { format!("https://nodejs.org/dist/v{}/{}", self.version, file_name) } - #[cfg(target_os = "windows")] - fn file(&self) -> String { - format!( - "node-v{version}-win-{arch}.zip", - version = self.version(), - arch = if cfg!(target_arch = "x86") { - "x86" - } else { - "x64" - }, - ) - } - - #[cfg(target_os = "macos")] fn file(&self) -> String { - format!( - "node-v{version}-darwin-x64.tar.gz", - version = self.version() - ) - } - - #[cfg(target_os = "linux")] - fn file(&self) -> String { - format!("node-v{version}-linux-x64.tar.gz", version = self.version()) + format!("node-v{}-{PLATFORM}-{ARCH}{EXT}", self.version()) } } @@ -276,8 +275,24 @@ mod tests { use anyhow::Result; use node_semver::Version; + use spectral::prelude::*; + use crate::node_version::OnlineNodeVersion; + #[test] + fn formats_file_name_correctly() -> Result<()> { + let version = OnlineNodeVersion { + version: Version::from((18, 12, 1)), + release_date: "".to_string(), + files: vec![], + }; + + assert_that!(version.file()) + .is_equal_to("node-v18.12.1-darwin-arm64.tar.gz".to_string()); + + Ok(()) + } + #[test] fn can_parse_version_data() -> Result<()> { let expected = OnlineNodeVersion { @@ -350,7 +365,7 @@ mod tests { let result: OnlineNodeVersion = serde_json::from_str(json_str) .expect("Failed to parse version data from nodejs.org"); - assert_eq!(expected, result); + assert_that!(expected).is_equal_to(result); Ok(()) } diff --git a/tests/install_test.rs b/tests/install_test.rs index 2362e70..3097009 100644 --- a/tests/install_test.rs +++ b/tests/install_test.rs @@ -8,7 +8,7 @@ mod install { fn can_install_version_matching_range() -> Result<()> { let (temp_dir, mut cmd) = utils::setup_integration_test()?; - let version_range = ">=12, <12.8"; + let version_range = ">=14, <14.21"; let result = cmd .arg("install") .arg("--force") @@ -17,10 +17,10 @@ mod install { utils::assert_outputs_contain( &result, - "Downloading from https://nodejs.org/dist/v12.7.0/node-v12.7.0-", + "Downloading from https://nodejs.org/dist/v14.20.1/node-v14.20.1-", "", )?; - utils::assert_version_installed(&temp_dir, "12.7.0", true)?; + utils::assert_version_installed(&temp_dir, "14.20.1", true)?; temp_dir.close().map_err(anyhow::Error::from) } @@ -29,12 +29,12 @@ mod install { fn can_install_version_matching_exact_version() -> Result<()> { let (temp_dir, mut cmd) = utils::setup_integration_test()?; - let version_str = "12.18.3"; + let version_str = "14.21.2"; let result = cmd.arg("install").arg("--force").arg(version_str).assert(); utils::assert_outputs_contain( &result, - "Downloading from https://nodejs.org/dist/v12.18.3/node-v12.18.3-", + "Downloading from https://nodejs.org/dist/v14.21.2/node-v14.21.2-", "", )?; utils::assert_version_installed(&temp_dir, version_str, true)?; @@ -46,12 +46,12 @@ mod install { fn stops_when_installing_installed_version() -> Result<()> { let (temp_dir, mut cmd) = utils::setup_integration_test()?; - let version_str = "12.18.3"; + let version_str = "14.21.2"; utils::install_mock_version(&temp_dir, version_str)?; let result = cmd.arg("install").arg(version_str).assert(); - utils::assert_outputs_contain(&result, "12.18.3 is already installed - skipping...", "")?; + utils::assert_outputs_contain(&result, "14.21.2 is already installed - skipping...", "")?; temp_dir.close().map_err(anyhow::Error::from) } @@ -60,12 +60,12 @@ mod install { fn force_forces_install_of_installed_version() -> Result<()> { let (temp_dir, mut cmd) = utils::setup_integration_test()?; - let version_str = "12.18.3"; + let version_str = "14.21.2"; let result = cmd.arg("install").arg("--force").arg(version_str).assert(); utils::assert_outputs_contain( &result, - "Downloading from https://nodejs.org/dist/v12.18.3/node-v12.18.3-", + "Downloading from https://nodejs.org/dist/v14.21.2/node-v14.21.2-", "", )?; utils::assert_outputs_contain(&result, "Extracting...", "")?; From 151143f681cb12df14051f54f29b0ccc2f7bf569 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 22 Dec 2022 23:05:35 +0100 Subject: [PATCH 2/4] clippy fix --- src/archives.rs | 8 ++++---- src/node_version.rs | 5 ++--- src/subcommand/install.rs | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/archives.rs b/src/archives.rs index b1e0aca..3954e11 100644 --- a/src/archives.rs +++ b/src/archives.rs @@ -63,7 +63,7 @@ pub fn extract_archive(bytes: Vec, path: &Path) -> Result<()> { let mut archive = Archive::new(tar); let version_dir_path = path.to_owned(); - create_dir_all(version_dir_path.to_owned()).expect("fuck"); + create_dir_all(&version_dir_path).expect("fuck"); println!("Extracting..."); @@ -72,11 +72,11 @@ pub fn extract_archive(bytes: Vec, path: &Path) -> Result<()> { .map_err(anyhow::Error::from)? .filter_map(|e| e.ok()) .map(|mut entry| -> Result { - let file_path = entry.path()?.to_owned(); + let file_path = entry.path()?; let file_path = file_path.to_str().unwrap(); let new_path: PathBuf = if let Some(index) = file_path.find('/') { - path.to_owned().join(file_path[index + 1..].to_owned()) + path.to_owned().join(&file_path[index + 1..]) } else { // This happens if it's the root index, the base folder path.to_owned() @@ -105,7 +105,7 @@ pub fn extract_archive(bytes: Vec, path: &Path) -> Result<()> { )); } - println!("Extracted to {:?}", version_dir_path); + println!("Extracted to {version_dir_path:?}"); Ok(()) } diff --git a/src/node_version.rs b/src/node_version.rs index e7c0d39..7f1a48a 100644 --- a/src/node_version.rs +++ b/src/node_version.rs @@ -1,5 +1,4 @@ use std::{ - borrow::Borrow, cmp::Ordering, collections::HashMap, fs::{read_link, remove_dir_all}, @@ -89,7 +88,7 @@ fn parse_version_str(version_str: &str) -> Result { let clean_version = if version_str.starts_with('v') { version_str.get(1..).unwrap() } else { - version_str.borrow() + version_str }; Version::parse(clean_version).context(version_str.to_owned()) @@ -252,7 +251,7 @@ impl InstalledNodeVersion { pub fn find_matching(config: &Config, range: &Range) -> Option { Self::list(config) .iter() - .find(|inv| range.satisfies(inv.version().borrow())) + .find(|inv| range.satisfies(inv.version())) .map(|inv| inv.to_owned()) } } diff --git a/src/subcommand/install.rs b/src/subcommand/install.rs index 6597a77..f7aab70 100644 --- a/src/subcommand/install.rs +++ b/src/subcommand/install.rs @@ -1,4 +1,4 @@ -use std::{borrow::Borrow, path::Path, time::Duration}; +use std::{path::Path, time::Duration}; use anyhow::{Context, Result}; use clap::Parser; @@ -59,7 +59,7 @@ impl Action for InstallCommand { } let install_path = version_to_install.install_path(config); - download_and_extract_to(version_to_install.borrow(), &install_path)?; + download_and_extract_to(version_to_install, &install_path)?; if config.force || (options.switch From 613d0b3f4eae78fe193fdf4216af611447bd6ba8 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 22 Dec 2022 23:38:31 +0100 Subject: [PATCH 3/4] download arm64 and fall back to x64 --- src/node_version.rs | 49 +++++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/src/node_version.rs b/src/node_version.rs index 7f1a48a..e836f70 100644 --- a/src/node_version.rs +++ b/src/node_version.rs @@ -32,6 +32,8 @@ const ARCH: &str = "x86"; #[cfg(target_arch = "aarch64")] const ARCH: &str = "arm64"; +const X64: &str = "x64"; + pub trait NodeVersion { fn version(&self) -> &Version; } @@ -119,13 +121,40 @@ impl OnlineNodeVersion { } pub fn download_url(&self) -> String { - let file_name = self.file(); + let file_name: String; + + #[cfg(target_os = "macos")] + { + let has_arm = self.has_arm(); + + file_name = self.file(!has_arm); + } + + #[cfg(not(target_os = "macos"))] + { + file_name = self.file(false); + } format!("https://nodejs.org/dist/v{}/{}", self.version, file_name) } - fn file(&self) -> String { - format!("node-v{}-{PLATFORM}-{ARCH}{EXT}", self.version()) + fn file(&self, force_x64: bool) -> String { + format!( + "node-v{VERSION}-{PLATFORM}-{ARCH}{EXT}", + VERSION = self.version(), + ARCH = if force_x64 { X64 } else { ARCH }, + ) + } + + #[cfg(target_os = "macos")] + fn has_arm(&self) -> bool { + for file in self.files.iter() { + if file.contains("osx") && file.contains("arm64") { + return true; + } + } + + false } } @@ -278,20 +307,6 @@ mod tests { use crate::node_version::OnlineNodeVersion; - #[test] - fn formats_file_name_correctly() -> Result<()> { - let version = OnlineNodeVersion { - version: Version::from((18, 12, 1)), - release_date: "".to_string(), - files: vec![], - }; - - assert_that!(version.file()) - .is_equal_to("node-v18.12.1-darwin-arm64.tar.gz".to_string()); - - Ok(()) - } - #[test] fn can_parse_version_data() -> Result<()> { let expected = OnlineNodeVersion { From 367a8cd8b6278269e07a7b93b7edc6d1e3cc6252 Mon Sep 17 00:00:00 2001 From: Adam Date: Thu, 22 Dec 2022 23:42:29 +0100 Subject: [PATCH 4/4] fix the corepack executable path --- src/subcommand/install.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/subcommand/install.rs b/src/subcommand/install.rs index f7aab70..105b0f2 100644 --- a/src/subcommand/install.rs +++ b/src/subcommand/install.rs @@ -78,7 +78,9 @@ impl Action for InstallCommand { if options.enable_corepack { if let Err(e) = std::process::Command::new( - install_path.join(format!("corepack{}", utils::exec_ext())), + install_path + .join("bin") + .join(format!("corepack{}", utils::exec_ext())), ) .arg("enable") .output()