1
1
use r_efi:: protocols:: simple_text_output;
2
2
3
3
use super :: helpers;
4
+ use crate :: collections:: BTreeMap ;
4
5
pub use crate :: ffi:: OsString as EnvKey ;
5
6
use crate :: ffi:: { OsStr , OsString } ;
6
7
use crate :: num:: { NonZero , NonZeroI32 } ;
@@ -21,6 +22,7 @@ pub struct Command {
21
22
args : Vec < OsString > ,
22
23
stdout : Option < Stdio > ,
23
24
stderr : Option < Stdio > ,
25
+ env : CommandEnv ,
24
26
}
25
27
26
28
// passed back to std::process with the pipes connected to the child, if any
@@ -40,15 +42,21 @@ pub enum Stdio {
40
42
41
43
impl Command {
42
44
pub fn new ( program : & OsStr ) -> Command {
43
- Command { prog : program. to_os_string ( ) , args : Vec :: new ( ) , stdout : None , stderr : None }
45
+ Command {
46
+ prog : program. to_os_string ( ) ,
47
+ args : Vec :: new ( ) ,
48
+ stdout : None ,
49
+ stderr : None ,
50
+ env : Default :: default ( ) ,
51
+ }
44
52
}
45
53
46
54
pub fn arg ( & mut self , arg : & OsStr ) {
47
55
self . args . push ( arg. to_os_string ( ) ) ;
48
56
}
49
57
50
58
pub fn env_mut ( & mut self ) -> & mut CommandEnv {
51
- panic ! ( "unsupported" )
59
+ & mut self . env
52
60
}
53
61
54
62
pub fn cwd ( & mut self , _dir : & OsStr ) {
@@ -76,7 +84,7 @@ impl Command {
76
84
}
77
85
78
86
pub fn get_envs ( & self ) -> CommandEnvs < ' _ > {
79
- panic ! ( "unsupported" )
87
+ self . env . iter ( )
80
88
}
81
89
82
90
pub fn get_current_dir ( & self ) -> Option < & Path > {
@@ -140,8 +148,30 @@ impl Command {
140
148
cmd. stderr_inherit ( )
141
149
} ;
142
150
151
+ let env = env_changes ( & self . env ) ;
152
+
153
+ // Set any new vars
154
+ if let Some ( e) = & env {
155
+ for ( k, ( _, v) ) in e {
156
+ match v {
157
+ Some ( v) => crate :: env:: set_var ( k, v) ,
158
+ None => crate :: env:: remove_var ( k) ,
159
+ }
160
+ }
161
+ }
162
+
143
163
let stat = cmd. start_image ( ) ?;
144
164
165
+ // Rollback any env changes
166
+ if let Some ( e) = env {
167
+ for ( k, ( v, _) ) in e {
168
+ match v {
169
+ Some ( v) => crate :: env:: set_var ( k, v) ,
170
+ None => crate :: env:: remove_var ( k) ,
171
+ }
172
+ }
173
+ }
174
+
145
175
let stdout = cmd. stdout ( ) ?;
146
176
let stderr = cmd. stderr ( ) ?;
147
177
@@ -725,3 +755,32 @@ mod uefi_command_internal {
725
755
res. into_boxed_slice ( )
726
756
}
727
757
}
758
+
759
+ /// Create a map of environment variable changes. Allows efficient setting and rolling back of
760
+ /// enviroment variable changes.
761
+ ///
762
+ /// Entry: (Old Value, New Value)
763
+ fn env_changes ( env : & CommandEnv ) -> Option < BTreeMap < EnvKey , ( Option < OsString > , Option < OsString > ) > > {
764
+ if env. is_unchanged ( ) {
765
+ return None ;
766
+ }
767
+
768
+ let mut result = BTreeMap :: < EnvKey , ( Option < OsString > , Option < OsString > ) > :: new ( ) ;
769
+
770
+ // Check if we want to clear all prior variables
771
+ if env. does_clear ( ) {
772
+ for ( k, v) in crate :: env:: vars_os ( ) {
773
+ result. insert ( k. into ( ) , ( Some ( v) , None ) ) ;
774
+ }
775
+ }
776
+
777
+ for ( k, v) in env. iter ( ) {
778
+ let v: Option < OsString > = v. map ( Into :: into) ;
779
+ result
780
+ . entry ( k. into ( ) )
781
+ . and_modify ( |cur| * cur = ( cur. 0 . clone ( ) , v. clone ( ) ) )
782
+ . or_insert ( ( crate :: env:: var_os ( k) , v) ) ;
783
+ }
784
+
785
+ Some ( result)
786
+ }
0 commit comments