Skip to content

Commit e250bd5

Browse files
committed
refactor(cli): rewrite rustup (man|completions) with clap-derive
1 parent 4f03a74 commit e250bd5

8 files changed

+52
-90
lines changed

src/cli/rustup_mode.rs

Lines changed: 35 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::str::FromStr;
55

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

211228
#[derive(Debug, Subcommand)]
@@ -504,6 +521,11 @@ impl Rustup {
504521
topic,
505522
page,
506523
} => 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+
}
507529
}
508530
}
509531
}
@@ -582,11 +604,9 @@ pub fn main() -> Result<utils::ExitCode> {
582604
(
583605
"dump-testament" | "show" | "update" | "install" | "uninstall" | "toolchain"
584606
| "check" | "default" | "target" | "component" | "override" | "run" | "which"
585-
| "doc",
607+
| "doc" | "man" | "completions",
586608
_,
587609
) => Rustup::from_arg_matches(&matches)?.dispatch(cfg)?,
588-
#[cfg(not(windows))]
589-
("man", m) => man(cfg, m)?,
590610
("self", c) => match c.subcommand() {
591611
Some(s) => match s {
592612
("update", _) => self_update::update(cfg)?,
@@ -604,18 +624,6 @@ pub fn main() -> Result<utils::ExitCode> {
604624
},
605625
None => unreachable!(),
606626
},
607-
("completions", c) => {
608-
if let Some(&shell) = c.get_one::<Shell>("shell") {
609-
output_completion_script(
610-
shell,
611-
c.get_one::<CompletionCommand>("command")
612-
.copied()
613-
.unwrap_or(CompletionCommand::Rustup),
614-
)?
615-
} else {
616-
unreachable!()
617-
}
618-
}
619627
_ => unreachable!(),
620628
},
621629
None => {
@@ -626,7 +634,7 @@ pub fn main() -> Result<utils::ExitCode> {
626634
}
627635

628636
pub(crate) fn cli() -> Command {
629-
let mut app = Command::new("rustup")
637+
let app = Command::new("rustup")
630638
.version(common::version())
631639
.about("The Rust toolchain installer")
632640
.before_help(format!("rustup {}", common::version()))
@@ -654,24 +662,7 @@ pub(crate) fn cli() -> Command {
654662
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}")))
655663
}
656664
}),
657-
);
658-
659-
if cfg!(not(target_os = "windows")) {
660-
app = app.subcommand(
661-
Command::new("man")
662-
.about("View the man page for a given command")
663-
.arg(Arg::new("command").required(true))
664-
.arg(
665-
Arg::new("toolchain")
666-
.help(OFFICIAL_TOOLCHAIN_ARG_HELP)
667-
.long("toolchain")
668-
.num_args(1)
669-
.value_parser(partial_toolchain_desc_parser),
670-
),
671-
);
672-
}
673-
674-
app = app
665+
)
675666
.subcommand(
676667
Command::new("self")
677668
.about("Modify the rustup installation")
@@ -717,18 +708,6 @@ pub(crate) fn cli() -> Command {
717708
.default_value(SelfUpdateMode::default_mode()),
718709
),
719710
),
720-
)
721-
.subcommand(
722-
Command::new("completions")
723-
.about("Generate tab-completion scripts for your shell")
724-
.after_help(COMPLETIONS_HELP)
725-
.arg_required_else_help(true)
726-
.arg(Arg::new("shell").value_parser(EnumValueParser::<Shell>::new()))
727-
.arg(
728-
Arg::new("command")
729-
.value_parser(EnumValueParser::<CompletionCommand>::new())
730-
.default_missing_value("rustup"),
731-
),
732711
);
733712

734713
RustupSubcmd::augment_subcommands(app)
@@ -1291,16 +1270,6 @@ fn component_remove(
12911270
Ok(utils::ExitCode(0))
12921271
}
12931272

1294-
// Make *sure* only to use this for a subcommand whose "toolchain" argument
1295-
// has .value_parser(partial_toolchain_desc_parser), or it will panic.
1296-
// FIXME: Delete this.
1297-
fn explicit_desc_or_dir_toolchain_old<'a>(cfg: &'a Cfg, m: &ArgMatches) -> Result<Toolchain<'a>> {
1298-
let toolchain = m
1299-
.get_one::<PartialToolchainDesc>("toolchain")
1300-
.map(Into::into);
1301-
explicit_or_dir_toolchain2(cfg, toolchain)
1302-
}
1303-
13041273
fn explicit_desc_or_dir_toolchain(
13051274
cfg: &Cfg,
13061275
toolchain: Option<PartialToolchainDesc>,
@@ -1546,12 +1515,14 @@ fn doc(
15461515
}
15471516

15481517
#[cfg(not(windows))]
1549-
fn man(cfg: &Cfg, m: &ArgMatches) -> Result<utils::ExitCode> {
1518+
fn man(
1519+
cfg: &Cfg,
1520+
command: &str,
1521+
toolchain: Option<PartialToolchainDesc>,
1522+
) -> Result<utils::ExitCode> {
15501523
use crate::currentprocess::varsource::VarSource;
15511524

1552-
let command = m.get_one::<String>("command").unwrap();
1553-
1554-
let toolchain = explicit_desc_or_dir_toolchain_old(cfg, m)?;
1525+
let toolchain = explicit_desc_or_dir_toolchain(cfg, toolchain)?;
15551526
let mut path = toolchain.path().to_path_buf();
15561527
path.push("share");
15571528
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
@@ -863,11 +863,11 @@ fn completion_bad_shell() {
863863
setup(&|config| {
864864
config.expect_err(
865865
&["rustup", "completions", "fake"],
866-
r#"error: invalid value 'fake' for '[shell]'"#,
866+
r#"error: invalid value 'fake' for '<SHELL>'"#,
867867
);
868868
config.expect_err(
869869
&["rustup", "completions", "fake", "cargo"],
870-
r#"error: invalid value 'fake' for '[shell]'"#,
870+
r#"error: invalid value 'fake' for '<SHELL>'"#,
871871
);
872872
});
873873
}
@@ -877,7 +877,7 @@ fn completion_bad_tool() {
877877
setup(&|config| {
878878
config.expect_err(
879879
&["rustup", "completions", "bash", "fake"],
880-
r#"error: invalid value 'fake' for '[command]'"#,
880+
r#"error: invalid value 'fake' for '[COMMAND]'"#,
881881
);
882882
});
883883
}

0 commit comments

Comments
 (0)