11use anyhow:: anyhow;
2+ use cargo:: core:: shell:: Shell ;
23use cargo:: core:: { features, CliUnstable } ;
34use 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 } ;
86use itertools:: Itertools ;
97use std:: collections:: HashMap ;
108use 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]
492512fn verify_cli ( ) {
493513 cli ( ) . debug_assert ( ) ;
0 commit comments