use anyhow::anyhow;
+use cargo::core::shell::Shell;
use cargo::core::{features, CliUnstable};
use cargo::{self, drop_print, drop_println, CliResult, Config};
use clap::{AppSettings, Arg, ArgMatches};
]);
}
-pub fn main(config: &mut Config) -> CliResult {
+pub fn main(config: &mut LazyConfig) -> CliResult {
+ let args = cli().try_get_matches()?;
+
// CAUTION: Be careful with using `config` until it is configured below.
// In general, try to avoid loading config values unless necessary (like
// the [alias] table).
-
- let args = cli().try_get_matches()?;
+ 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
.subcommands(commands::builtin())
}
+/// Delay loading [`Config`] until access.
+///
+/// In the common path, the [`Config`] is dependent on CLI parsing and shouldn't be loaded until
+/// after that is done but some other paths (like fix or earlier errors) might need access to it,
+/// so this provides a way to share the instance and the implementation across these different
+/// accesses.
+pub struct LazyConfig {
+ config: Option<Config>,
+}
+
+impl LazyConfig {
+ pub fn new() -> Self {
+ Self { config: None }
+ }
+
+ /// Check whether the config is loaded
+ ///
+ /// This is useful for asserts in case the environment needs to be setup before loading
+ pub fn is_init(&self) -> bool {
+ self.config.is_some()
+ }
+
+ /// Get the config, loading it if needed
+ ///
+ /// On error, the process is terminated
+ pub fn get(&mut self) -> &Config {
+ self.get_mut()
+ }
+
+ /// Get the config, loading it if needed
+ ///
+ /// On error, the process is terminated
+ pub fn get_mut(&mut self) -> &mut Config {
+ self.config.get_or_insert_with(|| match Config::default() {
+ Ok(cfg) => cfg,
+ Err(e) => {
+ let mut shell = Shell::new();
+ cargo::exit_with_error(e.into(), &mut shell)
+ }
+ })
+ }
+}
+
#[test]
fn verify_cli() {
cli().debug_assert();
#![warn(rust_2018_idioms)] // while we're getting used to 2018
#![allow(clippy::all)]
-use cargo::core::shell::Shell;
use cargo::util::toml::StringOrVec;
use cargo::util::CliError;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
#[cfg(not(feature = "pretty-env-logger"))]
env_logger::init_from_env("CARGO_LOG");
- let mut config = match Config::default() {
- Ok(cfg) => cfg,
- Err(e) => {
- let mut shell = Shell::new();
- cargo::exit_with_error(e.into(), &mut shell)
- }
- };
+ let mut config = cli::LazyConfig::new();
let result = if let Some(lock_addr) = cargo::ops::fix_get_proxy_lock_addr() {
- cargo::ops::fix_exec_rustc(&config, &lock_addr).map_err(|e| CliError::from(e))
+ cargo::ops::fix_exec_rustc(config.get(), &lock_addr).map_err(|e| CliError::from(e))
} else {
let _token = cargo::util::job::setup();
cli::main(&mut config)
};
match result {
- Err(e) => cargo::exit_with_error(e, &mut *config.shell()),
+ Err(e) => cargo::exit_with_error(e, &mut config.get_mut().shell()),
Ok(()) => {}
}
}