Skip to content

Commit 8a22d57

Browse files
committed
refactor(cli): rewrite rustup (man|completions) with clap-derive
1 parent 989d81a commit 8a22d57

8 files changed

+52
-88
lines changed

src/cli/rustup_mode.rs

Lines changed: 35 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use std::str::FromStr;
66

77
use anyhow::{anyhow, Error, Result};
88
use clap::{
9-
builder::{EnumValueParser, PossibleValue, PossibleValuesParser},
9+
builder::{PossibleValue, PossibleValuesParser},
1010
Arg, ArgAction, ArgMatches, Args, Command, FromArgMatches as _, Parser, Subcommand, ValueEnum,
1111
};
1212
use clap_complete::Shell;
@@ -37,8 +37,8 @@ use crate::{
3737
toolchain::{
3838
distributable::DistributableToolchain,
3939
names::{
40-
partial_toolchain_desc_parser, CustomToolchainName, MaybeResolvableToolchainName,
41-
ResolvableLocalToolchainName, ResolvableToolchainName, ToolchainName,
40+
CustomToolchainName, MaybeResolvableToolchainName, ResolvableLocalToolchainName,
41+
ResolvableToolchainName, ToolchainName,
4242
},
4343
toolchain::Toolchain,
4444
},
@@ -206,6 +206,24 @@ enum RustupSubcmd {
206206
#[command(flatten)]
207207
page: DocPage,
208208
},
209+
210+
/// View the man page for a given command
211+
#[cfg(not(windows))]
212+
Man {
213+
command: String,
214+
215+
#[arg(long, help = OFFICIAL_TOOLCHAIN_ARG_HELP)]
216+
toolchain: Option<PartialToolchainDesc>,
217+
},
218+
219+
/// Generate tab-completion scripts for your shell
220+
#[command(after_help = COMPLETIONS_HELP, arg_required_else_help = true)]
221+
Completions {
222+
shell: Shell,
223+
224+
#[arg(default_value = "rustup")]
225+
command: CompletionCommand,
226+
},
209227
}
210228

211229
#[derive(Debug, Subcommand)]
@@ -503,6 +521,11 @@ impl Rustup {
503521
topic,
504522
page,
505523
} => doc(cfg, path, toolchain, topic.as_deref(), &page),
524+
#[cfg(not(windows))]
525+
RustupSubcmd::Man { command, toolchain } => man(cfg, &command, toolchain),
526+
RustupSubcmd::Completions { shell, command } => {
527+
output_completion_script(shell, command)
528+
}
506529
}
507530
}
508531
}
@@ -581,10 +604,9 @@ pub fn main() -> Result<utils::ExitCode> {
581604
(
582605
"dump-testament" | "show" | "update" | "install" | "uninstall" | "toolchain"
583606
| "check" | "default" | "target" | "component" | "override" | "run" | "which"
584-
| "doc",
607+
| "doc" | "man" | "completions",
585608
_,
586609
) => Rustup::from_arg_matches(&matches)?.dispatch(cfg)?,
587-
("man", m) => man(cfg, m)?,
588610
("self", c) => match c.subcommand() {
589611
Some(s) => match s {
590612
("update", _) => self_update::update(cfg)?,
@@ -602,18 +624,6 @@ pub fn main() -> Result<utils::ExitCode> {
602624
},
603625
None => unreachable!(),
604626
},
605-
("completions", c) => {
606-
if let Some(&shell) = c.get_one::<Shell>("shell") {
607-
output_completion_script(
608-
shell,
609-
c.get_one::<CompletionCommand>("command")
610-
.copied()
611-
.unwrap_or(CompletionCommand::Rustup),
612-
)?
613-
} else {
614-
unreachable!()
615-
}
616-
}
617627
_ => unreachable!(),
618628
},
619629
None => {
@@ -624,7 +634,7 @@ pub fn main() -> Result<utils::ExitCode> {
624634
}
625635

626636
pub(crate) fn cli() -> Command {
627-
let mut app = Command::new("rustup")
637+
let app = Command::new("rustup")
628638
.version(common::version())
629639
.about("The Rust toolchain installer")
630640
.before_help(format!("rustup {}", common::version()))
@@ -652,24 +662,7 @@ pub(crate) fn cli() -> Command {
652662
Err(Error::raw(ErrorKind::InvalidSubcommand, format!("\"{s}\" is not a valid subcommand, so it was interpreted as a toolchain name, but it is also invalid. {TOOLCHAIN_OVERRIDE_ERROR}")))
653663
}
654664
}),
655-
);
656-
657-
if cfg!(not(target_os = "windows")) {
658-
app = app.subcommand(
659-
Command::new("man")
660-
.about("View the man page for a given command")
661-
.arg(Arg::new("command").required(true))
662-
.arg(
663-
Arg::new("toolchain")
664-
.help(OFFICIAL_TOOLCHAIN_ARG_HELP)
665-
.long("toolchain")
666-
.num_args(1)
667-
.value_parser(partial_toolchain_desc_parser),
668-
),
669-
);
670-
}
671-
672-
app = app
665+
)
673666
.subcommand(
674667
Command::new("self")
675668
.about("Modify the rustup installation")
@@ -715,18 +708,6 @@ pub(crate) fn cli() -> Command {
715708
.default_value(SelfUpdateMode::default_mode()),
716709
),
717710
),
718-
)
719-
.subcommand(
720-
Command::new("completions")
721-
.about("Generate tab-completion scripts for your shell")
722-
.after_help(COMPLETIONS_HELP)
723-
.arg_required_else_help(true)
724-
.arg(Arg::new("shell").value_parser(EnumValueParser::<Shell>::new()))
725-
.arg(
726-
Arg::new("command")
727-
.value_parser(EnumValueParser::<CompletionCommand>::new())
728-
.default_missing_value("rustup"),
729-
),
730711
);
731712

