Browse Source

feat: add remote version sorting and filtering

remotes/origin/list-filter
Ryan Cao 1 year ago
parent
commit
934ec4f6b2
No known key found for this signature in database
  1. 5
      .changeset/fifty-emus-type.md
  2. 22
      src/commands/install.rs
  3. 47
      src/commands/ls_remote.rs
  4. 23
      src/remote_node_index.rs

5
.changeset/fifty-emus-type.md

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
---
"fnm": minor
---
feat: add remote version sorting and filtering

22
src/commands/install.rs

@ -67,7 +67,10 @@ impl Command for Install { @@ -67,7 +67,10 @@ 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)
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)
@ -84,7 +87,10 @@ impl Command for Install { @@ -84,7 +87,10 @@ impl Command for Install {
picked_version
}
UserVersion::Full(Version::Latest) => {
let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror)
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()
@ -99,7 +105,10 @@ impl Command for Install { @@ -99,7 +105,10 @@ impl Command for Install {
picked_version
}
current_version => {
let available_versions: Vec<_> = remote_node_index::list(&config.node_dist_mirror)
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)
@ -254,8 +263,11 @@ mod tests { @@ -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());

47
src/commands/ls_remote.rs

@ -1,24 +1,63 @@ @@ -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<String>,
// 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()));
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 {
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(())
}
}

23
src/remote_node_index.rs

@ -66,16 +66,35 @@ pub struct IndexedNodeVersion { @@ -66,16 +66,35 @@ pub struct IndexedNodeVersion {
pub files: Vec<String>,
}
#[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<Vec<IndexedNodeVersion>, crate::http::Error> {
pub fn list(
base_url: &Url,
sort: &SortingMethod,
) -> Result<Vec<IndexedNodeVersion>, crate::http::Error> {
let index_json_url = format!("{base_url}/index.json");
let resp = crate::http::get(&index_json_url)?;
let mut value: Vec<IndexedNodeVersion> = 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));
}
Ok(value)
}
@ -88,7 +107,7 @@ mod tests { @@ -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(..)

Loading…
Cancel
Save