1
1
use anyhow:: anyhow;
2
+ use cargo:: core:: shell:: Shell ;
2
3
use cargo:: core:: { features, CliUnstable } ;
3
4
use cargo:: { self , drop_print, drop_println, CliResult , Config } ;
4
5
use clap:: { AppSettings , Arg , ArgMatches } ;
@@ -21,12 +22,13 @@ lazy_static::lazy_static! {
21
22
] ) ;
22
23
}
23
24
24
- pub fn main ( config : & mut Config ) -> CliResult {
25
+ pub fn main ( config : & mut LazyConfig ) -> CliResult {
26
+ let args = cli ( ) . try_get_matches ( ) ?;
27
+
25
28
// CAUTION: Be careful with using `config` until it is configured below.
26
29
// In general, try to avoid loading config values unless necessary (like
27
30
// the [alias] table).
28
-
29
- let args = cli ( ) . try_get_matches ( ) ?;
31
+ let config = config. get_mut ( ) ;
30
32
31
33
// Global args need to be extracted before expanding aliases because the
32
34
// clap code for extracting a subcommand discards global options
@@ -463,6 +465,49 @@ See 'cargo help <command>' for more information on a specific command.\n",
463
465
. subcommands ( commands:: builtin ( ) )
464
466
}
465
467
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
+
466
511
#[ test]
467
512
fn verify_cli ( ) {
468
513
cli ( ) . debug_assert ( ) ;
0 commit comments