732713
RustupSubcmd::augment_subcommands(app)
@@ -1336,16 +1317,6 @@ fn component_remove(
13361317
Ok(utils::ExitCode(0))
13371318
}
13381319

1339-
// Make *sure* only to use this for a subcommand whose "toolchain" argument
1340-
// has .value_parser(partial_toolchain_desc_parser), or it will panic.
1341-
// FIXME: Delete this.
1342-
fn explicit_desc_or_dir_toolchain_old<'a>(cfg: &'a Cfg, m: &ArgMatches) -> Result<Toolchain<'a>> {
1343-
let toolchain = m
1344-
.get_one::<PartialToolchainDesc>("toolchain")
1345-
.map(Into::into);
1346-
explicit_or_dir_toolchain2(cfg, toolchain)
1347-
}
1348-
13491320
fn explicit_desc_or_dir_toolchain(
13501321
cfg: &Cfg,
13511322
toolchain: Option<PartialToolchainDesc>,
@@ -1580,10 +1551,12 @@ fn doc(
15801551
}
15811552
}
15821553

1583-
fn man(cfg: &Cfg, m: &ArgMatches) -> Result<utils::ExitCode> {
1584-
let command = m.get_one::<String>("command").unwrap();
1585-
1586-
let toolchain = explicit_desc_or_dir_toolchain_old(cfg, m)?;
1554+
fn man(
1555+
cfg: &Cfg,
1556+
command: &str,
1557+
toolchain: Option<PartialToolchainDesc>,
1558+
) -> Result<utils::ExitCode> {
1559+
let toolchain = explicit_desc_or_dir_toolchain(cfg, toolchain)?;
15871560
let mut path = toolchain.path().to_path_buf();
15881561
path.push("share");
15891562
path.push("man");

src/toolchain/names.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,15 +125,6 @@ fn validate(candidate: &str) -> Result<&str, InvalidName> {
125125
}
126126
}
127127

128-
/// Thunk to avoid errors like
129-
/// = note: `fn(&'2 str) -> Result<CustomToolchainName, <CustomToolchainName as TryFrom<&'2 str>>::Error> {<CustomToolchainName as TryFrom<&'2 str>>::try_from}` must implement `FnOnce<(&'1 str,)>`, for any lifetime `'1`...
130-
/// = note: ...but it actually implements `FnOnce<(&'2 str,)>`, for some specific lifetime `'2`
131-
pub(crate) fn partial_toolchain_desc_parser(
132-
value: &str,
133-
) -> Result<PartialToolchainDesc, anyhow::Error> {
134-
value.parse::<PartialToolchainDesc>()
135-
}
136-
137128
/// A toolchain name from user input.
138129
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
139130
pub(crate) enum ResolvableToolchainName {

tests/suite/cli-ui/rustup/rustup_completions_cmd_help_flag_stdout.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
bin.name = "rustup"
2-
args = ["completions","--help"]
2+
args = ["completions", "--help"]
33
stdout = """
44
...
55
Generate tab-completion scripts for your shell
66
7-
Usage: rustup[EXE] completions [shell] [command]
7+
Usage: rustup[EXE] completions <SHELL> [COMMAND]
88
99
Arguments:
10-
[shell] [possible values: bash, elvish, fish, powershell, zsh]
11-
[command] [possible values: rustup, cargo]
10+
<SHELL> [possible values: bash, elvish, fish, powershell, zsh]
11+
[COMMAND] [default: rustup] [possible values: rustup, cargo]
1212
1313
Options:
1414
-h, --help Print help

tests/suite/cli-ui/rustup/rustup_help_cmd_stdout.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ The Rust toolchain installer
99
Usage: rustup[EXE] [OPTIONS] [+toolchain] [COMMAND]
1010
1111
Commands:
12-
...
1312
self Modify the rustup installation
1413
set Alter rustup settings
15-
completions Generate tab-completion scripts for your shell
1614
show Show the active and installed toolchains or profiles
1715
update Update Rust toolchains and rustup
1816
check Check for updates to Rust toolchains and rustup
@@ -24,6 +22,8 @@ Commands:
2422
run Run a command with an environment configured for a given toolchain
2523
which Display which binary will be run for a given command
2624
doc Open the documentation for the current toolchain
25+
...
26+
completions Generate tab-completion scripts for your shell
2727
help Print this message or the help of the given subcommand(s)
2828
2929
Arguments:

tests/suite/cli-ui/rustup/rustup_help_flag_stdout.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ The Rust toolchain installer
99
Usage: rustup[EXE] [OPTIONS] [+toolchain] [COMMAND]
1010
1111
Commands:
12-
...
1312
self Modify the rustup installation
1413
set Alter rustup settings
15-
completions Generate tab-completion scripts for your shell
1614
show Show the active and installed toolchains or profiles
1715
update Update Rust toolchains and rustup
1816
check Check for updates to Rust toolchains and rustup
@@ -24,6 +22,8 @@ Commands:
2422
run Run a command with an environment configured for a given toolchain
2523
which Display which binary will be run for a given command
2624
doc Open the documentation for the current toolchain
25+
...
26+
completions Generate tab-completion scripts for your shell
2727
help Print this message or the help of the given subcommand(s)
2828
2929
Arguments:

tests/suite/cli-ui/rustup/rustup_man_cmd_help_flag_stdout.toml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
bin.name = "rustup"
2-
args = ["man","--help"]
2+
args = ["man", "--help"]
33
stdout = """
44
...
55
View the man page for a given command
66
7-
Usage: rustup[EXE] man [OPTIONS] <command>
7+
Usage: rustup[EXE] man [OPTIONS] <COMMAND>
88
99
Arguments:
10-
<command>
10+
<COMMAND>
1111
1212
Options:
13-
--toolchain <toolchain> Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more
13+
--toolchain <TOOLCHAIN> Toolchain name, such as 'stable', 'nightly', or '1.8.0'. For more
1414
information see `rustup help toolchain`
1515
-h, --help Print help
1616
"""

tests/suite/cli-ui/rustup/rustup_only_options_stdout.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,8 @@ The Rust toolchain installer
99
Usage: rustup[EXE] [OPTIONS] [+toolchain] [COMMAND]
1010
1111
Commands:
12-
...
1312
self Modify the rustup installation
1413
set Alter rustup settings
15-
completions Generate tab-completion scripts for your shell
1614
show Show the active and installed toolchains or profiles
1715
update Update Rust toolchains and rustup
1816
check Check for updates to Rust toolchains and rustup
@@ -24,6 +22,8 @@ Commands:
2422
run Run a command with an environment configured for a given toolchain
2523
which Display which binary will be run for a given command
2624
doc Open the documentation for the current toolchain
25+
...
26+
completions Generate tab-completion scripts for your shell
2727
help Print this message or the help of the given subcommand(s)
2828
2929
Arguments:

tests/suite/cli_misc.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -798,11 +798,11 @@ fn completion_bad_shell() {
798798
setup(&|config| {
799799
config.expect_err(
800800
&["rustup", "completions", "fake"],
801-
r#"error: invalid value 'fake' for '[shell]'"#,
801+
r#"error: invalid value 'fake' for '<SHELL>'"#,
802802
);
803803
config.expect_err(
804804
&["rustup", "completions", "fake", "cargo"],
805-
r#"error: invalid value 'fake' for '[shell]'"#,
805+
r#"error: invalid value 'fake' for '<SHELL>'"#,
806806
);
807807
});
808808
}
@@ -812,7 +812,7 @@ fn completion_bad_tool() {
812812
setup(&|config| {
813813
config.expect_err(
814814
&["rustup", "completions", "bash", "fake"],
815-
r#"error: invalid value 'fake' for '[command]'"#,
815+
r#"error: invalid value 'fake' for '[COMMAND]'"#,
816816
);
817817
});
818818
}

0 commit comments

Comments
 (0)