Browse Source

Bump Clap 3 -> 4 (#991)

* fix(deps): update clap-rs to v4

* Define enums for multi-choice clap args

* fix test

* Update command docs

* Add `all` alias to log-level

* remove unused thing

* Add changeset

* Use `Shells` instead of `Box<dyn Shell>` everywhere

* Revert "Use `Shells` instead of `Box<dyn Shell>` everywhere"

This reverts commit 7781b5d87354c1f9500ecfafde1aba43d6dd5e37.

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
remotes/origin/list-filter
Amit Dahan 2 years ago committed by GitHub
parent
commit
b19eb29b26
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .changeset/breezy-olives-appear.md
  2. 7
      .ci/print-command-docs.js
  3. 137
      Cargo.lock
  4. 4
      Cargo.toml
  5. 1067
      docs/commands.md
  6. 16
      src/commands/completions.rs
  7. 22
      src/commands/env.rs
  8. 14
      src/config.rs
  9. 31
      src/log_level.rs
  10. 2
      src/shell/mod.rs
  11. 49
      src/shell/shell.rs
  12. 2
      src/user_version_reader.rs
  13. 32
      src/version_file_strategy.rs

5
.changeset/breezy-olives-appear.md

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
---
"fnm": patch
---
Bump Clap 3 -> 4

7
.ci/print-command-docs.js

@ -106,11 +106,14 @@ async function getCommandHelp(fnmPath, command) { @@ -106,11 +106,14 @@ async function getCommandHelp(fnmPath, command) {
const result = await run(fnmPath, [...cmdArg, "--help"])
const text = result.stdout
const rows = text.split("\n")
const headerIndex = rows.findIndex((x) => x.includes("SUBCOMMANDS"))
const headerIndex = rows.findIndex((x) => x.includes("Commands:"))
/** @type {string[]} */
const subcommands = []
if (!command) {
for (const row of rows.slice(headerIndex + 1)) {
for (const row of rows.slice(
headerIndex + 1,
rows.indexOf("", headerIndex + 1)
)) {
const [, word] = row.split(/\s+/)
if (word && word[0].toLowerCase() === word[0]) {
subcommands.push(word)

137
Cargo.lock generated

@ -67,6 +67,55 @@ dependencies = [ @@ -67,6 +67,55 @@ dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"colorchoice",
"is-terminal",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a30da5c5f2d5e72842e00bcb57657162cdabef0931f40e2deb9b4140440cecd"
[[package]]
name = "anstyle-parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "anstyle-wincon"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188"
dependencies = [
"anstyle",
"windows-sys 0.48.0",
]
[[package]]
name = "anyhow"
version = "1.0.71"
@ -254,51 +303,59 @@ dependencies = [ @@ -254,51 +303,59 @@ dependencies = [
[[package]]
name = "clap"
version = "3.2.25"
version = "4.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123"
checksum = "384e169cc618c613d5e3ca6404dda77a8685a63e08660dcc64abaf7da7cb0c7a"
dependencies = [
"atty",
"bitflags",
"clap_builder",
"clap_derive",
"clap_lex",
"indexmap",
"once_cell",
]
[[package]]
name = "clap_builder"
version = "4.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef137bbe35aab78bdb468ccfba75a5f4d8321ae011d34063770780545176af2d"
dependencies = [
"anstream",
"anstyle",
"clap_lex",
"strsim",
"termcolor",
"textwrap",
]
[[package]]
name = "clap_complete"
version = "3.2.5"
version = "4.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f7a2e0a962c45ce25afce14220bc24f9dade0a1787f185cecf96bfba7847cd8"
checksum = "7f6b5c519bab3ea61843a7923d074b04245624bb84a64a8c150f5deb014e388b"
dependencies = [
"clap",
]
[[package]]
name = "clap_derive"
version = "3.2.25"
version = "4.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae6371b8bdc8b7d3959e9cf7b22d4435ef3e79e138688421ec654acf8c81b008"
checksum = "b8cd2b2a819ad6eec39e8f1d6b53001af1e5469f8c177579cdaeb313115b825f"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.22",
]
[[package]]
name = "clap_lex"
version = "0.2.4"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5"
dependencies = [
"os_str_bytes",
]
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "colored"
@ -1174,12 +1231,6 @@ dependencies = [ @@ -1174,12 +1231,6 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "os_str_bytes"
version = "6.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d5d9eb14b174ee9aa2ef96dc2b94637a2d4b6e7cb873c7e171f0c20c6cf3eac"
[[package]]
name = "output_vt100"
version = "0.1.3"
@ -1248,30 +1299,6 @@ dependencies = [ @@ -1248,30 +1299,6 @@ dependencies = [
"yansi",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.63"
@ -1747,12 +1774,6 @@ dependencies = [ @@ -1747,12 +1774,6 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "textwrap"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
[[package]]
name = "thiserror"
version = "1.0.40"
@ -1947,6 +1968,12 @@ dependencies = [ @@ -1947,6 +1968,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "utf8parse"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "version_check"
version = "0.9.4"

4
Cargo.toml

@ -10,7 +10,7 @@ description = "Fast and simple Node.js version manager" @@ -10,7 +10,7 @@ description = "Fast and simple Node.js version manager"
[dependencies]
serde = { version = "1.0.164", features = ["derive"] }
clap = { version = "3.2.25", features = ["derive", "env"] }
clap = { version = "4.3.10", features = ["derive", "env"] }
serde_json = "1.0.99"
chrono = { version = "0.4.26", features = ["serde"] }
tar = "0.4.38"
@ -28,7 +28,7 @@ reqwest = { version = "0.11.18", features = ["blocking", "json", "rustls-tls", " @@ -28,7 +28,7 @@ reqwest = { version = "0.11.18", features = ["blocking", "json", "rustls-tls", "
url = "2.4.0"
sysinfo = "0.29.3"
thiserror = "1.0.40"
clap_complete = "3.2.5"
clap_complete = "4.3.1"
anyhow = "1.0.71"
[dev-dependencies]

1067
docs/commands.md

File diff suppressed because it is too large Load Diff

16
src/commands/completions.rs

@ -1,16 +1,16 @@ @@ -1,16 +1,16 @@
use super::command::Command;
use crate::cli::Cli;
use crate::config::FnmConfig;
use crate::shell::{infer_shell, AVAILABLE_SHELLS};
use clap::{IntoApp, Parser};
use clap_complete::{Generator, Shell};
use crate::shell::{infer_shell, Shell};
use crate::{cli::Cli, shell::Shells};
use clap::{CommandFactory, Parser, ValueEnum};
use clap_complete::{Generator, Shell as ClapShell};
use thiserror::Error;
#[derive(Parser, Debug)]
pub struct Completions {
/// The shell syntax to use. Infers when missing.
#[clap(long)]
shell: Option<Shell>,
shell: Option<Shells>,
}
impl Command for Completions {
@ -18,10 +18,12 @@ impl Command for Completions { @@ -18,10 +18,12 @@ impl Command for Completions {
fn apply(self, _config: &FnmConfig) -> Result<(), Self::Error> {
let mut stdio = std::io::stdout();
let shell = self
let shell: Box<dyn Shell> = self
.shell
.map(Into::into)
.or_else(|| infer_shell().map(Into::into))
.ok_or(Error::CantInferShell)?;
let shell: ClapShell = shell.into();
let app = Cli::command();
shell.generate(&app, &mut stdio);
Ok(())
@ -41,7 +43,7 @@ pub enum Error { @@ -41,7 +43,7 @@ pub enum Error {
}
fn shells_as_string() -> String {
AVAILABLE_SHELLS
Shells::value_variants()
.iter()
.map(|x| format!("* {x}"))
.collect::<Vec<_>>()

22
src/commands/env.rs

@ -4,7 +4,8 @@ use crate::directories; @@ -4,7 +4,8 @@ use crate::directories;
use crate::fs::symlink_dir;
use crate::outln;
use crate::path_ext::PathExt;
use crate::shell::{infer_shell, Shell, AVAILABLE_SHELLS};
use crate::shell::{infer_shell, Shell, Shells};
use clap::ValueEnum;
use colored::Colorize;
use std::collections::HashMap;
use std::fmt::Debug;
@ -14,8 +15,7 @@ use thiserror::Error; @@ -14,8 +15,7 @@ use thiserror::Error;
pub struct Env {
/// The shell syntax to use. Infers when missing.
#[clap(long)]
#[clap(possible_values = AVAILABLE_SHELLS)]
shell: Option<Box<dyn Shell>>,
shell: Option<Shells>,
/// Print JSON instead of shell commands.
#[clap(long, conflicts_with = "shell")]
json: bool,
@ -104,6 +104,7 @@ impl Command for Env { @@ -104,6 +104,7 @@ impl Command for Env {
let shell: Box<dyn Shell> = self
.shell
.map(Into::into)
.or_else(infer_shell)
.ok_or(Error::CantInferShell)?;
@ -148,7 +149,7 @@ pub enum Error { @@ -148,7 +149,7 @@ pub enum Error {
}
fn shells_as_string() -> String {
AVAILABLE_SHELLS
Shells::value_variants()
.iter()
.map(|x| format!("* {x}"))
.collect::<Vec<_>>()
@ -161,16 +162,13 @@ mod tests { @@ -161,16 +162,13 @@ mod tests {
#[test]
fn test_smoke() {
use crate::shell;
let config = FnmConfig::default();
let shell: Box<dyn Shell> = if cfg!(windows) {
Box::from(shell::WindowsCmd)
} else {
Box::from(shell::Bash)
};
Env {
shell: Some(shell),
..Env::default()
#[cfg(windows)]
shell: Some(Shells::Cmd),
#[cfg(not(windows))]
shell: Some(Shells::Bash),
..Default::default()
}
.call(config);
}

14
src/config.rs

@ -36,10 +36,9 @@ pub struct FnmConfig { @@ -36,10 +36,9 @@ pub struct FnmConfig {
#[clap(
long,
env = "FNM_LOGLEVEL",
default_value = "info",
default_value_t,
global = true,
hide_env_values = true,
possible_values = LogLevel::possible_values()
hide_env_values = true
)]
log_level: LogLevel,
@ -57,17 +56,12 @@ pub struct FnmConfig { @@ -57,17 +56,12 @@ pub struct FnmConfig {
/// 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.
///
/// * `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
#[clap(
long,
env = "FNM_VERSION_FILE_STRATEGY",
possible_values = VersionFileStrategy::possible_values(),
default_value = "local",
default_value_t,
global = true,
hide_env_values = true,
hide_env_values = true
)]
version_file_strategy: VersionFileStrategy,

31
src/log_level.rs

@ -1,10 +1,26 @@ @@ -1,10 +1,26 @@
#[derive(Debug, PartialEq, PartialOrd, Eq, Ord, Clone)]
use std::fmt::Display;
use clap::ValueEnum;
#[derive(Debug, Default, PartialEq, PartialOrd, Eq, Ord, Clone, ValueEnum)]
pub enum LogLevel {
Quiet,
Error,
#[default]
#[value(alias("all"))]
Info,
}
impl Display for LogLevel {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
LogLevel::Quiet => write!(f, "quiet"),
LogLevel::Error => write!(f, "error"),
LogLevel::Info => write!(f, "info"),
}
}
}
impl LogLevel {
pub fn is_writable(&self, logging: &Self) -> bool {
use std::cmp::Ordering;
@ -37,19 +53,6 @@ impl From<LogLevel> for &'static str { @@ -37,19 +53,6 @@ impl From<LogLevel> for &'static str {
}
}
impl std::str::FromStr for LogLevel {
type Err = &'static str;
fn from_str(s: &str) -> Result<LogLevel, Self::Err> {
match s {
"quiet" => Ok(Self::Quiet),
"info" | "all" => Ok(Self::Info),
"error" => Ok(Self::Error),
_ => Err("Unsupported log level"),
}
}
}
#[macro_export]
macro_rules! outln {
($config:ident, $level:path, $($expr:expr),+) => {{

2
src/shell/mod.rs

@ -13,7 +13,7 @@ pub use bash::Bash; @@ -13,7 +13,7 @@ pub use bash::Bash;
pub use fish::Fish;
pub use infer::infer_shell;
pub use powershell::PowerShell;
pub use shell::{Shell, AVAILABLE_SHELLS};
pub use shell::{Shell, Shells};
pub use windows_cmd::WindowsCmd;
pub use windows_compat::maybe_fix_windows_path;
pub use zsh::Zsh;

49
src/shell/shell.rs

@ -1,6 +1,8 @@ @@ -1,6 +1,8 @@
use std::fmt::Debug;
use std::fmt::{Debug, Display};
use std::path::Path;
use clap::ValueEnum;
pub trait Shell: Debug {
fn path(&self, path: &Path) -> anyhow::Result<String>;
fn set_env_var(&self, name: &str, value: &str) -> String;
@ -11,23 +13,38 @@ pub trait Shell: Debug { @@ -11,23 +13,38 @@ pub trait Shell: Debug {
fn to_clap_shell(&self) -> clap_complete::Shell;
}
#[cfg(windows)]
pub const AVAILABLE_SHELLS: &[&str; 5] = &["cmd", "powershell", "bash", "zsh", "fish"];
#[cfg(unix)]
pub const AVAILABLE_SHELLS: &[&str; 4] = &["bash", "zsh", "fish", "powershell"];
#[derive(Debug, Clone, ValueEnum)]
pub enum Shells {
Bash,
Zsh,
Fish,
PowerShell,
#[cfg(windows)]
Cmd,
}
impl std::str::FromStr for Box<dyn Shell> {
type Err = String;
impl Display for Shells {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Shells::Bash => write!(f, "bash"),
Shells::Zsh => write!(f, "zsh"),
Shells::Fish => write!(f, "fish"),
Shells::PowerShell => write!(f, "powershell"),
#[cfg(windows)]
Shells::Cmd => write!(f, "cmd"),
}
}
}
fn from_str(s: &str) -> Result<Box<dyn Shell>, Self::Err> {
match s {
"cmd" => Ok(Box::from(super::windows_cmd::WindowsCmd)),
"zsh" => Ok(Box::from(super::zsh::Zsh)),
"bash" => Ok(Box::from(super::bash::Bash)),
"fish" => Ok(Box::from(super::fish::Fish)),
"powershell" => Ok(Box::from(super::powershell::PowerShell)),
shell_type => Err(format!("I don't know the shell type of {shell_type:?}",)),
impl From<Shells> for Box<dyn Shell> {
fn from(shell: Shells) -> Box<dyn Shell> {
match shell {
Shells::Zsh => Box::from(super::zsh::Zsh),
Shells::Bash => Box::from(super::bash::Bash),
Shells::Fish => Box::from(super::fish::Fish),
Shells::PowerShell => Box::from(super::powershell::PowerShell),
#[cfg(windows)]
Shells::Cmd => Box::from(super::windows_cmd::WindowsCmd),
}
}
}

2
src/user_version_reader.rs

@ -4,7 +4,7 @@ use crate::version_files::{get_user_version_for_directory, get_user_version_for_ @@ -4,7 +4,7 @@ use crate::version_files::{get_user_version_for_directory, get_user_version_for_
use std::path::PathBuf;
use std::str::FromStr;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub enum UserVersionReader {
Direct(UserVersion),
Path(PathBuf),

32
src/version_file_strategy.rs

@ -1,17 +1,25 @@ @@ -1,17 +1,25 @@
use std::str::FromStr;
use clap::ValueEnum;
use std::fmt::Display;
#[derive(Debug, Default)]
#[derive(Debug, Clone, Default, ValueEnum)]
pub enum VersionFileStrategy {
/// Use the local version of Node defined within the current directory
#[default]
Local,
/// Use the version of Node defined within the current directory and all parent directories
Recursive,
}
impl VersionFileStrategy {
pub fn possible_values() -> &'static [&'static str] {
&["local", "recursive"]
impl Display for VersionFileStrategy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
VersionFileStrategy::Local => write!(f, "local"),
VersionFileStrategy::Recursive => write!(f, "recursive"),
}
}
}
impl VersionFileStrategy {
pub fn as_str(&self) -> &'static str {
match self {
VersionFileStrategy::Local => "local",
@ -19,17 +27,3 @@ impl VersionFileStrategy { @@ -19,17 +27,3 @@ impl VersionFileStrategy {
}
}
}
impl FromStr for VersionFileStrategy {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"local" => Ok(VersionFileStrategy::Local),
"recursive" => Ok(VersionFileStrategy::Recursive),
_ => Err(format!(
"Invalid strategy: {s}. Expected one of: local, recursive"
)),
}
}
}

Loading…
Cancel
Save