diff --git a/src/bin/cargo/cli.rs b/src/bin/cargo/cli.rs index 00e528d80f7a..2f1ebffe547b 100644 --- a/src/bin/cargo/cli.rs +++ b/src/bin/cargo/cli.rs @@ -30,9 +30,6 @@ pub fn main(config: &mut LazyConfig) -> CliResult { // the [alias] table). let config = config.get_mut(); - // Global args need to be extracted before expanding aliases because the - // clap code for extracting a subcommand discards global options - // (appearing before the subcommand). let (expanded_args, global_args) = expand_aliases(config, args, vec![])?; if expanded_args @@ -222,16 +219,30 @@ fn add_ssl(version_string: &mut String) { } } +/// Expands aliases recursively to collect all the command line arguments. +/// +/// [`GlobalArgs`] need to be extracted before expanding aliases because the +/// clap code for extracting a subcommand discards global options +/// (appearing before the subcommand). fn expand_aliases( config: &mut Config, args: ArgMatches, mut already_expanded: Vec, ) -> Result<(ArgMatches, GlobalArgs), CliError> { if let Some((cmd, args)) = args.subcommand() { - match ( - commands::builtin_exec(cmd), - super::aliased_command(config, cmd)?, - ) { + let exec = commands::builtin_exec(cmd); + let aliased_cmd = super::aliased_command(config, cmd).or_else(|e| { + // HACK: `cargo version` must always work even with malformed configs. + // Here we treat the error as the aliased command not found, + // so it falls back to call builtin `cargo version` + if cmd == "version" { + Ok(None) + } else { + Err(e) + } + })?; + + match (exec, aliased_cmd) { (Some(_), Some(_)) => { // User alias conflicts with a built-in subcommand config.shell().warn(format!(