3
3
//! This module provides the [`ExecutionContext`] type, which holds global configuration
4
4
//! relevant during the execution of commands in bootstrap. This includes dry-run
5
5
//! mode, verbosity level, and behavior on failure.
6
+ #![ allow( warnings) ]
7
+ use std:: collections:: HashMap ;
6
8
use std:: panic:: Location ;
7
9
use std:: process:: Child ;
8
10
use std:: sync:: { Arc , Mutex } ;
9
11
10
12
use crate :: core:: config:: DryRun ;
11
13
#[ cfg( feature = "tracing" ) ]
12
14
use crate :: trace_cmd;
15
+ use crate :: utils:: exec:: CommandCacheKey ;
13
16
use crate :: { BehaviorOnFailure , BootstrapCommand , CommandOutput , OutputMode , exit} ;
14
17
15
18
#[ derive( Clone , Default ) ]
@@ -18,6 +21,26 @@ pub struct ExecutionContext {
18
21
verbose : u8 ,
19
22
pub fail_fast : bool ,
20
23
delayed_failures : Arc < Mutex < Vec < String > > > ,
24
+ command_cache : Arc < CommandCache > ,
25
+ }
26
+
27
+ #[ derive( Default ) ]
28
+ pub struct CommandCache {
29
+ cache : Mutex < HashMap < CommandCacheKey , CommandOutput > > ,
30
+ }
31
+
32
+ impl CommandCache {
33
+ pub fn new ( ) -> Self {
34
+ Self { cache : Mutex :: new ( HashMap :: new ( ) ) }
35
+ }
36
+
37
+ pub fn get ( & self , key : & CommandCacheKey ) -> Option < CommandOutput > {
38
+ self . cache . lock ( ) . unwrap ( ) . get ( key) . cloned ( )
39
+ }
40
+
41
+ pub fn insert ( & self , key : CommandCacheKey , output : CommandOutput ) {
42
+ self . cache . lock ( ) . unwrap ( ) . insert ( key, output) ;
43
+ }
21
44
}
22
45
23
46
impl ExecutionContext {
@@ -123,7 +146,24 @@ impl ExecutionContext {
123
146
stdout : OutputMode ,
124
147
stderr : OutputMode ,
125
148
) -> CommandOutput {
126
- self . start ( command, stdout, stderr) . wait_for_output ( self )
149
+ let cache_key = command. cache_key ( ) ;
150
+
151
+ if let Some ( cached_output) = self . command_cache . get ( & cache_key) {
152
+ command. mark_as_executed ( ) ;
153
+ if self . dry_run ( ) && !command. run_always {
154
+ return CommandOutput :: default ( ) ;
155
+ }
156
+ self . verbose ( || println ! ( "Cache hit: {:?}" , command) ) ;
157
+ return cached_output;
158
+ }
159
+
160
+ let output = self . start ( command, stdout, stderr) . wait_for_output ( self ) ;
161
+
162
+ if output != CommandOutput :: default ( ) {
163
+ self . command_cache . insert ( cache_key, output. clone ( ) ) ;
164
+ }
165
+
166
+ output
127
167
}
128
168
129
169
fn fail ( & self , message : & str , output : CommandOutput ) -> ! {
0 commit comments