Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add 'info' command to display current, LTS, and latest Node.js #1304

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Usage: fnm [OPTIONS] <COMMAND>
Commands:
list-remote List all remote Node.js versions [aliases: ls-remote]
list List all locally installed Node.js versions [aliases: ls]
info Print information about the current, lts and latest Node.js versions
install Install a new Node.js version [aliases: i]
use Change Node.js version
env Print and set up required environment variables for fnm
Expand Down Expand Up @@ -220,6 +221,86 @@ Options:
Print help (see a summary with '-h')
```

# `fnm info`

```
Print information about the current, lts and latest Node.js versions

Usage: fnm info [OPTIONS]

Options:
--filter <FILTER>
Filter versions by a user-defined version or a semver range

--node-dist-mirror <NODE_DIST_MIRROR>
<https://nodejs.org/dist/> mirror

[env: FNM_NODE_DIST_MIRROR]
[default: https://nodejs.org/dist]

--fnm-dir <BASE_DIR>
The root directory of fnm installations

[env: FNM_DIR]

--lts [<LTS>]
Show only LTS versions (optionally filter by LTS codename)

--sort <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 <LOG_LEVEL>
The log level of fnm commands

[env: FNM_LOGLEVEL]
[default: info]
[possible values: quiet, error, info]

--arch <ARCH>
Override the architecture of the installed Node binary. Defaults to arch of fnm binary

[env: FNM_ARCH]

--version-file-strategy <VERSION_FILE_STRATEGY>
A strategy for how to resolve the Node version. Used whenever `fnm use` or `fnm install` is called without a version, or when `--use-on-cd` is configured on evaluation

[env: FNM_VERSION_FILE_STRATEGY]
[default: local]

Possible values:
- local: Use the local version of Node defined within the current directory
- recursive: Use the version of Node defined within the current directory and all parent directories

--corepack-enabled
Enable corepack support for each new installation. This will make fnm call `corepack enable` on every Node.js installation. For more information about corepack see <https://nodejs.org/api/corepack.html>

[env: FNM_COREPACK_ENABLED]

--resolve-engines [<RESOLVE_ENGINES>]
Resolve `engines.node` field in `package.json` whenever a `.node-version` or `.nvmrc` file is not present.
This feature is enabled by default. To disable it, provide `--resolve-engines=false`.

Note: `engines.node` can be any semver range, with the latest satisfying version being resolved.
Note 2: If you disable it, please open an issue on GitHub describing _why_ you disabled it.
In the future, disabling it might be a no-op, so it's worth knowing any reason to
do that.

[env: FNM_RESOLVE_ENGINES]
[possible values: true, false]

-h, --help
Print help (see a summary with '-h')
```

# `fnm install`

```
Expand Down
5 changes: 5 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ pub enum SubCommand {
#[clap(name = "list", bin_name = "list", visible_aliases = &["ls"])]
LsLocal(commands::ls_local::LsLocal),

/// Print information about the current, lts and latest Node.js versions
#[clap(name = "info", bin_name = "info")]
Info(commands::info::Info),

/// Install a new Node.js version
#[clap(name = "install", bin_name = "install", visible_aliases = &["i"])]
Install(commands::install::Install),
Expand Down Expand Up @@ -76,6 +80,7 @@ impl SubCommand {
match self {
Self::LsLocal(cmd) => cmd.call(config),
Self::LsRemote(cmd) => cmd.call(config),
Self::Info(cmd) => cmd.call(config),
Self::Install(cmd) => cmd.call(config),
Self::Env(cmd) => cmd.call(config),
Self::Use(cmd) => cmd.call(config),
Expand Down
101 changes: 101 additions & 0 deletions src/commands/info.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use crate::config::FnmConfig;
use crate::remote_node_index;
use crate::user_version::UserVersion;
use crate::current_version::{current_version, Error as CurrentVersionError};

use colored::Colorize;
use thiserror::Error;

#[derive(clap::Parser, Debug)]
pub struct Info {
/// Filter versions by a user-defined version or a semver range
#[arg(long)]
filter: Option<UserVersion>,

/// Show only LTS versions (optionally filter by LTS codename)
#[arg(long)]
#[expect(
clippy::option_option,
reason = "clap Option<Option<T>> supports --x and --x=value syntaxes"
)]
lts: Option<Option<String>>,

/// Version sorting order
#[arg(long, default_value = "asc")]
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 Info {
type Error = Error;

fn apply(self, config: &FnmConfig) -> Result<(), Self::Error> {
// Get all versions from the Node.js URL.
let all_versions = remote_node_index::list(&config.node_dist_mirror)?;

// Filter the latest LTS version.
let latest_lts = all_versions.iter().rev()
.find(|v| match &v.lts {
Some(_) => true, // If it is Some, pass (any value)
None => false, // If it is None, do not pass
})
.map(|v| v.version.clone());

// Filter the latest version "latest".
let latest = all_versions.last().map(|v| v.version.clone());

// Print the current version
let version_string = match current_version(config)? {
Some(ver) => ver.v_str(),
None => "none".into(),
};

println!("Using: {}", format!("{version_string}").green());

// Print the latest LTS version.
if let Some(lts) = latest_lts {
let version_str = format!("{lts}");

println!("Current LTS: {}", version_str.cyan());
} else {
eprintln!("{}", "No LTS version found.".red());
}

// Print the latest version.
if let Some(latest) = latest {
let version_str = format!("{latest}");
println!("Current latest: {}", version_str.cyan());
} else {
eprintln!("{}", "No latest version found.".red());
}

Ok(())
}
}

#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
HttpError {
#[from]
source: crate::http::Error,
},
#[error(transparent)]
CurrentVersionError {
#[from]
source: CurrentVersionError,
},
}
1 change: 1 addition & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod current;
pub mod default;
pub mod env;
pub mod exec;
pub mod info;
pub mod install;
pub mod ls_local;
pub mod ls_remote;
Expand Down