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