55#![ allow( warnings) ]
66
77use std:: collections:: HashMap ;
8- use std:: ffi:: OsStr ;
8+ use std:: ffi:: { OsStr , OsString } ;
99use std:: fmt:: { Debug , Formatter } ;
1010use std:: hash:: { Hash , Hasher } ;
1111use std:: path:: Path ;
@@ -55,6 +55,14 @@ impl OutputMode {
5555 }
5656}
5757
58+ #[ derive( Clone , Debug , PartialEq , Eq , Hash , Default ) ]
59+ pub struct CommandCacheKey {
60+ program : OsString ,
61+ args : Vec < OsString > ,
62+ envs : Vec < ( OsString , OsString ) > ,
63+ cwd : Option < PathBuf > ,
64+ }
65+
5866/// Wrapper around `std::process::Command`.
5967///
6068/// By default, the command will exit bootstrap if it fails.
@@ -69,33 +77,39 @@ impl OutputMode {
6977/// [allow_failure]: BootstrapCommand::allow_failure
7078/// [delay_failure]: BootstrapCommand::delay_failure
7179pub struct BootstrapCommand {
72- program : String ,
73- args : Vec < String > ,
74- envs : Vec < ( String , String ) > ,
75- cwd : Option < PathBuf > ,
76-
80+ cache_key : CommandCacheKey ,
7781 command : Command ,
7882 pub failure_behavior : BehaviorOnFailure ,
7983 // Run the command even during dry run
8084 pub run_in_dry_run : bool ,
8185 // This field makes sure that each command is executed (or disarmed) before it is dropped,
8286 // to avoid forgetting to execute a command.
8387 drop_bomb : DropBomb ,
88+ should_cache : bool ,
8489}
8590
8691impl < ' a > BootstrapCommand {
8792 #[ track_caller]
8893 pub fn new < S : AsRef < OsStr > > ( program : S ) -> Self {
89- Command :: new ( program) . into ( )
94+ Self {
95+ should_cache : true ,
96+ cache_key : CommandCacheKey {
97+ program : program. as_ref ( ) . to_os_string ( ) ,
98+ ..CommandCacheKey :: default ( )
99+ } ,
100+ ..Command :: new ( program) . into ( )
101+ }
90102 }
91-
92103 pub fn arg < S : AsRef < OsStr > > ( & mut self , arg : S ) -> & mut Self {
93- let arg_str = arg. as_ref ( ) . to_string_lossy ( ) . into_owned ( ) ;
94- self . args . push ( arg_str. clone ( ) ) ;
104+ self . cache_key . args . push ( arg. as_ref ( ) . to_os_string ( ) ) ;
95105 self . command . arg ( arg. as_ref ( ) ) ;
96106 self
97107 }
98108
109+ pub fn should_cache ( & self ) -> bool {
110+ self . should_cache
111+ }
112+
99113 pub fn args < I , S > ( & mut self , args : I ) -> & mut Self
100114 where
101115 I : IntoIterator < Item = S > ,
@@ -112,9 +126,7 @@ impl<'a> BootstrapCommand {
112126 K : AsRef < OsStr > ,
113127 V : AsRef < OsStr > ,
114128 {
115- let key_str = key. as_ref ( ) . to_string_lossy ( ) . into_owned ( ) ;
116- let val_str = val. as_ref ( ) . to_string_lossy ( ) . into_owned ( ) ;
117- self . envs . push ( ( key_str. clone ( ) , val_str. clone ( ) ) ) ;
129+ self . cache_key . envs . push ( ( key. as_ref ( ) . to_os_string ( ) , val. as_ref ( ) . to_os_string ( ) ) ) ;
118130 self . command . env ( key, val) ;
119131 self
120132 }
@@ -133,7 +145,7 @@ impl<'a> BootstrapCommand {
133145 }
134146
135147 pub fn current_dir < P : AsRef < Path > > ( & mut self , dir : P ) -> & mut Self {
136- self . cwd = Some ( dir. as_ref ( ) . to_path_buf ( ) ) ;
148+ self . cache_key . cwd = Some ( dir. as_ref ( ) . to_path_buf ( ) ) ;
137149 self . command . current_dir ( dir) ;
138150 self
139151 }
@@ -205,6 +217,7 @@ impl<'a> BootstrapCommand {
205217 // We don't know what will happen with the returned command, so we need to mark this
206218 // command as executed proactively.
207219 self . mark_as_executed ( ) ;
220+ self . should_cache = false ;
208221 & mut self . command
209222 }
210223
@@ -230,6 +243,10 @@ impl<'a> BootstrapCommand {
230243 self . env ( "TERM" , "xterm" ) . args ( [ "--color" , "always" ] ) ;
231244 }
232245 }
246+
247+ pub fn cache_key ( & self ) -> CommandCacheKey {
248+ self . cache_key . clone ( )
249+ }
233250}
234251
235252impl Debug for BootstrapCommand {
@@ -245,10 +262,8 @@ impl From<Command> for BootstrapCommand {
245262 let program = command. get_program ( ) . to_owned ( ) ;
246263
247264 Self {
248- program : program. clone ( ) . into_string ( ) . unwrap ( ) ,
249- args : Vec :: new ( ) ,
250- envs : Vec :: new ( ) ,
251- cwd : None ,
265+ cache_key : CommandCacheKey :: default ( ) ,
266+ should_cache : false ,
252267 command,
253268 failure_behavior : BehaviorOnFailure :: Exit ,
254269 run_in_dry_run : false ,
0 commit comments