diff --git a/Cargo.toml b/Cargo.toml index 20dfd540f0b..3435686adc0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -61,7 +61,7 @@ toml = "0.5.7" unicode-xid = "0.2.0" url = "2.2.2" walkdir = "2.2" -clap = "2.34.0" +clap = "3.0.5" unicode-width = "0.1.5" openssl = { version = '0.10.11', optional = true } im-rc = "15.0.0" diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs index cd1fea8f1f4..1db83f1f193 100644 --- a/src/bin/cargo/cli.rs +++ b/src/bin/cargo/cli.rs @@ -35,8 +35,8 @@ pub fn main(config: &mut Config) -> CliResult { Err(e) => { if e.kind == clap::ErrorKind::UnrecognizedSubcommand { // An unrecognized subcommand might be an external subcommand. - let cmd = &e.info.as_ref().unwrap()[0].to_owned(); - return super::execute_external_subcommand(config, cmd, &[cmd, "--help"]) + let cmd = e.info[0].clone(); + return super::execute_external_subcommand(config, &cmd, &[&cmd, "--help"]) .map_err(|_| e.into()); } else { return Err(e.into()); @@ -152,7 +152,7 @@ Run with 'cargo -Z [FLAG] [SUBCOMMAND]'", } let (cmd, subcommand_args) = match expanded_args.subcommand() { - (cmd, Some(args)) => (cmd, args), + Some((cmd, args)) => (cmd, args), _ => { // No subcommand provided. cli().print_help()?; @@ -236,10 +236,10 @@ fn add_ssl(version_string: &mut String) { fn expand_aliases( config: &mut Config, - args: ArgMatches<'static>, + args: ArgMatches, mut already_expanded: Vec, -) -> Result<(ArgMatches<'static>, GlobalArgs), CliError> { - if let (cmd, Some(args)) = args.subcommand() { +) -> Result<(ArgMatches, GlobalArgs), CliError> { + if let Some((cmd, args)) = args.subcommand() { match ( commands::builtin_exec(cmd), super::aliased_command(config, cmd)?, @@ -292,7 +292,7 @@ For more information, see issue #10049 , - subcommand_args: &ArgMatches<'_>, + args: &ArgMatches, + subcommand_args: &ArgMatches, global_args: GlobalArgs, ) -> CliResult { - let arg_target_dir = &subcommand_args.value_of_path("target-dir", config); + let arg_target_dir = &subcommand_args + ._is_valid_arg("target-dir") + .then(|| subcommand_args.value_of_path("target-dir", config)) + .flatten(); let verbose = global_args.verbose + args.occurrences_of("verbose") as u32; // quiet is unusual because it is redefined in some subcommands in order // to provide custom help text. - let quiet = - args.is_present("quiet") || subcommand_args.is_present("quiet") || global_args.quiet; + let quiet = args.is_present("quiet") + || subcommand_args.is_valid_and_present("quiet") + || global_args.quiet; let global_color = global_args.color; // Extract so it can take reference. let color = args.value_of("color").or_else(|| global_color.as_deref()); let frozen = args.is_present("frozen") || global_args.frozen; @@ -353,11 +357,7 @@ fn config_configure( Ok(()) } -fn execute_subcommand( - config: &mut Config, - cmd: &str, - subcommand_args: &ArgMatches<'_>, -) -> CliResult { +fn execute_subcommand(config: &mut Config, cmd: &str, subcommand_args: &ArgMatches) -> CliResult { if let Some(exec) = commands::builtin_exec(cmd) { return exec(config, subcommand_args); } @@ -380,7 +380,7 @@ struct GlobalArgs { } impl GlobalArgs { - fn new(args: &ArgMatches<'_>) -> GlobalArgs { + fn new(args: &ArgMatches) -> GlobalArgs { GlobalArgs { verbose: args.occurrences_of("verbose") as u32, quiet: args.is_present("quiet"), @@ -411,9 +411,12 @@ fn cli() -> App { .settings(&[ AppSettings::UnifiedHelpMessage, AppSettings::DeriveDisplayOrder, - AppSettings::VersionlessSubcommands, AppSettings::AllowExternalSubcommands, + AppSettings::NoAutoVersion, ]) + // Doesn't mix well with our list of common cargo commands. See clap-rs/clap#3108 for + // opening clap up to allow us to style our help template + .global_setting(AppSettings::DisableColoredHelp) .usage(usage) .template( "\ @@ -423,7 +426,7 @@ USAGE: {usage} OPTIONS: -{unified} +{options} Some common cargo commands are (see all commands with --list): build, b Compile the current package @@ -443,7 +446,7 @@ Some common cargo commands are (see all commands with --list): See 'cargo help ' for more information on a specific command.\n", ) - .arg(opt("version", "Print version info and exit").short("V")) + .arg(opt("version", "Print version info and exit").short('V')) .arg(opt("list", "List installed commands")) .arg(opt("explain", "Run `rustc --explain CODE`").value_name("CODE")) .arg( @@ -451,8 +454,8 @@ See 'cargo help ' for more information on a specific command.\n", "verbose", "Use verbose output (-vv very verbose/build.rs output)", ) - .short("v") - .multiple(true) + .short('v') + .multiple_occurrences(true) .global(true), ) .arg_quiet() @@ -475,7 +478,7 @@ See 'cargo help ' for more information on a specific command.\n", .arg( Arg::with_name("unstable-features") .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details") - .short("Z") + .short('Z') .value_name("FLAG") .multiple(true) .number_of_values(1) @@ -483,3 +486,8 @@ See 'cargo help ' for more information on a specific command.\n", ) .subcommands(commands::builtin()) } + +#[test] +fn verify_cli() { + cli().debug_assert(); +} diff --git a/src/bin/cargo/commands/bench.rs b/src/bin/cargo/commands/bench.rs index 39ec1be2253..d81f1f8ab60 100644 --- a/src/bin/cargo/commands/bench.rs +++ b/src/bin/cargo/commands/bench.rs @@ -50,7 +50,7 @@ pub fn cli() -> App { .after_help("Run `cargo help bench` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let mut compile_opts = args.compile_options( config, diff --git a/src/bin/cargo/commands/build.rs b/src/bin/cargo/commands/build.rs index ad6705119a9..367cad83884 100644 --- a/src/bin/cargo/commands/build.rs +++ b/src/bin/cargo/commands/build.rs @@ -47,7 +47,7 @@ pub fn cli() -> App { .after_help("Run `cargo help build` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let mut compile_opts = args.compile_options( config, diff --git a/src/bin/cargo/commands/check.rs b/src/bin/cargo/commands/check.rs index 3be146c6d26..07b98be707a 100644 --- a/src/bin/cargo/commands/check.rs +++ b/src/bin/cargo/commands/check.rs @@ -39,7 +39,7 @@ pub fn cli() -> App { .after_help("Run `cargo help check` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; // This is a legacy behavior that causes `cargo check` to pass `--test`. let test = matches!(args.value_of("profile"), Some("test")); diff --git a/src/bin/cargo/commands/clean.rs b/src/bin/cargo/commands/clean.rs index c966c65f13b..f758981b1ba 100644 --- a/src/bin/cargo/commands/clean.rs +++ b/src/bin/cargo/commands/clean.rs @@ -17,7 +17,7 @@ pub fn cli() -> App { .after_help("Run `cargo help clean` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; if args.is_present_with_zero_values("package") { diff --git a/src/bin/cargo/commands/config.rs b/src/bin/cargo/commands/config.rs index 61938dfc2ca..78613696223 100644 --- a/src/bin/cargo/commands/config.rs +++ b/src/bin/cargo/commands/config.rs @@ -26,12 +26,12 @@ pub fn cli() -> App { ) } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { config .cli_unstable() .fail_if_stable_command(config, "config", 9301)?; match args.subcommand() { - ("get", Some(args)) => { + Some(("get", args)) => { let opts = cargo_config::GetOptions { key: args.value_of("key"), format: args.value_of("format").unwrap().parse()?, @@ -40,8 +40,11 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { }; cargo_config::get(config, &opts)?; } - (cmd, _) => { - panic!("unexpected command `{}`", cmd) + Some((cmd, _)) => { + unreachable!("unexpected command {}", cmd) + } + None => { + unreachable!("unexpected command") } } Ok(()) diff --git a/src/bin/cargo/commands/doc.rs b/src/bin/cargo/commands/doc.rs index 21d561394ca..9833594493a 100644 --- a/src/bin/cargo/commands/doc.rs +++ b/src/bin/cargo/commands/doc.rs @@ -39,7 +39,7 @@ pub fn cli() -> App { .after_help("Run `cargo help doc` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let mode = CompileMode::Doc { deps: !args.is_present("no-deps"), diff --git a/src/bin/cargo/commands/fetch.rs b/src/bin/cargo/commands/fetch.rs index ff3fcbec5da..0106c0f1e84 100644 --- a/src/bin/cargo/commands/fetch.rs +++ b/src/bin/cargo/commands/fetch.rs @@ -12,7 +12,7 @@ pub fn cli() -> App { .after_help("Run `cargo help fetch` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let opts = FetchOptions { diff --git a/src/bin/cargo/commands/fix.rs b/src/bin/cargo/commands/fix.rs index 85cf955e433..5463e12df68 100644 --- a/src/bin/cargo/commands/fix.rs +++ b/src/bin/cargo/commands/fix.rs @@ -65,7 +65,7 @@ pub fn cli() -> App { .after_help("Run `cargo help fix` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; // This is a legacy behavior that causes `cargo fix` to pass `--test`. let test = matches!(args.value_of("profile"), Some("test")); diff --git a/src/bin/cargo/commands/generate_lockfile.rs b/src/bin/cargo/commands/generate_lockfile.rs index 1eebdbd418c..b20d8616a1f 100644 --- a/src/bin/cargo/commands/generate_lockfile.rs +++ b/src/bin/cargo/commands/generate_lockfile.rs @@ -10,7 +10,7 @@ pub fn cli() -> App { .after_help("Run `cargo help generate-lockfile` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; ops::generate_lockfile(&ws)?; Ok(()) diff --git a/src/bin/cargo/commands/git_checkout.rs b/src/bin/cargo/commands/git_checkout.rs index aae435a5196..3cc0701ffa2 100644 --- a/src/bin/cargo/commands/git_checkout.rs +++ b/src/bin/cargo/commands/git_checkout.rs @@ -9,6 +9,6 @@ pub fn cli() -> App { .help(REMOVED) } -pub fn exec(_config: &mut Config, _args: &ArgMatches<'_>) -> CliResult { +pub fn exec(_config: &mut Config, _args: &ArgMatches) -> CliResult { Err(anyhow::format_err!(REMOVED).into()) } diff --git a/src/bin/cargo/commands/init.rs b/src/bin/cargo/commands/init.rs index 257d30756f5..3bb957f3f01 100644 --- a/src/bin/cargo/commands/init.rs +++ b/src/bin/cargo/commands/init.rs @@ -12,7 +12,7 @@ pub fn cli() -> App { .after_help("Run `cargo help init` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let opts = args.new_options(config)?; let project_kind = ops::init(&opts, config)?; config diff --git a/src/bin/cargo/commands/install.rs b/src/bin/cargo/commands/install.rs index 79be166e4ee..fb8db412104 100644 --- a/src/bin/cargo/commands/install.rs +++ b/src/bin/cargo/commands/install.rs @@ -45,7 +45,7 @@ pub fn cli() -> App { "list all installed packages and their versions", )) .arg_jobs() - .arg(opt("force", "Force overwriting existing crates or binaries").short("f")) + .arg(opt("force", "Force overwriting existing crates or binaries").short('f')) .arg(opt("no-track", "Do not save tracking information")) .arg_features() .arg_profile("Install artifacts with the specified profile") @@ -75,7 +75,7 @@ pub fn cli() -> App { .after_help("Run `cargo help install` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { if let Some(path) = args.value_of_path("path", config) { config.reload_rooted_at(path)?; } else { diff --git a/src/bin/cargo/commands/locate_project.rs b/src/bin/cargo/commands/locate_project.rs index a045e14548b..673f69903c2 100644 --- a/src/bin/cargo/commands/locate_project.rs +++ b/src/bin/cargo/commands/locate_project.rs @@ -24,7 +24,7 @@ pub struct ProjectLocation<'a> { root: &'a str, } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let root_manifest; let workspace; let root = match WhatToFind::parse(args) { @@ -64,7 +64,7 @@ enum WhatToFind { } impl WhatToFind { - fn parse(args: &ArgMatches<'_>) -> Self { + fn parse(args: &ArgMatches) -> Self { if args.is_present("workspace") { WhatToFind::Workspace } else { @@ -79,7 +79,7 @@ enum MessageFormat { } impl MessageFormat { - fn parse(args: &ArgMatches<'_>) -> CargoResult { + fn parse(args: &ArgMatches) -> CargoResult { let fmt = match args.value_of("message-format") { Some(fmt) => fmt, None => return Ok(MessageFormat::Json), diff --git a/src/bin/cargo/commands/login.rs b/src/bin/cargo/commands/login.rs index 0f51d52969d..3eea2bb12b1 100644 --- a/src/bin/cargo/commands/login.rs +++ b/src/bin/cargo/commands/login.rs @@ -14,7 +14,7 @@ pub fn cli() -> App { .after_help("Run `cargo help login` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { ops::registry_login( config, args.value_of("token").map(String::from), diff --git a/src/bin/cargo/commands/logout.rs b/src/bin/cargo/commands/logout.rs index 4ce9498e7e1..518247e8b85 100644 --- a/src/bin/cargo/commands/logout.rs +++ b/src/bin/cargo/commands/logout.rs @@ -9,7 +9,7 @@ pub fn cli() -> App { .after_help("Run `cargo help logout` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { if !config.cli_unstable().credential_process { config .cli_unstable() diff --git a/src/bin/cargo/commands/metadata.rs b/src/bin/cargo/commands/metadata.rs index 66e856b48e7..6caa7ab946a 100644 --- a/src/bin/cargo/commands/metadata.rs +++ b/src/bin/cargo/commands/metadata.rs @@ -29,7 +29,7 @@ pub fn cli() -> App { .after_help("Run `cargo help metadata` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let version = match args.value_of("format-version") { diff --git a/src/bin/cargo/commands/mod.rs b/src/bin/cargo/commands/mod.rs index 838902da3cf..7d77388f5c2 100644 --- a/src/bin/cargo/commands/mod.rs +++ b/src/bin/cargo/commands/mod.rs @@ -40,7 +40,7 @@ pub fn builtin() -> Vec { ] } -pub fn builtin_exec(cmd: &str) -> Option) -> CliResult> { +pub fn builtin_exec(cmd: &str) -> Option CliResult> { let f = match cmd { "bench" => bench::exec, "build" => build::exec, diff --git a/src/bin/cargo/commands/new.rs b/src/bin/cargo/commands/new.rs index c1828fd8637..2474bcc0ef4 100644 --- a/src/bin/cargo/commands/new.rs +++ b/src/bin/cargo/commands/new.rs @@ -12,7 +12,7 @@ pub fn cli() -> App { .after_help("Run `cargo help new` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let opts = args.new_options(config)?; ops::new(&opts, config)?; diff --git a/src/bin/cargo/commands/owner.rs b/src/bin/cargo/commands/owner.rs index fd3d6169b29..1ece0845322 100644 --- a/src/bin/cargo/commands/owner.rs +++ b/src/bin/cargo/commands/owner.rs @@ -13,7 +13,7 @@ pub fn cli() -> App { "LOGIN", "Name of a user or team to invite as an owner", ) - .short("a"), + .short('a'), ) .arg( multi_opt( @@ -21,16 +21,16 @@ pub fn cli() -> App { "LOGIN", "Name of a user or team to remove as an owner", ) - .short("r"), + .short('r'), ) - .arg(opt("list", "List owners of a crate").short("l")) + .arg(opt("list", "List owners of a crate").short('l')) .arg(opt("index", "Registry index to modify owners for").value_name("INDEX")) .arg(opt("token", "API token to use when authenticating").value_name("TOKEN")) .arg(opt("registry", "Registry to use").value_name("REGISTRY")) .after_help("Run `cargo help owner` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { config.load_credentials()?; let registry = args.registry(config)?; diff --git a/src/bin/cargo/commands/package.rs b/src/bin/cargo/commands/package.rs index 875a0b0ab54..5584052e909 100644 --- a/src/bin/cargo/commands/package.rs +++ b/src/bin/cargo/commands/package.rs @@ -11,7 +11,7 @@ pub fn cli() -> App { "list", "Print files included in a package without making one", ) - .short("l"), + .short('l'), ) .arg(opt( "no-verify", @@ -38,7 +38,7 @@ pub fn cli() -> App { .after_help("Run `cargo help package` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let specs = args.packages_from_flags()?; diff --git a/src/bin/cargo/commands/pkgid.rs b/src/bin/cargo/commands/pkgid.rs index 5bf7d8c2219..b5f7925aae2 100644 --- a/src/bin/cargo/commands/pkgid.rs +++ b/src/bin/cargo/commands/pkgid.rs @@ -13,7 +13,7 @@ pub fn cli() -> App { .after_help("Run `cargo help pkgid` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; if args.is_present_with_zero_values("package") { print_available_packages(&ws)? diff --git a/src/bin/cargo/commands/publish.rs b/src/bin/cargo/commands/publish.rs index 869fbccdf27..f1cdcc2c19d 100644 --- a/src/bin/cargo/commands/publish.rs +++ b/src/bin/cargo/commands/publish.rs @@ -27,7 +27,7 @@ pub fn cli() -> App { .after_help("Run `cargo help publish` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { config.load_credentials()?; let registry = args.registry(config)?; diff --git a/src/bin/cargo/commands/read_manifest.rs b/src/bin/cargo/commands/read_manifest.rs index 86867152c93..186091a35ff 100644 --- a/src/bin/cargo/commands/read_manifest.rs +++ b/src/bin/cargo/commands/read_manifest.rs @@ -13,7 +13,7 @@ Deprecated, use `cargo metadata --no-deps` instead.\ .arg_manifest_path() } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; config .shell() diff --git a/src/bin/cargo/commands/report.rs b/src/bin/cargo/commands/report.rs index 34a79bb8f39..0135ef90afb 100644 --- a/src/bin/cargo/commands/report.rs +++ b/src/bin/cargo/commands/report.rs @@ -22,14 +22,19 @@ pub fn cli() -> App { ) } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { match args.subcommand() { - ("future-incompatibilities", Some(args)) => report_future_incompatibilies(config, args), - (cmd, _) => panic!("unexpected command `{}`", cmd), + Some(("future-incompatibilities", args)) => report_future_incompatibilies(config, args), + Some((cmd, _)) => { + unreachable!("unexpected command {}", cmd) + } + None => { + unreachable!("unexpected command") + } } } -fn report_future_incompatibilies(config: &Config, args: &ArgMatches<'_>) -> CliResult { +fn report_future_incompatibilies(config: &Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let reports = OnDiskReports::load(&ws)?; let id = args diff --git a/src/bin/cargo/commands/run.rs b/src/bin/cargo/commands/run.rs index 75f317c94b6..a42f49ae562 100644 --- a/src/bin/cargo/commands/run.rs +++ b/src/bin/cargo/commands/run.rs @@ -11,7 +11,11 @@ pub fn cli() -> App { .setting(AppSettings::TrailingVarArg) .about("Run a binary or example of the local package") .arg_quiet() - .arg(Arg::with_name("args").multiple(true)) + .arg( + Arg::with_name("args") + .allow_invalid_utf8(true) + .multiple(true), + ) .arg_targets_bin_example( "Name of the bin target to run", "Name of the example target to run", @@ -30,7 +34,7 @@ pub fn cli() -> App { .after_help("Run `cargo help run` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let mut compile_opts = args.compile_options( diff --git a/src/bin/cargo/commands/rustc.rs b/src/bin/cargo/commands/rustc.rs index 750505dc04e..0b6401fcd1b 100644 --- a/src/bin/cargo/commands/rustc.rs +++ b/src/bin/cargo/commands/rustc.rs @@ -50,7 +50,7 @@ pub fn cli() -> App { .after_help("Run `cargo help rustc` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; // This is a legacy behavior that changes the behavior based on the profile. // If we want to support this more formally, I think adding a --mode flag diff --git a/src/bin/cargo/commands/rustdoc.rs b/src/bin/cargo/commands/rustdoc.rs index a6a32440ccb..246e3382210 100644 --- a/src/bin/cargo/commands/rustdoc.rs +++ b/src/bin/cargo/commands/rustdoc.rs @@ -38,7 +38,7 @@ pub fn cli() -> App { .after_help("Run `cargo help rustdoc` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let mut compile_opts = args.compile_options_for_single_package( config, diff --git a/src/bin/cargo/commands/search.rs b/src/bin/cargo/commands/search.rs index f3f1d04679d..0c8d172e9ad 100644 --- a/src/bin/cargo/commands/search.rs +++ b/src/bin/cargo/commands/search.rs @@ -21,7 +21,7 @@ pub fn cli() -> App { .after_help("Run `cargo help search` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let registry = args.registry(config)?; let index = args.index()?; let limit = args.value_of_u32("limit")?; diff --git a/src/bin/cargo/commands/test.rs b/src/bin/cargo/commands/test.rs index d03ed99d206..b2d31ba2c64 100644 --- a/src/bin/cargo/commands/test.rs +++ b/src/bin/cargo/commands/test.rs @@ -23,7 +23,7 @@ pub fn cli() -> App { "quiet", "Display one character per test instead of one line", ) - .short("q"), + .short('q'), ) .arg_targets_all( "Test only this package's library unit tests", @@ -62,7 +62,7 @@ pub fn cli() -> App { ) } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; let mut compile_opts = args.compile_options( diff --git a/src/bin/cargo/commands/tree.rs b/src/bin/cargo/commands/tree.rs index f45e21ba619..7cdfa3c422b 100644 --- a/src/bin/cargo/commands/tree.rs +++ b/src/bin/cargo/commands/tree.rs @@ -20,7 +20,7 @@ pub fn cli() -> App { "Exclude specific workspace members", ) // Deprecated, use --no-dedupe instead. - .arg(Arg::with_name("all").long("all").short("a").hidden(true)) + .arg(Arg::with_name("all").long("all").short('a').hidden(true)) // Deprecated, use --target=all instead. .arg( Arg::with_name("all-targets") @@ -46,7 +46,7 @@ pub fn cli() -> App { (features, normal, build, dev, all, \ no-normal, no-build, no-dev, no-proc-macro)", ) - .short("e"), + .short('e'), ) .arg( optional_multi_opt( @@ -54,7 +54,7 @@ pub fn cli() -> App { "SPEC", "Invert the tree direction and focus on the given package", ) - .short("i"), + .short('i'), ) .arg(multi_opt( "prune", @@ -88,7 +88,7 @@ pub fn cli() -> App { "duplicates", "Show only dependencies which come in multiple versions (implies -i)", ) - .short("d") + .short('d') .alias("duplicate"), ) .arg( @@ -100,20 +100,20 @@ pub fn cli() -> App { .arg( opt("format", "Format string used for printing dependencies") .value_name("FORMAT") - .short("f") + .short('f') .default_value("{p}"), ) .arg( // Backwards compatibility with old cargo-tree. Arg::with_name("version") .long("version") - .short("V") + .short('V') .hidden(true), ) .after_help("Run `cargo help tree` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { if args.is_present("version") { let verbose = args.occurrences_of("verbose") > 0; let version = cli::get_version_string(verbose); @@ -226,10 +226,7 @@ subtree of the package given to -p.\n\ /// Parses `--edges` option. /// /// Returns a tuple of `EdgeKind` map and `no_proc_marco` flag. -fn parse_edge_kinds( - config: &Config, - args: &ArgMatches<'_>, -) -> CargoResult<(HashSet, bool)> { +fn parse_edge_kinds(config: &Config, args: &ArgMatches) -> CargoResult<(HashSet, bool)> { let (kinds, no_proc_macro) = { let mut no_proc_macro = false; let mut kinds = args.values_of("edges").map_or_else( diff --git a/src/bin/cargo/commands/uninstall.rs b/src/bin/cargo/commands/uninstall.rs index f228af195d3..33f3f3819dd 100644 --- a/src/bin/cargo/commands/uninstall.rs +++ b/src/bin/cargo/commands/uninstall.rs @@ -13,7 +13,7 @@ pub fn cli() -> App { .after_help("Run `cargo help uninstall` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let root = args.value_of("root"); if args.is_present_with_zero_values("package") { diff --git a/src/bin/cargo/commands/update.rs b/src/bin/cargo/commands/update.rs index c1041310bfb..92be87ed990 100644 --- a/src/bin/cargo/commands/update.rs +++ b/src/bin/cargo/commands/update.rs @@ -7,7 +7,7 @@ pub fn cli() -> App { subcommand("update") .about("Update dependencies as recorded in the local lock file") .arg_quiet() - .arg(opt("workspace", "Only update the workspace packages").short("w")) + .arg(opt("workspace", "Only update the workspace packages").short('w')) .arg_package_spec_simple("Package to update") .arg(opt( "aggressive", @@ -25,7 +25,7 @@ pub fn cli() -> App { .after_help("Run `cargo help update` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let ws = args.workspace(config)?; if args.is_present_with_zero_values("package") { diff --git a/src/bin/cargo/commands/vendor.rs b/src/bin/cargo/commands/vendor.rs index 9a96af613d4..104cf902859 100644 --- a/src/bin/cargo/commands/vendor.rs +++ b/src/bin/cargo/commands/vendor.rs @@ -7,7 +7,11 @@ pub fn cli() -> App { .about("Vendor all dependencies for a project locally") .arg_quiet() .arg_manifest_path() - .arg(Arg::with_name("path").help("Where to vendor crates (`vendor` by default)")) + .arg( + Arg::with_name("path") + .allow_invalid_utf8(true) + .help("Where to vendor crates (`vendor` by default)"), + ) .arg( Arg::with_name("no-delete") .long("no-delete") @@ -15,17 +19,18 @@ pub fn cli() -> App { ) .arg( Arg::with_name("tomls") - .short("s") + .short('s') .long("sync") .help("Additional `Cargo.toml` to sync and vendor") .value_name("TOML") + .allow_invalid_utf8(true) .multiple(true), ) .arg( Arg::with_name("respect-source-config") .long("respect-source-config") .help("Respect `[source]` config in `.cargo/config`") - .multiple(true), + .multiple_occurrences(true), ) .arg( Arg::with_name("versioned-dirs") @@ -59,7 +64,7 @@ pub fn cli() -> App { .after_help("Run `cargo help vendor` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { // We're doing the vendoring operation ourselves, so we don't actually want // to respect any of the `source` configuration in Cargo itself. That's // intended for other consumers of Cargo, but we want to go straight to the diff --git a/src/bin/cargo/commands/verify_project.rs b/src/bin/cargo/commands/verify_project.rs index 4a5cf68c1e2..e3779d89573 100644 --- a/src/bin/cargo/commands/verify_project.rs +++ b/src/bin/cargo/commands/verify_project.rs @@ -11,7 +11,7 @@ pub fn cli() -> App { .after_help("Run `cargo help verify-project` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { if let Err(e) = args.workspace(config) { let mut h = HashMap::new(); h.insert("invalid".to_string(), e.to_string()); diff --git a/src/bin/cargo/commands/version.rs b/src/bin/cargo/commands/version.rs index 8518877893a..1e59f136954 100644 --- a/src/bin/cargo/commands/version.rs +++ b/src/bin/cargo/commands/version.rs @@ -8,7 +8,7 @@ pub fn cli() -> App { .after_help("Run `cargo help version` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let verbose = args.occurrences_of("verbose") > 0; let version = cli::get_version_string(verbose); cargo::drop_print!(config, "{}", version); diff --git a/src/bin/cargo/commands/yank.rs b/src/bin/cargo/commands/yank.rs index 9bf3fa02cc0..ec19c5e029b 100644 --- a/src/bin/cargo/commands/yank.rs +++ b/src/bin/cargo/commands/yank.rs @@ -22,7 +22,7 @@ pub fn cli() -> App { .after_help("Run `cargo help yank` for more detailed information.\n") } -pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult { +pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { config.load_credentials()?; let registry = args.registry(config)?; diff --git a/src/bin/cargo/main.rs b/src/bin/cargo/main.rs index 57895b766ec..af2e4141c80 100644 --- a/src/bin/cargo/main.rs +++ b/src/bin/cargo/main.rs @@ -116,7 +116,7 @@ fn list_commands(config: &Config) -> BTreeMap { commands.insert( cmd.get_name().to_string(), CommandInfo::BuiltIn { - about: cmd.p.meta.about.map(|s| s.to_string()), + about: cmd.get_about().map(|s| s.to_string()), }, ); } diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index e4178fd1630..17fcf8c0fe1 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -30,9 +30,12 @@ mod version; pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! { debug!("exit_with_error; err={:?}", err); + if let Some(ref err) = err.error { if let Some(clap_err) = err.downcast_ref::() { - clap_err.exit() + let exit_code = if clap_err.use_stderr() { 1 } else { 0 }; + let _ = clap_err.print(); + std::process::exit(exit_code) } } diff --git a/src/cargo/util/command_prelude.rs b/src/cargo/util/command_prelude.rs index ef94584016a..1e672357e6b 100644 --- a/src/cargo/util/command_prelude.rs +++ b/src/cargo/util/command_prelude.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + use crate::core::compiler::{BuildConfig, MessageFormat}; use crate::core::resolver::CliFeatures; use crate::core::{Edition, Workspace}; @@ -23,10 +25,10 @@ pub use crate::core::compiler::CompileMode; pub use crate::{CliError, CliResult, Config}; pub use clap::{AppSettings, Arg, ArgMatches}; -pub type App = clap::App<'static, 'static>; +pub type App = clap::App<'static>; pub trait AppExt: Sized { - fn _arg(self, arg: Arg<'static, 'static>) -> Self; + fn _arg(self, arg: Arg<'static>) -> Self; /// Do not use this method, it is only for backwards compatibility. /// Use `arg_package_spec_no_all` instead. @@ -55,13 +57,13 @@ pub trait AppExt: Sized { } fn arg_package_spec_simple(self, package: &'static str) -> Self { - self._arg(optional_multi_opt("package", "SPEC", package).short("p")) + self._arg(optional_multi_opt("package", "SPEC", package).short('p')) } fn arg_package(self, package: &'static str) -> Self { self._arg( optional_opt("package", package) - .short("p") + .short('p') .value_name("SPEC"), ) } @@ -69,7 +71,7 @@ pub trait AppExt: Sized { fn arg_jobs(self) -> Self { self._arg( opt("jobs", "Number of parallel jobs, defaults to # of CPUs") - .short("j") + .short('j') .value_name("N"), ) } @@ -142,7 +144,7 @@ pub trait AppExt: Sized { } fn arg_release(self, release: &'static str) -> Self { - self._arg(opt("release", release).short("r")) + self._arg(opt("release", release).short('r')) } fn arg_profile(self, profile: &'static str) -> Self { @@ -238,21 +240,21 @@ pub trait AppExt: Sized { } fn arg_quiet(self) -> Self { - self._arg(opt("quiet", "Do not print cargo log messages").short("q")) + self._arg(opt("quiet", "Do not print cargo log messages").short('q')) } } impl AppExt for App { - fn _arg(self, arg: Arg<'static, 'static>) -> Self { + fn _arg(self, arg: Arg<'static>) -> Self { self.arg(arg) } } -pub fn opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> { +pub fn opt(name: &'static str, help: &'static str) -> Arg<'static> { Arg::with_name(name).long(name).help(help) } -pub fn optional_opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> { +pub fn optional_opt(name: &'static str, help: &'static str) -> Arg<'static> { opt(name, help).min_values(0) } @@ -260,7 +262,7 @@ pub fn optional_multi_opt( name: &'static str, value_name: &'static str, help: &'static str, -) -> Arg<'static, 'static> { +) -> Arg<'static> { opt(name, help) .value_name(value_name) .multiple(true) @@ -268,11 +270,7 @@ pub fn optional_multi_opt( .number_of_values(1) } -pub fn multi_opt( - name: &'static str, - value_name: &'static str, - help: &'static str, -) -> Arg<'static, 'static> { +pub fn multi_opt(name: &'static str, value_name: &'static str, help: &'static str) -> Arg<'static> { // Note that all `.multiple(true)` arguments in Cargo should specify // `.number_of_values(1)` as well, so that `--foo val1 val2` is // *not* parsed as `foo` with values ["val1", "val2"]. @@ -308,7 +306,10 @@ pub trait ArgMatchesExt { let arg = match self._value_of(name) { None => None, Some(arg) => Some(arg.parse::().map_err(|_| { - clap::Error::value_validation_auto(format!("could not parse `{}` as a number", arg)) + clap::Error::raw( + clap::ErrorKind::ValueValidation, + format!("Invalid value: could not parse `{}` as a number", arg), + ) })?), }; Ok(arg) @@ -320,7 +321,11 @@ pub trait ArgMatchesExt { } fn root_manifest(&self, config: &Config) -> CargoResult { - if let Some(path) = self.value_of_path("manifest-path", config) { + if let Some(path) = self + ._is_valid_arg("manifest-path") + .then(|| self.value_of_path("manifest-path", config)) + .flatten() + { // In general, we try to avoid normalizing paths in Cargo, // but in this particular case we need it to fix #3586. let path = paths::normalize_path(&path); @@ -395,8 +400,8 @@ pub trait ArgMatchesExt { }; let name = match ( - self._is_present("release"), - self._is_present("debug"), + self.is_valid_and_present("release"), + self.is_valid_and_present("debug"), specified_profile, ) { (false, false, None) => default, @@ -424,9 +429,13 @@ pub trait ArgMatchesExt { fn packages_from_flags(&self) -> CargoResult { Packages::from_flags( // TODO Integrate into 'workspace' - self._is_present("workspace") || self._is_present("all"), - self._values_of("exclude"), - self._values_of("package"), + self.is_valid_and_present("workspace") || self.is_valid_and_present("all"), + self._is_valid_arg("exclude") + .then(|| self._values_of("exclude")) + .unwrap_or_default(), + self._is_valid_arg("package") + .then(|| self._values_of("package")) + .unwrap_or_default(), ) } @@ -503,9 +512,9 @@ pub trait ArgMatchesExt { let mut build_config = BuildConfig::new(config, self.jobs()?, &self.targets(), mode)?; build_config.message_format = message_format.unwrap_or(MessageFormat::Human); build_config.requested_profile = self.get_profile_name(config, "dev", profile_checking)?; - build_config.build_plan = self._is_present("build-plan"); - build_config.unit_graph = self._is_present("unit-graph"); - build_config.future_incompat_report = self._is_present("future-incompat-report"); + build_config.build_plan = self.is_valid_and_present("build-plan"); + build_config.unit_graph = self.is_valid_and_present("unit-graph"); + build_config.future_incompat_report = self.is_valid_and_present("future-incompat-report"); if build_config.build_plan { config .cli_unstable() @@ -522,28 +531,32 @@ pub trait ArgMatchesExt { cli_features: self.cli_features()?, spec, filter: CompileFilter::from_raw_arguments( - self._is_present("lib"), + self.is_valid_and_present("lib"), self._values_of("bin"), - self._is_present("bins"), - self._values_of("test"), - self._is_present("tests"), + self.is_valid_and_present("bins"), + self._is_valid_arg("test") + .then(|| self._values_of("test")) + .unwrap_or_default(), + self.is_valid_and_present("tests"), self._values_of("example"), - self._is_present("examples"), - self._values_of("bench"), - self._is_present("benches"), - self._is_present("all-targets"), + self.is_valid_and_present("examples"), + self._is_valid_arg("bench") + .then(|| self._values_of("bench")) + .unwrap_or_default(), + self.is_valid_and_present("benches"), + self.is_valid_and_present("all-targets"), ), target_rustdoc_args: None, target_rustc_args: None, target_rustc_crate_types: None, local_rustdoc_args: None, rustdoc_document_private_items: false, - honor_rust_version: !self._is_present("ignore-rust-version"), + honor_rust_version: !self.is_valid_and_present("ignore-rust-version"), }; if let Some(ws) = workspace { self.check_optional_opts(ws, &opts)?; - } else if self.is_present_with_zero_values("package") { + } else if self._is_valid_arg("package") && self.is_present_with_zero_values("package") { // As for cargo 0.50.0, this won't occur but if someone sneaks in // we can still provide this informative message for them. anyhow::bail!( @@ -630,7 +643,7 @@ pub trait ArgMatchesExt { workspace: &Workspace<'_>, compile_opts: &CompileOptions, ) -> CargoResult<()> { - if self.is_present_with_zero_values("package") { + if self._is_valid_arg("package") && self.is_present_with_zero_values("package") { print_available_packages(workspace)? } @@ -642,11 +655,11 @@ pub trait ArgMatchesExt { print_available_binaries(workspace, compile_opts)?; } - if self.is_present_with_zero_values("bench") { + if self._is_valid_arg("bench") && self.is_present_with_zero_values("bench") { print_available_benches(workspace, compile_opts)?; } - if self.is_present_with_zero_values("test") { + if self._is_valid_arg("test") && self.is_present_with_zero_values("test") { print_available_tests(workspace, compile_opts)?; } @@ -657,6 +670,10 @@ pub trait ArgMatchesExt { self._is_present(name) && self._value_of(name).is_none() } + fn is_valid_and_present(&self, name: &str) -> bool { + self._is_valid_arg(name) && self._is_present(name) + } + fn _value_of(&self, name: &str) -> Option<&str>; fn _values_of(&self, name: &str) -> Vec; @@ -666,9 +683,11 @@ pub trait ArgMatchesExt { fn _values_of_os(&self, name: &str) -> Vec; fn _is_present(&self, name: &str) -> bool; + + fn _is_valid_arg(&self, name: &str) -> bool; } -impl<'a> ArgMatchesExt for ArgMatches<'a> { +impl<'a> ArgMatchesExt for ArgMatches { fn _value_of(&self, name: &str) -> Option<&str> { self.value_of(name) } @@ -694,13 +713,17 @@ impl<'a> ArgMatchesExt for ArgMatches<'a> { fn _is_present(&self, name: &str) -> bool { self.is_present(name) } + + fn _is_valid_arg(&self, name: &str) -> bool { + self.is_valid_arg(name) + } } -pub fn values(args: &ArgMatches<'_>, name: &str) -> Vec { +pub fn values(args: &ArgMatches, name: &str) -> Vec { args._values_of(name) } -pub fn values_os(args: &ArgMatches<'_>, name: &str) -> Vec { +pub fn values_os(args: &ArgMatches, name: &str) -> Vec { args._values_of_os(name) } diff --git a/src/cargo/util/errors.rs b/src/cargo/util/errors.rs index 8a371607725..524a5d627c4 100644 --- a/src/cargo/util/errors.rs +++ b/src/cargo/util/errors.rs @@ -300,6 +300,12 @@ impl From for CliError { } } +impl From for CliError { + fn from(err: std::io::Error) -> CliError { + CliError::new(err.into(), 1) + } +} + // ============================================================================= // Construction helpers diff --git a/tests/testsuite/cargo_config.rs b/tests/testsuite/cargo_config.rs index a11e9afc58f..0a3bc37c012 100644 --- a/tests/testsuite/cargo_config.rs +++ b/tests/testsuite/cargo_config.rs @@ -473,22 +473,20 @@ fn includes() { .with_stderr("") .run(); - cargo_process( - "config get build.rustflags --show-origin=yes -Zunstable-options -Zconfig-include", - ) - .cwd(&sub_folder.parent().unwrap()) - .masquerade_as_nightly_cargo() - .with_stdout( - "\ + cargo_process("config get build.rustflags --show-origin -Zunstable-options -Zconfig-include") + .cwd(&sub_folder.parent().unwrap()) + .masquerade_as_nightly_cargo() + .with_stdout( + "\ build.rustflags = [ \"--flag-other\", # [ROOT]/foo/.cargo/other.toml \"--flag-directory\", # [ROOT]/foo/.cargo/config.toml \"--flag-global\", # [ROOT]/home/.cargo/config.toml ] ", - ) - .with_stderr("") - .run(); + ) + .with_stderr("") + .run(); cargo_process("config get --merged=no -Zunstable-options -Zconfig-include") .cwd(&sub_folder.parent().unwrap()) diff --git a/tests/testsuite/metadata.rs b/tests/testsuite/metadata.rs index bc39d86ed0f..279b760ad6c 100644 --- a/tests/testsuite/metadata.rs +++ b/tests/testsuite/metadata.rs @@ -1183,7 +1183,7 @@ fn cargo_metadata_bad_version() { .with_status(1) .with_stderr_contains( "\ -error: '2' isn't a valid value for '--format-version ' +error: \"2\" isn't a valid value for '--format-version ' [possible values: 1] ", ) diff --git a/tests/testsuite/new.rs b/tests/testsuite/new.rs index 829638141da..8d85f488c55 100644 --- a/tests/testsuite/new.rs +++ b/tests/testsuite/new.rs @@ -362,7 +362,7 @@ fn new_default_edition() { #[cargo_test] fn new_with_bad_edition() { cargo_process("new --edition something_else foo") - .with_stderr_contains("error: 'something_else' isn't a valid value[..]") + .with_stderr_contains("error: \"something_else\" isn't a valid value[..]") .with_status(1) .run(); } diff --git a/tests/testsuite/run.rs b/tests/testsuite/run.rs index ee7c138daf1..022dc2c5fa3 100644 --- a/tests/testsuite/run.rs +++ b/tests/testsuite/run.rs @@ -1251,7 +1251,7 @@ fn run_multiple_packages() { cargo().arg("-p").arg("d1").arg("-p").arg("d2") .with_status(1) - .with_stderr_contains("error: The argument '--package ' was provided more than once, but cannot be used multiple times").run(); + .with_stderr_contains("error: The argument '--package ...' was provided more than once, but cannot be used multiple times").run(); cargo() .arg("-p") diff --git a/tests/testsuite/rustc.rs b/tests/testsuite/rustc.rs index 571e5392783..243055a5a86 100644 --- a/tests/testsuite/rustc.rs +++ b/tests/testsuite/rustc.rs @@ -540,7 +540,7 @@ fn fail_with_multiple_packages() { .with_status(1) .with_stderr_contains( "\ -error: The argument '--package ' was provided more than once, \ +error: The argument '--package ...' was provided more than once, \ but cannot be used multiple times ", )