@@ -6,7 +6,7 @@ use std::str::FromStr;
66use anyhow:: { anyhow, Error , Result } ;
77use clap:: {
88 builder:: { PossibleValue , PossibleValuesParser } ,
9- Arg , ArgAction , Args , Command , FromArgMatches as _ , Parser , Subcommand , ValueEnum ,
9+ Args , CommandFactory , Parser , Subcommand , ValueEnum ,
1010} ;
1111use clap_complete:: Shell ;
1212use itertools:: Itertools ;
@@ -64,15 +64,43 @@ fn handle_epipe(res: Result<utils::ExitCode>) -> Result<utils::ExitCode> {
6464 }
6565}
6666
67+ /// The Rust toolchain installer
6768#[ derive( Debug , Parser ) ]
6869#[ command(
6970 name = "rustup" ,
7071 bin_name = "rustup[EXE]" ,
7172 version = common:: version( ) ,
73+ before_help = format!( "rustup {}" , common:: version( ) ) ,
74+ after_help = RUSTUP_HELP ,
7275) ]
7376struct Rustup {
77+ /// Enable verbose output
78+ #[ arg( short, long) ]
79+ verbose : bool ,
80+
81+ /// Disable progress output
82+ #[ arg( short, long, conflicts_with = "verbose" ) ]
83+ quiet : bool ,
84+
85+ /// Release channel (e.g. +stable) or custom toolchain to set override
86+ #[ arg(
87+ name = "+toolchain" ,
88+ value_parser = plus_toolchain_value_parser,
89+ ) ]
90+ plus_toolchain : Option < ResolvableToolchainName > ,
91+
7492 #[ command( subcommand) ]
75- subcmd : RustupSubcmd ,
93+ subcmd : Option < RustupSubcmd > ,
94+ }
95+
96+ fn plus_toolchain_value_parser ( s : & str ) -> clap:: error:: Result < ResolvableToolchainName > {
97+ use clap:: { error:: ErrorKind , Error } ;
98+ if let Some ( stripped) = s. strip_prefix ( '+' ) {
99+ ResolvableToolchainName :: try_from ( stripped)
100+ . map_err ( |e| Error :: raw ( ErrorKind :: InvalidValue , e) )
101+ } else {
102+ Err ( Error :: raw ( ErrorKind :: InvalidSubcommand , format ! ( "\" {s}\" is not a valid subcommand, so it was interpreted as a toolchain name, but it is also invalid. {TOOLCHAIN_OVERRIDE_ERROR}" ) ) )
103+ }
76104}
77105
78106#[ derive( Debug , Subcommand ) ]
@@ -496,9 +524,9 @@ enum SetSubcmd {
496524 } ,
497525}
498526
499- impl Rustup {
527+ impl RustupSubcmd {
500528 fn dispatch ( self , cfg : & mut Cfg ) -> Result < utils:: ExitCode > {
501- match self . subcmd {
529+ match self {
502530 RustupSubcmd :: DumpTestament => common:: dump_testament ( ) ,
503531 RustupSubcmd :: Install { opts } => update ( cfg, opts) ,
504532 RustupSubcmd :: Uninstall { opts } => toolchain_remove ( cfg, opts) ,
@@ -606,7 +634,7 @@ pub fn main() -> Result<utils::ExitCode> {
606634 self_update:: cleanup_self_updater ( ) ?;
607635
608636 use clap:: error:: ErrorKind :: * ;
609- let matches = match cli ( ) . try_get_matches_from ( process ( ) . args_os ( ) ) {
637+ let matches = match Rustup :: try_parse_from ( process ( ) . args_os ( ) ) {
610638 Ok ( matches) => Ok ( matches) ,
611639 Err ( err) if err. kind ( ) == DisplayHelp => {
612640 write ! ( process( ) . stdout( ) . lock( ) , "{err}" ) ?;
@@ -656,66 +684,23 @@ pub fn main() -> Result<utils::ExitCode> {
656684 Err ( err)
657685 }
658686 } ?;
659- let verbose = matches. get_flag ( "verbose" ) ;
660- let quiet = matches. get_flag ( "quiet" ) ;
661- let cfg = & mut common:: set_globals ( verbose, quiet) ?;
687+ let cfg = & mut common:: set_globals ( matches. verbose , matches. quiet ) ?;
662688
663- if let Some ( t) = matches. get_one :: < ResolvableToolchainName > ( "+toolchain" ) {
689+ if let Some ( t) = & matches. plus_toolchain {
664690 cfg. set_toolchain_override ( t) ;
665691 }
666692
667693 cfg. check_metadata_version ( ) ?;
668694
669- Ok ( match matches. subcommand ( ) {
670- Some ( _ ) => Rustup :: from_arg_matches ( & matches ) ? . dispatch ( cfg) ?,
695+ Ok ( match matches. subcmd {
696+ Some ( subcmd ) => subcmd . dispatch ( cfg) ?,
671697 None => {
672- eprintln ! ( "{}" , cli ( ) . render_long_help( ) ) ;
698+ eprintln ! ( "{}" , Rustup :: command ( ) . render_long_help( ) ) ;
673699 utils:: ExitCode ( 1 )
674700 }
675701 } )
676702}
677703
678- pub ( crate ) fn cli ( ) -> Command {
679- let app = Command :: new ( "rustup" )
680- . version ( common:: version ( ) )
681- . about ( "The Rust toolchain installer" )
682- . before_help ( format ! ( "rustup {}" , common:: version( ) ) )
683- . after_help ( RUSTUP_HELP )
684- . subcommand_required ( false )
685- . arg (
686- verbose_arg ( "Enable verbose output" ) ,
687- )
688- . arg (
689- Arg :: new ( "quiet" )
690- . conflicts_with ( "verbose" )
691- . help ( "Disable progress output" )
692- . short ( 'q' )
693- . long ( "quiet" )
694- . action ( ArgAction :: SetTrue ) ,
695- )
696- . arg (
697- Arg :: new ( "+toolchain" )
698- . help ( "release channel (e.g. +stable) or custom toolchain to set override" )
699- . value_parser ( |s : & str | {
700- use clap:: { Error , error:: ErrorKind } ;
701- if let Some ( stripped) = s. strip_prefix ( '+' ) {
702- ResolvableToolchainName :: try_from ( stripped) . map_err ( |e| Error :: raw ( ErrorKind :: InvalidValue , e) )
703- } else {
704- Err ( Error :: raw ( ErrorKind :: InvalidSubcommand , format ! ( "\" {s}\" is not a valid subcommand, so it was interpreted as a toolchain name, but it is also invalid. {TOOLCHAIN_OVERRIDE_ERROR}" ) ) )
705- }
706- } ) ,
707- ) ;
708- RustupSubcmd :: augment_subcommands ( app)
709- }
710-
711- fn verbose_arg ( help : & ' static str ) -> Arg {
712- Arg :: new ( "verbose" )
713- . help ( help)
714- . short ( 'v' )
715- . long ( "verbose" )
716- . action ( ArgAction :: SetTrue )
717- }
718-
719704fn upgrade_data ( cfg : & Cfg ) -> Result < utils:: ExitCode > {
720705 cfg. upgrade_data ( ) ?;
721706 Ok ( utils:: ExitCode ( 0 ) )
@@ -1589,7 +1574,12 @@ impl fmt::Display for CompletionCommand {
15891574fn output_completion_script ( shell : Shell , command : CompletionCommand ) -> Result < utils:: ExitCode > {
15901575 match command {
15911576 CompletionCommand :: Rustup => {
1592- clap_complete:: generate ( shell, & mut cli ( ) , "rustup" , & mut process ( ) . stdout ( ) . lock ( ) ) ;
1577+ clap_complete:: generate (
1578+ shell,
1579+ & mut Rustup :: command ( ) ,
1580+ "rustup" ,
1581+ & mut process ( ) . stdout ( ) . lock ( ) ,
1582+ ) ;
15931583 }
15941584 CompletionCommand :: Cargo => {
15951585 if let Shell :: Zsh = shell {
0 commit comments