Skip to content

Commit 17f8088

Browse files
committed
Auto merge of #10753 - epage:clap32-deprecated, r=weihanglo
chore: Upgrade to clap 3.2 I decided to use cargo as a test case for upgrading to clap 3.2 prior to release. From the builder API's perspective, a lot has change. While the changelog summarizes it, the release announcement is still pending. In short, the API is now typed. You declare what type an `Arg` is and access it by that type. flags (both `is_present` and `occurrences_of`) are also now specified through `ArgAction` and the result gets stored like any other arg value. I made a `ArgMatchesExt::flag` and `command_prelude::flag` functions to make working with these easier. Now that clap exposes non-panicking variants of its functions, I switched from a "look before you leap" approach with `is_arg_valid` to a "better to ask forgiveness than permission" with checking the error variant. I decided to just make a convenience to swallow that error type. Not a fan of how loose things are but I think this will just be something we iterate on over time.
2 parents 6b8e192 + fc0ca1e commit 17f8088

35 files changed

+408
-410
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ toml_edit = { version = "0.14.3", features = ["serde", "easy", "perf"] }
6363
unicode-xid = "0.2.0"
6464
url = "2.2.2"
6565
walkdir = "2.2"
66-
clap = "3.1.0"
66+
clap = "3.2.1"
6767
unicode-width = "0.1.5"
6868
openssl = { version = '0.10.11', optional = true }
6969
im-rc = "15.0.0"

src/bin/cargo/cli.rs

