@@ -3,7 +3,8 @@ mod tests;
33
44use crate :: os:: unix:: prelude:: * ;
55
6- use crate :: collections:: BTreeMap ;
6+ use crate :: collections:: { btree_map, BTreeMap } ;
7+ use crate :: env;
78use crate :: ffi:: { CStr , CString , OsStr , OsString } ;
89use crate :: fmt;
910use crate :: io;
@@ -12,7 +13,7 @@ use crate::ptr;
1213use crate :: sys:: fd:: FileDesc ;
1314use crate :: sys:: fs:: File ;
1415use crate :: sys:: pipe:: { self , AnonPipe } ;
15- use crate :: sys_common :: process:: { CommandEnv , CommandEnvs } ;
16+ use crate :: sys :: process:: EnvKey ;
1617use crate :: sys_common:: IntoInner ;
1718
1819#[ cfg( not( target_os = "fuchsia" ) ) ]
@@ -324,6 +325,101 @@ impl Command {
324325 }
325326}
326327
328+ // An iterator over environment key/values.
329+ pub type CommandEnvs < ' a > = btree_map:: Iter < ' a , EnvKey , Option < OsString > > ;
330+
331+ // Stores a set of changes to an environment
332+ #[ derive( Clone , Debug ) ]
333+ pub struct CommandEnv {
334+ clear : bool ,
335+ saw_path : bool ,
336+ vars : BTreeMap < EnvKey , Option < OsString > > ,
337+ }
338+
339+ impl Default for CommandEnv {
340+ fn default ( ) -> Self {
341+ CommandEnv { clear : false , saw_path : false , vars : Default :: default ( ) }
342+ }
343+ }
344+
345+ impl CommandEnv {
346+ // Capture the current environment with these changes applied
347+ pub fn capture ( & self ) -> BTreeMap < EnvKey , OsString > {
348+ let mut result = BTreeMap :: < EnvKey , OsString > :: new ( ) ;
349+ if !self . clear {
350+ for ( k, v) in env:: vars_os ( ) {
351+ result. insert ( k. into ( ) , v) ;
352+ }
353+ }
354+ for ( k, maybe_v) in & self . vars {
355+ if let & Some ( ref v) = maybe_v {
356+ result. insert ( k. clone ( ) , v. clone ( ) ) ;
357+ } else {
358+ result. remove ( k) ;
359+ }
360+ }
361+ result
362+ }
363+
364+ // Apply these changes directly to the current environment
365+ pub fn apply ( & self ) {
366+ if self . clear {
367+ for ( k, _) in env:: vars_os ( ) {
368+ env:: remove_var ( k) ;
369+ }
370+ }
371+ for ( key, maybe_val) in self . vars . iter ( ) {
372+ if let Some ( ref val) = maybe_val {
373+ env:: set_var ( key, val) ;
374+ } else {
375+ env:: remove_var ( key) ;
376+ }
377+ }
378+ }
379+
380+ pub fn is_unchanged ( & self ) -> bool {
381+ !self . clear && self . vars . is_empty ( )
382+ }
383+
384+ pub fn capture_if_changed ( & self ) -> Option < BTreeMap < EnvKey , OsString > > {
385+ if self . is_unchanged ( ) { None } else { Some ( self . capture ( ) ) }
386+ }
387+
388+ // The following functions build up changes
389+ pub fn set ( & mut self , key : & OsStr , value : & OsStr ) {
390+ self . maybe_saw_path ( & key) ;
391+ self . vars . insert ( key. to_owned ( ) . into ( ) , Some ( value. to_owned ( ) ) ) ;
392+ }
393+
394+ pub fn remove ( & mut self , key : & OsStr ) {
395+ self . maybe_saw_path ( & key) ;
396+ if self . clear {
397+ self . vars . remove ( key) ;
398+ } else {
399+ self . vars . insert ( key. to_owned ( ) . into ( ) , None ) ;
400+ }
401+ }
402+
403+ pub fn clear ( & mut self ) {
404+ self . clear = true ;
405+ self . vars . clear ( ) ;
406+ }
407+
408+ pub fn have_changed_path ( & self ) -> bool {
409+ self . saw_path || self . clear
410+ }
411+
412+ fn maybe_saw_path ( & mut self , key : & OsStr ) {
413+ if !self . saw_path && key == "PATH" {
414+ self . saw_path = true ;
415+ }
416+ }
417+
418+ pub fn iter ( & self ) -> CommandEnvs < ' _ > {
419+ self . vars . iter ( )
420+ }
421+ }
422+
327423fn os2c ( s : & OsStr , saw_nul : & mut bool ) -> CString {
328424 CString :: new ( s. as_bytes ( ) ) . unwrap_or_else ( |_e| {
329425 * saw_nul = true ;
0 commit comments