Skip to content

Commit 67491dd

Browse files
authored
Merge branch 'master' into edit-refactor
2 parents 5346159 + 646e9a0 commit 67491dd

File tree

8 files changed

+177
-137
lines changed

8 files changed

+177
-137
lines changed

Cargo.toml

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

src/bin/cargo/cli.rs

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
use anyhow::anyhow;
2+
use cargo::core::shell::Shell;
23
use cargo::core::{features, CliUnstable};
34
use cargo::{self, drop_print, drop_println, CliResult, Config};
4-
use clap::{
5-
error::{ContextKind, ContextValue},
6-
AppSettings, Arg, ArgMatches,
7-
};
5+
use clap::{AppSettings, Arg, ArgMatches};
86
use itertools::Itertools;
97
use std::collections::HashMap;
108
use std::fmt::Write;
@@ -24,36 +22,13 @@ lazy_static::lazy_static! {
2422
]);
2523
}
2624

27-
pub fn main(config: &mut Config) -> CliResult {
25+
pub fn main(config: &mut LazyConfig) -> CliResult {
26+
let args = cli().try_get_matches()?;
27+
2828
// CAUTION: Be careful with using `config` until it is configured below.
2929
// In general, try to avoid loading config values unless necessary (like
3030
// the [alias] table).
31-
32-
if commands::help::handle_embedded_help(config) {
33-
return Ok(());
34-
}
35-
36-
let args = match cli().try_get_matches() {
37-
Ok(args) => args,
38-
Err(e) => {
39-
if e.kind() == clap::ErrorKind::UnrecognizedSubcommand {
40-
// An unrecognized subcommand might be an external subcommand.
41-
let cmd = e
42-
.context()
43-
.find_map(|c| match c {
44-
(ContextKind::InvalidSubcommand, &ContextValue::String(ref cmd)) => {
45-
Some(cmd)
46-
}
47-
_ => None,
48-
})
49-
.expect("UnrecognizedSubcommand implies the presence of InvalidSubcommand");
50-
return super::execute_external_subcommand(config, cmd, &[cmd, "--help"])
51-
.map_err(|_| e.into());
52-
} else {
53-
return Err(e.into());
54-
}
55-
}
56-
};
31+
let config = config.get_mut();
5732

5833
// Global args need to be extracted before expanding aliases because the
5934
// clap code for extracting a subcommand discards global options
@@ -412,7 +387,7 @@ impl GlobalArgs {
412387
}
413388
}
414389

415-
fn cli() -> App {
390+
pub fn cli() -> App {
416391
let is_rustup = std::env::var_os("RUSTUP_HOME").is_some();
417392
let usage = if is_rustup {
418393
"cargo [+toolchain] [OPTIONS] [SUBCOMMAND]"
@@ -425,6 +400,8 @@ fn cli() -> App {
425400
// Doesn't mix well with our list of common cargo commands. See clap-rs/clap#3108 for
426401
// opening clap up to allow us to style our help template
427402
.disable_colored_help(true)
403+
// Provide a custom help subcommand for calling into man pages
404+
.disable_help_subcommand(true)
428405
.override_usage(usage)
429406
.help_template(
430407
"\
@@ -488,6 +465,49 @@ See 'cargo help <command>' for more information on a specific command.\n",
488465
.subcommands(commands::builtin())
489466
}
490467

468+
/// Delay loading [`Config`] until access.
469+
///
470+
/// In the common path, the [`Config`] is dependent on CLI parsing and shouldn't be loaded until
471+
/// after that is done but some other paths (like fix or earlier errors) might need access to it,
472+
/// so this provides a way to share the instance and the implementation across these different
473+
/// accesses.
474+
pub struct LazyConfig {
475+
config: Option<Config>,
476+
}
477+
478+
impl LazyConfig {
479+
pub fn new() -> Self {
480+
Self { config: None }
481+
}
482+
483+
/// Check whether the config is loaded
484+
///
485+
/// This is useful for asserts in case the environment needs to be setup before loading
486+
pub fn is_init(&self) -> bool {
487+
self.config.is_some()
488+
}
489+
490+
/// Get the config, loading it if needed
491+
///
492+
/// On error, the process is terminated
493+
pub fn get(&mut self) -> &Config {
494+
self.get_mut()
495+
}
496+
497+
/// Get the config, loading it if needed
498+
///
499+
/// On error, the process is terminated
500+
pub fn get_mut(&mut self) -> &mut Config {
501+
self.config.get_or_insert_with(|| match Config::default() {
502+
Ok(cfg) => cfg,
503+
Err(e) => {
504+
let mut shell = Shell::new();
505+
cargo::exit_with_error(e.into(), &mut shell)
506+
}
507+
})
508+
}
509+
}
510+
491511
#[test]
492512
fn verify_cli() {
493513
cli().debug_assert();

src/bin/cargo/commands/help.rs

Lines changed: 17 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::aliased_command;
2+
use crate::command_prelude::*;
23
use cargo::util::errors::CargoResult;
34
use cargo::{drop_println, Config};
45
use cargo_util::paths::resolve_executable;
@@ -10,43 +11,26 @@ use std::path::Path;
1011

1112
const COMPRESSED_MAN: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/man.tgz"));
1213

13-
/// Checks if the `help` command is being issued.
14-
///
15-
/// This runs before clap processing, because it needs to intercept the `help`
16-
/// command if a man page is available.
17-
///
18-
/// Returns `true` if help information was successfully displayed to the user.
19-
/// In this case, Cargo should exit.
20-
pub fn handle_embedded_help(config: &Config) -> bool {
21-
match try_help(config) {
22-
Ok(true) => true,
23-
Ok(false) => false,
24-
Err(e) => {
25-
log::warn!("help failed: {:?}", e);
26-
false
27-
}
28-
}
14+
pub fn cli() -> App {
15+
subcommand("help")
16+
.about("Displays help for a cargo subcommand")
17+
.arg(Arg::new("SUBCOMMAND"))
2918
}
3019

31-
fn try_help(config: &Config) -> CargoResult<bool> {
32-
let mut args = std::env::args_os()
33-
.skip(1)
34-
.skip_while(|arg| arg.to_str().map_or(false, |s| s.starts_with('-')));
35-
if !args
36-
.next()
37-
.map_or(false, |arg| arg.to_str() == Some("help"))
38-
{
39-
return Ok(false);
20+
pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
21+
let subcommand = args.get_one::<String>("SUBCOMMAND");
22+
if let Some(subcommand) = subcommand {
23+
if !try_help(config, subcommand)? {
24+
crate::execute_external_subcommand(config, subcommand, &[subcommand, "--help"])?;
25+
}
26+
} else {
27+
let mut cmd = crate::cli::cli();
28+
let _ = cmd.print_help();
4029
}
41-
let subcommand = match args.next() {
42-
Some(arg) => arg,
43-
None => return Ok(false),
44-
};
45-
let subcommand = match subcommand.to_str() {
46-
Some(s) => s,
47-
None => return Ok(false),
48-
};
30+
Ok(())
31+
}
4932

33+
fn try_help(config: &Config, subcommand: &str) -> CargoResult<bool> {
5034
let subcommand = match check_alias(config, subcommand) {
5135
// If this alias is more than a simple subcommand pass-through, show the alias.
5236
Some(argv) if argv.len() > 1 => {

src/bin/cargo/commands/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub fn builtin() -> Vec<App> {
1313
fix::cli(),
1414
generate_lockfile::cli(),
1515
git_checkout::cli(),
16+
help::cli(),
1617
init::cli(),
1718
install::cli(),
1819
locate_project::cli(),
@@ -54,6 +55,7 @@ pub fn builtin_exec(cmd: &str) -> Option<fn(&mut Config, &ArgMatches) -> CliResu
5455
"fix" => fix::exec,
5556
"generate-lockfile" => generate_lockfile::exec,
5657
"git-checkout" => git_checkout::exec,
58+
"help" => help::exec,
5759
"init" => init::exec,
5860
"install" => install::exec,
5961
"locate-project" => locate_project::exec,

src/bin/cargo/main.rs

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#![warn(rust_2018_idioms)] // while we're getting used to 2018
22
#![allow(clippy::all)]
33

4-
use cargo::core::shell::Shell;
54
use cargo::util::toml::StringOrVec;
65
use cargo::util::CliError;
76
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
@@ -22,25 +21,17 @@ fn main() {
2221
#[cfg(not(feature = "pretty-env-logger"))]
2322
env_logger::init_from_env("CARGO_LOG");
2423

25-
let mut config = match Config::default() {
26-
Ok(cfg) => cfg,
27-
Err(e) => {
28-
let mut shell = Shell::new();
29-
cargo::exit_with_error(e.into(), &mut shell)
30-
}
31-
};
24+
let mut config = cli::LazyConfig::new();
3225

33-
let result = match cargo::ops::fix_maybe_exec_rustc(&config) {
34-
Ok(true) => Ok(()),
35-
Ok(false) => {
36-
let _token = cargo::util::job::setup();
37-
cli::main(&mut config)
38-
}
39-
Err(e) => Err(CliError::from(e)),
26+
let result = if let Some(lock_addr) = cargo::ops::fix_get_proxy_lock_addr() {
27+
cargo::ops::fix_exec_rustc(config.get(), &lock_addr).map_err(|e| CliError::from(e))
28+
} else {
29+
let _token = cargo::util::job::setup();
30+
cli::main(&mut config)
4031
};
4132

4233
match result {
43-
Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
34+
Err(e) => cargo::exit_with_error(e, &mut config.get_mut().shell()),
4435
Ok(()) => {}
4536
}
4637
}
@@ -190,11 +181,12 @@ fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&str]) -> Cli
190181
};
191182

192183
let cargo_exe = config.cargo_exe()?;
193-
let err = match ProcessBuilder::new(&command)
194-
.env(cargo::CARGO_ENV, cargo_exe)
195-
.args(args)
196-
.exec_replace()
197-
{
184+
let mut cmd = ProcessBuilder::new(&command);
185+
cmd.env(cargo::CARGO_ENV, cargo_exe).args(args);
186+
if let Some(client) = config.jobserver_from_env() {
187+
cmd.inherit_jobserver(client);
188+
}
189+
let err = match cmd.exec_replace() {
198190
Ok(()) => return Ok(()),
199191
Err(e) => e,
200192
};

src/cargo/ops/fix.rs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -333,20 +333,23 @@ to prevent this issue from happening.
333333
Ok(())
334334
}
335335

336+
/// Provide the lock address when running in proxy mode
337+
///
338+
/// Returns `None` if `fix` is not being run (not in proxy mode). Returns
339+
/// `Some(...)` if in `fix` proxy mode
340+
pub fn fix_get_proxy_lock_addr() -> Option<String> {
341+
env::var(FIX_ENV).ok()
342+
}
343+
336344
/// Entry point for `cargo` running as a proxy for `rustc`.
337345
///
338346
/// This is called every time `cargo` is run to check if it is in proxy mode.
339347
///
340-
/// Returns `false` if `fix` is not being run (not in proxy mode). Returns
341-
/// `true` if in `fix` proxy mode, and the fix was complete without any
342-
/// warnings or errors. If there are warnings or errors, this does not return,
348+
/// If there are warnings or errors, this does not return,
343349
/// and the process exits with the corresponding `rustc` exit code.
344-
pub fn fix_maybe_exec_rustc(config: &Config) -> CargoResult<bool> {
345-
let lock_addr = match env::var(FIX_ENV) {
346-
Ok(s) => s,
347-
Err(_) => return Ok(false),
348-
};
349-
350+
///
351+
/// See [`fix_proxy_lock_addr`]
352+
pub fn fix_exec_rustc(config: &Config, lock_addr: &str) -> CargoResult<()> {
350353
let args = FixArgs::get()?;
351354
trace!("cargo-fix as rustc got file {:?}", args.file);
352355

@@ -392,7 +395,7 @@ pub fn fix_maybe_exec_rustc(config: &Config) -> CargoResult<bool> {
392395
// any. If stderr is empty then there's no need for the final exec at
393396
// the end, we just bail out here.
394397
if output.status.success() && output.stderr.is_empty() {
395-
return Ok(true);
398+
return Ok(());
396399
}
397400

398401
// Otherwise, if our rustc just failed, then that means that we broke the

src/cargo/ops/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ pub use self::cargo_read_manifest::{read_package, read_packages};
1919
pub use self::cargo_run::run;
2020
pub use self::cargo_test::{run_benches, run_tests, TestOptions};
2121
pub use self::cargo_uninstall::uninstall;
22-
pub use self::fix::{fix, fix_maybe_exec_rustc, FixOptions};
22+
pub use self::fix::{fix, fix_exec_rustc, fix_get_proxy_lock_addr, FixOptions};
2323
pub use self::lockfile::{load_pkg_lockfile, resolve_to_string, write_pkg_lockfile};
2424
pub use self::registry::HttpTimeout;
2525
pub use self::registry::{configure_http_handle, http_handle, http_handle_and_timeout};

0 commit comments

Comments
 (0)