@@ -3,7 +3,8 @@ mod tests;
3
3
4
4
use crate :: os:: unix:: prelude:: * ;
5
5
6
- use crate :: collections:: BTreeMap ;
6
+ use crate :: collections:: { btree_map, BTreeMap } ;
7
+ use crate :: env;
7
8
use crate :: ffi:: { CStr , CString , OsStr , OsString } ;
8
9
use crate :: fmt;
9
10
use crate :: io;
@@ -12,7 +13,7 @@ use crate::ptr;
12
13
use crate :: sys:: fd:: FileDesc ;
13
14
use crate :: sys:: fs:: File ;
14
15
use crate :: sys:: pipe:: { self , AnonPipe } ;
15
- use crate :: sys_common :: process:: { CommandEnv , CommandEnvs } ;
16
+ use crate :: sys :: process:: EnvKey ;
16
17
use crate :: sys_common:: IntoInner ;
17
18
18
19
#[ cfg( not( target_os = "fuchsia" ) ) ]
@@ -324,6 +325,101 @@ impl Command {
324
325
}
325
326
}
326
327
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
+
327
423
fn os2c ( s : & OsStr , saw_nul : & mut bool ) -> CString {
328
424
CString :: new ( s. as_bytes ( ) ) . unwrap_or_else ( |_e| {
329
425
* saw_nul = true ;
0 commit comments