From 934ec4f6b2aafe9d0d5eb5dcb1a863237c019018 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Wed, 25 Oct 2023 23:49:03 +0800 Subject: [PATCH 01/19] feat: add remote version sorting and filtering --- .changeset/fifty-emus-type.md | 5 ++++ src/commands/install.rs | 34 +++++++++++++++++-------- src/commands/ls_remote.rs | 47 ++++++++++++++++++++++++++++++++--- src/remote_node_index.rs | 25 ++++++++++++++++--- 4 files changed, 93 insertions(+), 18 deletions(-) create mode 100644 .changeset/fifty-emus-type.md diff --git a/.changeset/fifty-emus-type.md b/.changeset/fifty-emus-type.md new file mode 100644 index 000000000..406a88ae0 --- /dev/null +++ b/.changeset/fifty-emus-type.md @@ -0,0 +1,5 @@ +--- +"fnm": minor +--- + +feat: add remote version sorting and filtering diff --git a/src/commands/install.rs b/src/commands/install.rs index 2c553844b..77840eb33 100644 --- a/src/commands/install.rs +++ b/src/commands/install.rs @@ -67,8 +67,11 @@ impl Command for Install { return Err(Error::UninstallableVersion { version: v }); } UserVersion::Full(Version::Lts(lts_type)) => { - let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror) - .map_err(|source| Error::CantListRemoteVersions { source })?; + let available_versions: Vec<_> = remote_node_index::list( + &config.node_dist_mirror, + &remote_node_index::SortingMethod::Ascending, + ) + .map_err(|source| Error::CantListRemoteVersions { source })?; let picked_version = lts_type .pick_latest(&available_versions) .ok_or_else(|| Error::CantFindRelevantLts { @@ -84,8 +87,11 @@ impl Command for Install { picked_version } UserVersion::Full(Version::Latest) => { - let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror) - .map_err(|source| Error::CantListRemoteVersions { source })?; + let available_versions: Vec<_> = remote_node_index::list( + &config.node_dist_mirror, + &remote_node_index::SortingMethod::Ascending, + ) + .map_err(|source| Error::CantListRemoteVersions { source })?; let picked_version = available_versions .last() .ok_or(Error::CantFindLatest)? @@ -99,11 +105,14 @@ impl Command for Install { picked_version } current_version => { - let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror) - .map_err(|source| Error::CantListRemoteVersions { source })? - .drain(..) - .map(|x| x.version) - .collect(); + let available_versions: Vec<_> = remote_node_index::list( + &config.node_dist_mirror, + &remote_node_index::SortingMethod::Ascending, + ) + .map_err(|source| Error::CantListRemoteVersions { source })? + .drain(..) + .map(|x| x.version) + .collect(); current_version .to_version(&available_versions, config) @@ -254,8 +263,11 @@ mod tests { .apply(&config) .expect("Can't install"); - let available_versions: Vec<_> = - remote_node_index::list(&config.node_dist_mirror).expect("Can't get node version list"); + let available_versions: Vec<_> = remote_node_index::list( + &config.node_dist_mirror, + &remote_node_index::SortingMethod::Ascending, + ) + .expect("Can't get node version list"); let latest_version = available_versions.last().unwrap().version.clone(); assert!(config.installations_dir().exists()); diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index 015b3ac5f..6cc03e9bd 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -1,24 +1,63 @@ use crate::config::FnmConfig; use crate::remote_node_index; +use colored::Colorize; use thiserror::Error; #[derive(clap::Parser, Debug)] -pub struct LsRemote {} +pub struct LsRemote { + /// Filter for version prefixes + filter: Option, + + // Version sorting order + #[arg(long, default_value = "asc")] + sort: remote_node_index::SortingMethod, +} impl super::command::Command for LsRemote { type Error = Error; fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> { - let all_versions = remote_node_index::list(&config.node_dist_mirror)?; + let filter = self + .filter + .and_then(|f| Some(f.strip_prefix('v').unwrap_or(&f).to_owned())); - for version in all_versions { + let mut all_versions = remote_node_index::list(&config.node_dist_mirror, &self.sort)?; + + if let Some(filter) = &filter { + all_versions = all_versions + .into_iter() + .filter(|v| { + v.version + .v_str() + .strip_prefix('v') + .and_then(|rv| Some(rv.starts_with(filter))) + .unwrap_or(false) + }) + .collect(); + } + + for version in &all_versions { print!("{}", version.version); if let Some(lts) = &version.lts { - print!(" ({lts})"); + print!("{}", format!(" ({lts})").cyan()); } println!(); } + if all_versions.is_empty() { + eprintln!( + "{}", + format!( + "No versions were found{}!", + match filter { + Some(filter) => format!(" with prefix {filter}"), + None => "".to_owned(), + } + ) + .red() + ); + } + Ok(()) } } diff --git a/src/remote_node_index.rs b/src/remote_node_index.rs index 4c9f3bdab..ac5974f05 100644 --- a/src/remote_node_index.rs +++ b/src/remote_node_index.rs @@ -66,16 +66,35 @@ pub struct IndexedNodeVersion { pub files: Vec, } +#[derive(clap::ValueEnum, Clone, Debug, PartialEq)] +pub enum SortingMethod { + #[clap(name = "desc")] + /// Sort versions in descending order (latest to earliest) + Descending, + #[clap(name = "asc")] + /// Sort versions in ascending order (earliest to latest) + Ascending, +} + /// Prints /// /// ```rust /// use crate::remote_node_index::list; /// ``` -pub fn list(base_url: &Url) -> Result, crate::http::Error> { +pub fn list( + base_url: &Url, + sort: &SortingMethod, +) -> Result, crate::http::Error> { let index_json_url = format!("{base_url}/index.json"); let resp = crate::http::get(&index_json_url)?; let mut value: Vec = resp.json()?; - value.sort_by(|a, b| a.version.cmp(&b.version)); + + if *sort == SortingMethod::Ascending { + value.sort_by(|a, b| a.version.cmp(&b.version)); + } else { + value.sort_by(|a, b| b.version.cmp(&a.version)); + } + Ok(value) } @@ -88,7 +107,7 @@ mod tests { fn test_list() { let base_url = Url::parse("https://nodejs.org/dist").unwrap(); let expected_version = Version::parse("12.0.0").unwrap(); - let mut versions = list(&base_url).expect("Can't get HTTP data"); + let mut versions = list(&base_url, &SortingMethod::Ascending).expect("Can't get HTTP data"); assert_eq!( versions .drain(..) From 1e2f09a61a3dc7614f70139cc7e375571f0061df Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Sat, 11 Nov 2023 18:38:23 +0800 Subject: [PATCH 02/19] use `UserVersion` for filtering --- src/commands/ls_remote.rs | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index 6cc03e9bd..e8dd70fb3 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -1,12 +1,14 @@ use crate::config::FnmConfig; use crate::remote_node_index; +use crate::user_version::UserVersion; + use colored::Colorize; use thiserror::Error; #[derive(clap::Parser, Debug)] pub struct LsRemote { - /// Filter for version prefixes - filter: Option, + /// Filter for versions + filter: Option, // Version sorting order #[arg(long, default_value = "asc")] @@ -17,22 +19,12 @@ impl super::command::Command for LsRemote { type Error = Error; fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> { - let filter = self - .filter - .and_then(|f| Some(f.strip_prefix('v').unwrap_or(&f).to_owned())); - let mut all_versions = remote_node_index::list(&config.node_dist_mirror, &self.sort)?; - if let Some(filter) = &filter { + if let Some(filter) = &self.filter { all_versions = all_versions .into_iter() - .filter(|v| { - v.version - .v_str() - .strip_prefix('v') - .and_then(|rv| Some(rv.starts_with(filter))) - .unwrap_or(false) - }) + .filter(|v| filter.matches(&v.version, config)) .collect(); } @@ -45,17 +37,7 @@ impl super::command::Command for LsRemote { } if all_versions.is_empty() { - eprintln!( - "{}", - format!( - "No versions were found{}!", - match filter { - Some(filter) => format!(" with prefix {filter}"), - None => "".to_owned(), - } - ) - .red() - ); + eprintln!("{}", "No versions were found!".red()); } Ok(()) From 38a07808f1b2ff1eb7ba86fdeb7dff0188cebfbd Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Sat, 11 Nov 2023 18:53:19 +0800 Subject: [PATCH 03/19] add additional lts filter --- src/commands/ls_remote.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index e8dd70fb3..d120d7af9 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -10,6 +10,10 @@ pub struct LsRemote { /// Filter for versions filter: Option, + /// Only show latest LTS versions + #[arg(long)] + lts: Option>, + // Version sorting order #[arg(long, default_value = "asc")] sort: remote_node_index::SortingMethod, @@ -21,6 +25,19 @@ impl super::command::Command for LsRemote { fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> { let mut all_versions = remote_node_index::list(&config.node_dist_mirror, &self.sort)?; + if let Some(lts) = &self.lts { + all_versions = all_versions + .into_iter() + .filter(|v| match lts { + None => v.lts.is_some(), + Some(lts) => v + .lts + .as_ref() + .is_some_and(|this_lts| this_lts.eq_ignore_ascii_case(lts)), + }) + .collect(); + } + if let Some(filter) = &self.filter { all_versions = all_versions .into_iter() From 3abd2842f5cb84517bfdcf5a3efcd7653a2501d3 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Sat, 11 Nov 2023 19:06:10 +0800 Subject: [PATCH 04/19] refactor: use `Vec::retain` instead of filtering and collecting --- src/commands/ls_remote.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index d120d7af9..fe5d276f5 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -26,23 +26,17 @@ impl super::command::Command for LsRemote { let mut all_versions = remote_node_index::list(&config.node_dist_mirror, &self.sort)?; if let Some(lts) = &self.lts { - all_versions = all_versions - .into_iter() - .filter(|v| match lts { - None => v.lts.is_some(), - Some(lts) => v - .lts - .as_ref() - .is_some_and(|this_lts| this_lts.eq_ignore_ascii_case(lts)), - }) - .collect(); + all_versions.retain(|v| match lts { + None => v.lts.is_some(), + Some(lts) => v + .lts + .as_ref() + .is_some_and(|this_lts| this_lts.eq_ignore_ascii_case(lts)), + }); } if let Some(filter) = &self.filter { - all_versions = all_versions - .into_iter() - .filter(|v| filter.matches(&v.version, config)) - .collect(); + all_versions.retain(|v| filter.matches(&v.version, config)); } for version in &all_versions { From c82e79e0bf88f612314d691a270f2e781044f8a2 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:25:48 +0800 Subject: [PATCH 05/19] fix docstring for sort option --- src/commands/ls_remote.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index fe5d276f5..c4ff7055e 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -14,7 +14,7 @@ pub struct LsRemote { #[arg(long)] lts: Option>, - // Version sorting order + /// Version sorting order #[arg(long, default_value = "asc")] sort: remote_node_index::SortingMethod, } From 5079ea8b804140e5333bf173a7526c78e4112895 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:26:27 +0800 Subject: [PATCH 06/19] change docstring for filter argument --- src/commands/ls_remote.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index c4ff7055e..4fb67824a 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -7,7 +7,7 @@ use thiserror::Error; #[derive(clap::Parser, Debug)] pub struct LsRemote { - /// Filter for versions + /// Filter with SemVer filter: Option, /// Only show latest LTS versions From d29c77be97986cbe561400c7c38448193f828927 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:29:06 +0800 Subject: [PATCH 07/19] refactor vec filtering Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com> --- src/commands/ls_remote.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index 4fb67824a..b7270fe63 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -26,13 +26,14 @@ impl super::command::Command for LsRemote { let mut all_versions = remote_node_index::list(&config.node_dist_mirror, &self.sort)?; if let Some(lts) = &self.lts { - all_versions.retain(|v| match lts { - None => v.lts.is_some(), - Some(lts) => v - .lts - .as_ref() - .is_some_and(|this_lts| this_lts.eq_ignore_ascii_case(lts)), - }); + match lts { + Some(codename) => all_versions.retain(|v| { + v.lts + .as_ref() + .is_some_and(|v_lts| v_lts.eq_ignore_ascii_case(codename)) + }), + None => all_versions.retain(|v| v.lts.is_some()), + }; } if let Some(filter) = &self.filter { From 84523ef4305b2d3cadb6e613939462a21f9f6f38 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:31:46 +0800 Subject: [PATCH 08/19] refactor to use `sort_by_key` and `reverse` Co-authored-by: Brennan Kinney <5098581+polarathene@users.noreply.github.com> --- src/remote_node_index.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/remote_node_index.rs b/src/remote_node_index.rs index ac5974f05..6eb325918 100644 --- a/src/remote_node_index.rs +++ b/src/remote_node_index.rs @@ -89,10 +89,9 @@ pub fn list( let resp = crate::http::get(&index_json_url)?; let mut value: Vec = resp.json()?; - if *sort == SortingMethod::Ascending { - value.sort_by(|a, b| a.version.cmp(&b.version)); - } else { - value.sort_by(|a, b| b.version.cmp(&a.version)); + value.sort_by_key(|v| v.version.clone()); + if let SortingMethod::Descending = sort { + value.reverse(); } Ok(value) From 9d8f80916a300a846dfd6bb8ad10d402a96ba3f3 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:38:14 +0800 Subject: [PATCH 09/19] add latest flag --- src/commands/ls_remote.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index b7270fe63..51ef3c084 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -17,6 +17,10 @@ pub struct LsRemote { /// Version sorting order #[arg(long, default_value = "asc")] sort: remote_node_index::SortingMethod, + + /// Only show the latest matching version + #[arg(long)] + latest: bool, } impl super::command::Command for LsRemote { @@ -40,6 +44,15 @@ impl super::command::Command for LsRemote { all_versions.retain(|v| filter.matches(&v.version, config)); } + if all_versions.is_empty() { + eprintln!("{}", "No versions were found!".red()); + return Ok(()); + } + + if self.latest { + all_versions = vec![all_versions.into_iter().last().unwrap()]; + } + for version in &all_versions { print!("{}", version.version); if let Some(lts) = &version.lts { @@ -48,10 +61,6 @@ impl super::command::Command for LsRemote { println!(); } - if all_versions.is_empty() { - eprintln!("{}", "No versions were found!".red()); - } - Ok(()) } } From cb179dc26629e7550d97517636110ca54c573f6f Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:38:33 +0800 Subject: [PATCH 10/19] make filter an option as well --- src/commands/ls_remote.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index 51ef3c084..6690910a3 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -8,6 +8,7 @@ use thiserror::Error; #[derive(clap::Parser, Debug)] pub struct LsRemote { /// Filter with SemVer + #[arg(long)] filter: Option, /// Only show latest LTS versions From 86191bae3f6173deccf00aa02e5e8654b1206b9a Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:44:00 +0800 Subject: [PATCH 11/19] move sort into command as it is presentational --- src/commands/install.rs | 34 +++++++++++----------------------- src/commands/ls_remote.rs | 19 +++++++++++++++++-- src/remote_node_index.rs | 24 +++--------------------- 3 files changed, 31 insertions(+), 46 deletions(-) diff --git a/src/commands/install.rs b/src/commands/install.rs index 77840eb33..2c553844b 100644 --- a/src/commands/install.rs +++ b/src/commands/install.rs @@ -67,11 +67,8 @@ impl Command for Install { return Err(Error::UninstallableVersion { version: v }); } UserVersion::Full(Version::Lts(lts_type)) => { - let available_versions: Vec<_> = remote_node_index::list( - &config.node_dist_mirror, - &remote_node_index::SortingMethod::Ascending, - ) - .map_err(|source| Error::CantListRemoteVersions { source })?; + let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror) + .map_err(|source| Error::CantListRemoteVersions { source })?; let picked_version = lts_type .pick_latest(&available_versions) .ok_or_else(|| Error::CantFindRelevantLts { @@ -87,11 +84,8 @@ impl Command for Install { picked_version } UserVersion::Full(Version::Latest) => { - let available_versions: Vec<_> = remote_node_index::list( - &config.node_dist_mirror, - &remote_node_index::SortingMethod::Ascending, - ) - .map_err(|source| Error::CantListRemoteVersions { source })?; + let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror) + .map_err(|source| Error::CantListRemoteVersions { source })?; let picked_version = available_versions .last() .ok_or(Error::CantFindLatest)? @@ -105,14 +99,11 @@ impl Command for Install { picked_version } current_version => { - let available_versions: Vec<_> = remote_node_index::list( - &config.node_dist_mirror, - &remote_node_index::SortingMethod::Ascending, - ) - .map_err(|source| Error::CantListRemoteVersions { source })? - .drain(..) - .map(|x| x.version) - .collect(); + let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror) + .map_err(|source| Error::CantListRemoteVersions { source })? + .drain(..) + .map(|x| x.version) + .collect(); current_version .to_version(&available_versions, config) @@ -263,11 +254,8 @@ mod tests { .apply(&config) .expect("Can't install"); - let available_versions: Vec<_> = remote_node_index::list( - &config.node_dist_mirror, - &remote_node_index::SortingMethod::Ascending, - ) - .expect("Can't get node version list"); + let available_versions: Vec<_> = + remote_node_index::list(&config.node_dist_mirror).expect("Can't get node version list"); let latest_version = available_versions.last().unwrap().version.clone(); assert!(config.installations_dir().exists()); diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index 6690910a3..c00105049 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -17,18 +17,28 @@ pub struct LsRemote { /// Version sorting order #[arg(long, default_value = "asc")] - sort: remote_node_index::SortingMethod, + sort: SortingMethod, /// Only show the latest matching version #[arg(long)] latest: bool, } +#[derive(clap::ValueEnum, Clone, Debug, PartialEq)] +pub enum SortingMethod { + #[clap(name = "desc")] + /// Sort versions in descending order (latest to earliest) + Descending, + #[clap(name = "asc")] + /// Sort versions in ascending order (earliest to latest) + Ascending, +} + impl super::command::Command for LsRemote { type Error = Error; fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> { - let mut all_versions = remote_node_index::list(&config.node_dist_mirror, &self.sort)?; + let mut all_versions = remote_node_index::list(&config.node_dist_mirror)?; if let Some(lts) = &self.lts { match lts { @@ -54,6 +64,11 @@ impl super::command::Command for LsRemote { all_versions = vec![all_versions.into_iter().last().unwrap()]; } + all_versions.sort_by_key(|v| v.version.clone()); + if let SortingMethod::Descending = self.sort { + all_versions.reverse(); + } + for version in &all_versions { print!("{}", version.version); if let Some(lts) = &version.lts { diff --git a/src/remote_node_index.rs b/src/remote_node_index.rs index 6eb325918..79ca956e8 100644 --- a/src/remote_node_index.rs +++ b/src/remote_node_index.rs @@ -66,33 +66,15 @@ pub struct IndexedNodeVersion { pub files: Vec, } -#[derive(clap::ValueEnum, Clone, Debug, PartialEq)] -pub enum SortingMethod { - #[clap(name = "desc")] - /// Sort versions in descending order (latest to earliest) - Descending, - #[clap(name = "asc")] - /// Sort versions in ascending order (earliest to latest) - Ascending, -} - /// Prints /// /// ```rust /// use crate::remote_node_index::list; /// ``` -pub fn list( - base_url: &Url, - sort: &SortingMethod, -) -> Result, crate::http::Error> { +pub fn list(base_url: &Url) -> Result, crate::http::Error> { let index_json_url = format!("{base_url}/index.json"); let resp = crate::http::get(&index_json_url)?; - let mut value: Vec = resp.json()?; - - value.sort_by_key(|v| v.version.clone()); - if let SortingMethod::Descending = sort { - value.reverse(); - } + let value: Vec = resp.json()?; Ok(value) } @@ -106,7 +88,7 @@ mod tests { fn test_list() { let base_url = Url::parse("https://nodejs.org/dist").unwrap(); let expected_version = Version::parse("12.0.0").unwrap(); - let mut versions = list(&base_url, &SortingMethod::Ascending).expect("Can't get HTTP data"); + let mut versions = list(&base_url).expect("Can't get HTTP data"); assert_eq!( versions .drain(..) From 76bd090bd6e2b929f6bc328bf24527a2b4b27c38 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Mon, 13 Nov 2023 20:45:18 +0800 Subject: [PATCH 12/19] fix getting latest version --- src/commands/ls_remote.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index c00105049..0fc6d5e0a 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -61,7 +61,7 @@ impl super::command::Command for LsRemote { } if self.latest { - all_versions = vec![all_versions.into_iter().last().unwrap()]; + all_versions = vec![all_versions.into_iter().next().unwrap()]; } all_versions.sort_by_key(|v| v.version.clone()); From 81e6532b262c39eaa2945ad45407ed14521a0bc0 Mon Sep 17 00:00:00 2001 From: Ryan Cao <70191398+ryanccn@users.noreply.github.com> Date: Wed, 15 Nov 2023 21:09:56 +0800 Subject: [PATCH 13/19] refactors --- src/commands/ls_remote.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index 0fc6d5e0a..157ebd639 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -11,7 +11,7 @@ pub struct LsRemote { #[arg(long)] filter: Option, - /// Only show latest LTS versions + /// Show only LTS versions (optionally filter by LTS codename) #[arg(long)] lts: Option>, @@ -55,13 +55,8 @@ impl super::command::Command for LsRemote { all_versions.retain(|v| filter.matches(&v.version, config)); } - if all_versions.is_empty() { - eprintln!("{}", "No versions were found!".red()); - return Ok(()); - } - if self.latest { - all_versions = vec![all_versions.into_iter().next().unwrap()]; + all_versions.truncate(1); } all_versions.sort_by_key(|v| v.version.clone()); @@ -69,6 +64,11 @@ impl super::command::Command for LsRemote { all_versions.reverse(); } + if all_versions.is_empty() { + eprintln!("{}", "No versions were found!".red()); + return Ok(()); + } + for version in &all_versions { print!("{}", version.version); if let Some(lts) = &version.lts { From c019f1cf2e735e4a40e68c94229b05af2f44e4d1 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Mon, 27 May 2024 11:34:44 +0300 Subject: [PATCH 14/19] update docs/commands.md --- docs/commands.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/commands.md b/docs/commands.md index 8468c8673..ce2eea925 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -81,6 +81,9 @@ List all remote Node.js versions Usage: fnm list-remote [OPTIONS] Options: + --filter + Filter with SemVer + --node-dist-mirror mirror @@ -92,6 +95,21 @@ Options: [env: FNM_DIR] + --lts [] + Show only LTS versions (optionally filter by LTS codename) + + --sort + Version sorting order + + [default: asc] + + Possible values: + - desc: Sort versions in descending order (latest to earliest) + - asc: Sort versions in ascending order (earliest to latest) + + --latest + Only show the latest matching version + --log-level The log level of fnm commands From 769b96e6886df93e5e3f95ec03cf48982894eed1 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Mon, 27 May 2024 11:45:50 +0300 Subject: [PATCH 15/19] sort upon installation --- src/commands/install.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/commands/install.rs b/src/commands/install.rs index 79013ad1d..d40551bd4 100644 --- a/src/commands/install.rs +++ b/src/commands/install.rs @@ -95,8 +95,10 @@ impl Command for Install { picked_version } UserVersion::Full(Version::Latest) => { - let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror) - .map_err(|source| Error::CantListRemoteVersions { source })?; + let mut available_versions: Vec<_> = + remote_node_index::list(&config.node_dist_mirror) + .map_err(|source| Error::CantListRemoteVersions { source })?; + available_versions.sort_by(|a, b| a.version.cmp(&b.version)); let picked_version = available_versions .last() .ok_or(Error::CantFindLatest)? @@ -256,8 +258,8 @@ mod tests { #[test] fn test_install_latest() { - let base_dir = tempfile::tempdir().unwrap(); - let config = FnmConfig::default().with_base_dir(Some(base_dir.path().to_path_buf())); + let base_dir = std::path::PathBuf::from("/tmp/test123"); + let config = FnmConfig::default().with_base_dir(Some(base_dir.to_path_buf())); Install { version: None, @@ -268,8 +270,9 @@ mod tests { .apply(&config) .expect("Can't install"); - let available_versions: Vec<_> = + let mut available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror).expect("Can't get node version list"); + available_versions.sort_by(|a, b| a.version.cmp(&b.version)); let latest_version = available_versions.last().unwrap().version.clone(); assert!(config.installations_dir().exists()); From ab5ea61c4167649a823b6641928e1636adb279c8 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Mon, 27 May 2024 12:00:42 +0300 Subject: [PATCH 16/19] fix clippy --- src/commands/install.rs | 2 +- src/commands/ls_remote.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/commands/install.rs b/src/commands/install.rs index d40551bd4..fb620ccec 100644 --- a/src/commands/install.rs +++ b/src/commands/install.rs @@ -259,7 +259,7 @@ mod tests { #[test] fn test_install_latest() { let base_dir = std::path::PathBuf::from("/tmp/test123"); - let config = FnmConfig::default().with_base_dir(Some(base_dir.to_path_buf())); + let config = FnmConfig::default().with_base_dir(Some(base_dir.clone())); Install { version: None, diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index 157ebd639..a44b3e3ab 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -7,12 +7,13 @@ use thiserror::Error; #[derive(clap::Parser, Debug)] pub struct LsRemote { - /// Filter with SemVer + /// Filter with `SemVer` #[arg(long)] filter: Option, /// Show only LTS versions (optionally filter by LTS codename) #[arg(long)] + #[allow(clippy::option_option)] lts: Option>, /// Version sorting order From b0903b53b9779978a4e6c9fcfd507bfcf85e43dc Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Mon, 27 May 2024 12:07:21 +0300 Subject: [PATCH 17/19] don't mention rust structs in the cli docs --- docs/commands.md | 2 +- src/commands/ls_remote.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index ce2eea925..616d520ea 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -82,7 +82,7 @@ Usage: fnm list-remote [OPTIONS] Options: --filter - Filter with SemVer + Filter versions by a user-defined version or a semver range --node-dist-mirror mirror diff --git a/src/commands/ls_remote.rs b/src/commands/ls_remote.rs index a44b3e3ab..32f744931 100644 --- a/src/commands/ls_remote.rs +++ b/src/commands/ls_remote.rs @@ -7,7 +7,7 @@ use thiserror::Error; #[derive(clap::Parser, Debug)] pub struct LsRemote { - /// Filter with `SemVer` + /// Filter versions by a user-defined version or a semver range #[arg(long)] filter: Option, From 516c6d8a497081d76730c63a5d41c463f64d8e7a Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Mon, 27 May 2024 12:33:47 +0300 Subject: [PATCH 18/19] sort by default --- src/commands/install.rs | 9 +++------ src/remote_node_index.rs | 4 ++-- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/commands/install.rs b/src/commands/install.rs index fb620ccec..e13b25b5d 100644 --- a/src/commands/install.rs +++ b/src/commands/install.rs @@ -95,10 +95,8 @@ impl Command for Install { picked_version } UserVersion::Full(Version::Latest) => { - let mut available_versions: Vec<_> = - remote_node_index::list(&config.node_dist_mirror) - .map_err(|source| Error::CantListRemoteVersions { source })?; - available_versions.sort_by(|a, b| a.version.cmp(&b.version)); + let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror) + .map_err(|source| Error::CantListRemoteVersions { source })?; let picked_version = available_versions .last() .ok_or(Error::CantFindLatest)? @@ -270,9 +268,8 @@ mod tests { .apply(&config) .expect("Can't install"); - let mut available_versions: Vec<_> = + let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror).expect("Can't get node version list"); - available_versions.sort_by(|a, b| a.version.cmp(&b.version)); let latest_version = available_versions.last().unwrap().version.clone(); assert!(config.installations_dir().exists()); diff --git a/src/remote_node_index.rs b/src/remote_node_index.rs index 79ca956e8..4c9f3bdab 100644 --- a/src/remote_node_index.rs +++ b/src/remote_node_index.rs @@ -74,8 +74,8 @@ pub struct IndexedNodeVersion { pub fn list(base_url: &Url) -> Result, crate::http::Error> { let index_json_url = format!("{base_url}/index.json"); let resp = crate::http::get(&index_json_url)?; - let value: Vec = resp.json()?; - + let mut value: Vec = resp.json()?; + value.sort_by(|a, b| a.version.cmp(&b.version)); Ok(value) } From a4362544ccb8e800230f07c9c603b0f4db80473d Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Mon, 27 May 2024 12:35:54 +0300 Subject: [PATCH 19/19] remove leftover temp dir from test --- src/commands/install.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/install.rs b/src/commands/install.rs index e13b25b5d..79013ad1d 100644 --- a/src/commands/install.rs +++ b/src/commands/install.rs @@ -256,8 +256,8 @@ mod tests { #[test] fn test_install_latest() { - let base_dir = std::path::PathBuf::from("/tmp/test123"); - let config = FnmConfig::default().with_base_dir(Some(base_dir.clone())); + let base_dir = tempfile::tempdir().unwrap(); + let config = FnmConfig::default().with_base_dir(Some(base_dir.path().to_path_buf())); Install { version: None,