Lines changed: 51 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ pub fn main(config: &mut Config) -> CliResult {
6060
// (appearing before the subcommand).
6161
let (expanded_args, global_args) = expand_aliases(config, args, vec![])?;
6262

63-
if expanded_args.value_of("unstable-features") == Some("help") {
63+
if expanded_args
64+
.get_one::<String>("unstable-features")
65+
.map(String::as_str)
66+
== Some("help")
67+
{
6468
let options = CliUnstable::help();
6569
let non_hidden_options: Vec<(String, String)> = options
6670
.iter()
@@ -112,20 +116,20 @@ Run with 'cargo -Z [FLAG] [SUBCOMMAND]'",
112116
return Ok(());
113117
}
114118

115-
let is_verbose = expanded_args.occurrences_of("verbose") > 0;
116-
if expanded_args.is_present("version") {
119+
let is_verbose = expanded_args.verbose() > 0;
120+
if expanded_args.flag("version") {
117121
let version = get_version_string(is_verbose);
118122
drop_print!(config, "{}", version);
119123
return Ok(());
120124
}
121125

122-
if let Some(code) = expanded_args.value_of("explain") {
126+
if let Some(code) = expanded_args.get_one::<String>("explain") {
123127
let mut procss = config.load_global_rustc(None)?.process();
124128
procss.arg("--explain").arg(code).exec()?;
125129
return Ok(());
126130
}
127131

128-
if expanded_args.is_present("list") {
132+
if expanded_args.flag("list") {
129133
drop_println!(config, "Installed Commands:");
130134
for (name, command) in list_commands(config) {
131135
let known_external_desc = KNOWN_EXTERNAL_COMMAND_DESCRIPTIONS.get(name.as_str());
@@ -262,7 +266,7 @@ fn expand_aliases(
262266
}
263267
(Some(_), None) => {
264268
// Command is built-in and is not conflicting with alias, but contains ignored values.
265-
if let Some(mut values) = args.values_of("") {
269+
if let Some(mut values) = args.get_many::<String>("") {
266270
config.shell().warn(format!(
267271
"trailing arguments after built-in command `{}` are ignored: `{}`",
268272
cmd,
@@ -287,11 +291,7 @@ For more information, see issue #10049 <https://github.com/rust-lang/cargo/issue
287291
))?;
288292
}
289293

290-
alias.extend(
291-
args.values_of("")
292-
.unwrap_or_default()
293-
.map(|s| s.to_string()),
294-
);
294+
alias.extend(args.get_many::<String>("").unwrap_or_default().cloned());
295295
// new_args strips out everything before the subcommand, so
296296
// capture those global options now.
297297
// Note that an alias to an external command will not receive
@@ -327,28 +327,26 @@ fn config_configure(
327327
subcommand_args: &ArgMatches,
328328
global_args: GlobalArgs,
329329
) -> CliResult {
330-
let arg_target_dir = &subcommand_args
331-
._is_valid_arg("target-dir")
332-
.then(|| subcommand_args.value_of_path("target-dir", config))
333-
.flatten();
334-
let verbose = global_args.verbose + args.occurrences_of("verbose") as u32;
330+
let arg_target_dir = &subcommand_args.value_of_path("target-dir", config);
331+
let verbose = global_args.verbose + args.verbose();
335332
// quiet is unusual because it is redefined in some subcommands in order
336333
// to provide custom help text.
337-
let quiet = args.is_present("quiet")
338-
|| subcommand_args.is_valid_and_present("quiet")
339-
|| global_args.quiet;
334+
let quiet = args.flag("quiet") || subcommand_args.flag("quiet") || global_args.quiet;
340335
let global_color = global_args.color; // Extract so it can take reference.
341-
let color = args.value_of("color").or_else(|| global_color.as_deref());
342-
let frozen = args.is_present("frozen") || global_args.frozen;
343-
let locked = args.is_present("locked") || global_args.locked;
344-
let offline = args.is_present("offline") || global_args.offline;
336+
let color = args
337+
.get_one::<String>("color")
338+
.map(String::as_str)
339+
.or_else(|| global_color.as_deref());
340+
let frozen = args.flag("frozen") || global_args.frozen;
341+
let locked = args.flag("locked") || global_args.locked;
342+
let offline = args.flag("offline") || global_args.offline;
345343
let mut unstable_flags = global_args.unstable_flags;
346-
if let Some(values) = args.values_of("unstable-features") {
347-
unstable_flags.extend(values.map(|s| s.to_string()));
344+
if let Some(values) = args.get_many::<String>("unstable-features") {
345+
unstable_flags.extend(values.cloned());
348346
}
349347
let mut config_args = global_args.config_args;
350-
if let Some(values) = args.values_of("config") {
351-
config_args.extend(values.map(|s| s.to_string()));
348+
if let Some(values) = args.get_many::<String>("config") {
349+
config_args.extend(values.cloned());
352350
}
353351
config.configure(
354352
verbose,
@@ -370,7 +368,12 @@ fn execute_subcommand(config: &mut Config, cmd: &str, subcommand_args: &ArgMatch
370368
}
371369

372370
let mut ext_args: Vec<&str> = vec![cmd];
373-
ext_args.extend(subcommand_args.values_of("").unwrap_or_default());
371+
ext_args.extend(
372+
subcommand_args
373+
.get_many::<String>("")
374+
.unwrap_or_default()
375+
.map(String::as_str),
376+
);
374377
super::execute_external_subcommand(config, cmd, &ext_args)
375378
}
376379

@@ -389,19 +392,21 @@ struct GlobalArgs {
389392
impl GlobalArgs {
390393
fn new(args: &ArgMatches) -> GlobalArgs {
391394
GlobalArgs {
392-
verbose: args.occurrences_of("verbose") as u32,
393-
quiet: args.is_present("quiet"),
394-
color: args.value_of("color").map(|s| s.to_string()),
395-
frozen: args.is_present("frozen"),
396-
locked: args.is_present("locked"),
397-
offline: args.is_present("offline"),
395+
verbose: args.verbose(),
396+
quiet: args.flag("quiet"),
397+
color: args.get_one::<String>("color").cloned(),
398+
frozen: args.flag("frozen"),
399+
locked: args.flag("locked"),
400+
offline: args.flag("offline"),
398401
unstable_flags: args
399-
.values_of_lossy("unstable-features")
400-
.unwrap_or_default(),
402+
.get_many::<String>("unstable-features")
403+
.unwrap_or_default()
404+
.cloned()
405+
.collect(),
401406
config_args: args
402-
.values_of("config")
407+
.get_many::<String>("config")
403408
.unwrap_or_default()
404-
.map(|s| s.to_string())
409+
.cloned()
405410
.collect(),
406411
}
407412
}
@@ -416,7 +421,7 @@ fn cli() -> App {
416421
};
417422
App::new("cargo")
418423
.allow_external_subcommands(true)
419-
.setting(AppSettings::DeriveDisplayOrder | AppSettings::NoAutoVersion)
424+
.setting(AppSettings::DeriveDisplayOrder)
420425
// Doesn't mix well with our list of common cargo commands. See clap-rs/clap#3108 for
421426
// opening clap up to allow us to style our help template
422427
.disable_colored_help(true)
@@ -450,16 +455,16 @@ Some common cargo commands are (see all commands with --list):
450455
451456
See 'cargo help <command>' for more information on a specific command.\n",
452457
)
453-
.arg(opt("version", "Print version info and exit").short('V'))
454-
.arg(opt("list", "List installed commands"))
458+
.arg(flag("version", "Print version info and exit").short('V'))
459+
.arg(flag("list", "List installed commands"))
455460
.arg(opt("explain", "Run `rustc --explain CODE`").value_name("CODE"))
456461
.arg(
457462
opt(
458463
"verbose",
459464
"Use verbose output (-vv very verbose/build.rs output)",
460465
)
461466
.short('v')
462-
.multiple_occurrences(true)
467+
.action(ArgAction::Count)
463468
.global(true),
464469
)
465470
.arg_quiet()
@@ -468,9 +473,9 @@ See 'cargo help <command>' for more information on a specific command.\n",
468473
.value_name("WHEN")
469474
.global(true),
470475
)
471-
.arg(opt("frozen", "Require Cargo.lock and cache are up to date").global(true))
472-
.arg(opt("locked", "Require Cargo.lock is up to date").global(true))
473-
.arg(opt("offline", "Run without accessing the network").global(true))
476+
.arg(flag("frozen", "Require Cargo.lock and cache are up to date").global(true))
477+
.arg(flag("locked", "Require Cargo.lock is up to date").global(true))
478+
.arg(flag("offline", "Run without accessing the network").global(true))
474479
.arg(
475480
multi_opt(
476481
"config",
@@ -484,7 +489,7 @@ See 'cargo help <command>' for more information on a specific command.\n",
484489
.help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
485490
.short('Z')
486491
.value_name("FLAG")
487-
.multiple_occurrences(true)
492+
.action(ArgAction::Append)
488493
.global(true),
489494
)
490495
.subcommands(commands::builtin())

src/bin/cargo/commands/add.rs

Lines changed: 32 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub fn cli() -> clap::Command<'static> {
2727
clap::Arg::new("crates")
2828
.takes_value(true)
2929
.value_name("DEP_ID")
30-
.multiple_occurrences(true)
30+
.multiple_values(true)
3131
.help("Reference to a package to add as a dependency")
3232
.long_help(
3333
"Reference to a package to add as a dependency
@@ -37,30 +37,26 @@ You can reference a package by:
3737
- `<name>@<version-req>`, like `cargo add serde@1` or `cargo add serde@=1.0.38`"
3838
)
3939
.group("selected"),
40-
clap::Arg::new("no-default-features")
41-
.long("no-default-features")
42-
.help("Disable the default features"),
43-
clap::Arg::new("default-features")
44-
.long("default-features")
45-
.help("Re-enable the default features")
40+
flag("no-default-features",
41+
"Disable the default features"),
42+
flag("default-features",
43+
"Re-enable the default features")
4644
.overrides_with("no-default-features"),
4745
clap::Arg::new("features")
4846
.short('F')
4947
.long("features")
5048
.takes_value(true)
5149
.value_name("FEATURES")
52-
.multiple_occurrences(true)
50+
.action(ArgAction::Append)
5351
.help("Space or comma separated list of features to activate"),
54-
clap::Arg::new("optional")
55-
.long("optional")
56-
.help("Mark the dependency as optional")
52+
flag("optional",
53+
"Mark the dependency as optional")
5754
.long_help("Mark the dependency as optional
5855
5956
The package name will be exposed as feature of your crate.")
6057
.conflicts_with("dev"),
61-
clap::Arg::new("no-optional")
62-
.long("no-optional")
63-
.help("Mark the dependency as required")
58+
flag("no-optional",
59+
"Mark the dependency as required")
6460
.long_help("Mark the dependency as required
6561
6662
The package will be removed from your features.")
@@ -141,18 +137,16 @@ This is the catch all, handling hashes to named references in remote repositorie
141137
])
142138
.next_help_heading("SECTION")
143139
.args([
144-
clap::Arg::new("dev")
145-
.long("dev")
146-
.help("Add as development dependency")
140+
flag("dev",
141+
"Add as development dependency")
147142
.long_help("Add as development dependency
148143
149144
Dev-dependencies are not used when compiling a package for building, but are used for compiling tests, examples, and benchmarks.
150145
151146
These dependencies are not propagated to other packages which depend on this package.")
152147
.group("section"),
153-
clap::Arg::new("build")
154-
.long("build")
155-
.help("Add as build dependency")
148+
flag("build",
149+
"Add as build dependency")
156150
.long_help("Add as build dependency
157151
158152
Build-dependencies are the only dependencies available for use by build scripts (`build.rs` files).")
@@ -161,13 +155,13 @@ Build-dependencies are the only dependencies available for use by build scripts
161155
.long("target")
162156
.takes_value(true)
163157
.value_name("TARGET")
164-
.forbid_empty_values(true)
158+
.value_parser(clap::builder::NonEmptyStringValueParser::new())
165159
.help("Add as dependency to the given target platform")
166160
])
167161
}
168162

169163
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
170-
let dry_run = args.is_present("dry-run");
164+
let dry_run = args.dry_run();
171165
let section = parse_section(args);
172166

173167
let ws = args.workspace(config)?;
@@ -206,21 +200,21 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
206200
}
207201

208202
fn parse_dependencies(config: &Config, matches: &ArgMatches) -> CargoResult<Vec<DepOp>> {
209-
let path = matches.value_of("path");
210-
let git = matches.value_of("git");
211-
let branch = matches.value_of("branch");
212-
let rev = matches.value_of("rev");
213-
let tag = matches.value_of("tag");
214-
let rename = matches.value_of("rename");
203+
let path = matches.get_one::<String>("path");
204+
let git = matches.get_one::<String>("git");
205+
let branch = matches.get_one::<String>("branch");
206+
let rev = matches.get_one::<String>("rev");
207+
let tag = matches.get_one::<String>("tag");
208+
let rename = matches.get_one::<String>("rename");
215209
let registry = matches.registry(config)?;
216210
let default_features = default_features(matches);
217211
let optional = optional(matches);
218212

219213
let mut crates = matches
220-
.values_of("crates")
214+
.get_many::<String>("crates")
221215
.into_iter()
222216
.flatten()
223-
.map(|c| (Some(String::from(c)), None))
217+
.map(|c| (Some(c.clone()), None))
224218
.collect::<IndexMap<_, _>>();
225219
let mut infer_crate_name = false;
226220
if crates.is_empty() {
@@ -232,9 +226,10 @@ fn parse_dependencies(config: &Config, matches: &ArgMatches) -> CargoResult<Vec<
232226
}
233227
}
234228
for feature in matches
235-
.values_of("features")
229+
.get_many::<String>("features")
236230
.into_iter()
237231
.flatten()
232+
.map(String::as_str)
238233
.flat_map(parse_feature)
239234
{
240235
let parsed_value = FeatureValue::new(InternedString::new(feature));
@@ -310,16 +305,13 @@ fn parse_dependencies(config: &Config, matches: &ArgMatches) -> CargoResult<Vec<
310305

311306
fn default_features(matches: &ArgMatches) -> Option<bool> {
312307
resolve_bool_arg(
313-
matches.is_present("default-features"),
314-
matches.is_present("no-default-features"),
308+
matches.flag("default-features"),
309+
matches.flag("no-default-features"),
315310
)
316311
}
317312

318313
fn optional(matches: &ArgMatches) -> Option<bool> {
319-
resolve_bool_arg(
320-
matches.is_present("optional"),
321-
matches.is_present("no-optional"),
322-
)
314+
resolve_bool_arg(matches.flag("optional"), matches.flag("no-optional"))
323315
}
324316

325317
fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
@@ -332,17 +324,17 @@ fn resolve_bool_arg(yes: bool, no: bool) -> Option<bool> {
332324
}
333325

334326
fn parse_section(matches: &ArgMatches) -> DepTable {
335-
let kind = if matches.is_present("dev") {
327+
let kind = if matches.flag("dev") {
336328
DepKind::Development
337-
} else if matches.is_present("build") {
329+
} else if matches.flag("build") {
338330
DepKind::Build
339331
} else {
340332
DepKind::Normal
341333
};
342334

343335
let mut table = DepTable::new().set_kind(kind);
344336

345-
if let Some(target) = matches.value_of("target") {
337+
if let Some(target) = matches.get_one::<String>("target") {
346338
assert!(!target.is_empty(), "Target specification may not be empty");
347339
table = table.set_target(target);
348340
}

0 commit comments

Comments
 (0)