11use r_efi:: protocols:: simple_text_output;
22
33use super :: helpers;
4+ use crate :: collections:: BTreeMap ;
45pub use crate :: ffi:: OsString as EnvKey ;
56use crate :: ffi:: { OsStr , OsString } ;
67use crate :: num:: { NonZero , NonZeroI32 } ;
@@ -21,6 +22,7 @@ pub struct Command {
2122 args : Vec < OsString > ,
2223 stdout : Option < Stdio > ,
2324 stderr : Option < Stdio > ,
25+ env : CommandEnv ,
2426}
2527
2628// passed back to std::process with the pipes connected to the child, if any
@@ -40,15 +42,21 @@ pub enum Stdio {
4042
4143impl Command {
4244 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+ }
4452 }
4553
4654 pub fn arg ( & mut self , arg : & OsStr ) {
4755 self . args . push ( arg. to_os_string ( ) ) ;
4856 }
4957
5058 pub fn env_mut ( & mut self ) -> & mut CommandEnv {
51- panic ! ( "unsupported" )
59+ & mut self . env
5260 }
5361
5462 pub fn cwd ( & mut self , _dir : & OsStr ) {
@@ -76,7 +84,7 @@ impl Command {
7684 }
7785
7886 pub fn get_envs ( & self ) -> CommandEnvs < ' _ > {
79- panic ! ( "unsupported" )
87+ self . env . iter ( )
8088 }
8189
8290 pub fn get_current_dir ( & self ) -> Option < & Path > {
@@ -140,8 +148,30 @@ impl Command {
140148 cmd. stderr_inherit ( )
141149 } ;
142150
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+
143163 let stat = cmd. start_image ( ) ?;
144164
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+
145175 let stdout = cmd. stdout ( ) ?;
146176 let stderr = cmd. stderr ( ) ?;
147177
@@ -725,3 +755,32 @@ mod uefi_command_internal {
725755 res. into_boxed_slice ( )
726756 }
727757}
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