Skip to content

Commit 5ef6128

Browse files
committed
Split CommandEnv into OS specific implementations
Also add unsupported implementation of `CommandEnv`.
1 parent 5217347 commit 5ef6128

File tree

7 files changed

+226
-146
lines changed

7 files changed

+226
-146
lines changed

library/std/src/process.rs

+33-3
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,6 @@ use crate::path::Path;
115115
use crate::str;
116116
use crate::sys::pipe::{read2, AnonPipe};
117117
use crate::sys::process as imp;
118-
#[unstable(feature = "command_access", issue = "44434")]
119-
pub use crate::sys_common::process::CommandEnvs;
120118
use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
121119

122120
/// Representation of a running or exited child process.
@@ -1006,7 +1004,7 @@ impl Command {
10061004
/// ```
10071005
#[unstable(feature = "command_access", issue = "44434")]
10081006
pub fn get_envs(&self) -> CommandEnvs<'_> {
1009-
self.inner.get_envs()
1007+
CommandEnvs { iter: self.inner.get_envs() }
10101008
}
10111009

10121010
/// Returns the working directory for the child process.
@@ -2058,3 +2056,35 @@ impl Termination for ExitCode {
20582056
self.0.as_i32()
20592057
}
20602058
}
2059+
2060+
/// An iterator over the command environment variables.
2061+
///
2062+
/// This struct is created by
2063+
/// [`Command::get_envs`][crate::process::Command::get_envs]. See its
2064+
/// documentation for more.
2065+
#[unstable(feature = "command_access", issue = "44434")]
2066+
#[derive(Debug)]
2067+
pub struct CommandEnvs<'a> {
2068+
iter: imp::CommandEnvs<'a>,
2069+
}
2070+
2071+
#[unstable(feature = "command_access", issue = "44434")]
2072+
impl<'a> Iterator for CommandEnvs<'a> {
2073+
type Item = (&'a OsStr, Option<&'a OsStr>);
2074+
fn next(&mut self) -> Option<Self::Item> {
2075+
self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref()))
2076+
}
2077+
fn size_hint(&self) -> (usize, Option<usize>) {
2078+
self.iter.size_hint()
2079+
}
2080+
}
2081+
2082+
#[unstable(feature = "command_access", issue = "44434")]
2083+
impl<'a> ExactSizeIterator for CommandEnvs<'a> {
2084+
fn len(&self) -> usize {
2085+
self.iter.len()
2086+
}
2087+
fn is_empty(&self) -> bool {
2088+
self.iter.is_empty()
2089+
}
2090+
}

library/std/src/sys/unix/process/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes};
1+
pub use self::process_common::{Command, CommandArgs, CommandEnvs, ExitCode, Stdio, StdioPipes};
22
pub use self::process_inner::{ExitStatus, ExitStatusError, Process};
33
pub use crate::ffi::OsString as EnvKey;
4-
pub use crate::sys_common::process::CommandEnvs;
54

65
mod process_common;
76

library/std/src/sys/unix/process/process_common.rs

+98-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ mod tests;
33

44
use crate::os::unix::prelude::*;
55

6-
use crate::collections::BTreeMap;
6+
use crate::collections::{btree_map, BTreeMap};
7+
use crate::env;
78
use crate::ffi::{CStr, CString, OsStr, OsString};
89
use crate::fmt;
910
use crate::io;
@@ -12,7 +13,7 @@ use crate::ptr;
1213
use crate::sys::fd::FileDesc;
1314
use crate::sys::fs::File;
1415
use crate::sys::pipe::{self, AnonPipe};
15-
use crate::sys_common::process::{CommandEnv, CommandEnvs};
16+
use crate::sys::process::EnvKey;
1617
use 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+
327423
fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
328424
CString::new(s.as_bytes()).unwrap_or_else(|_e| {
329425
*saw_nul = true;

library/std/src/sys/unsupported/process.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use crate::ffi::OsStr;
1+
use crate::collections::{btree_map, BTreeMap};
2+
use crate::ffi::{OsStr, OsString};
23
use crate::fmt;
34
use crate::io;
45
use crate::marker::PhantomData;
@@ -7,7 +8,6 @@ use crate::path::Path;
78
use crate::sys::fs::File;
89
use crate::sys::pipe::AnonPipe;
910
use crate::sys::unsupported;
10-
use crate::sys_common::process::{CommandEnv, CommandEnvs};
1111

1212
pub use crate::ffi::OsString as EnvKey;
1313

@@ -95,6 +95,33 @@ impl fmt::Debug for Command {
9595
}
9696
}
9797

98+
// An iterator over environment key/values.
99+
pub type CommandEnvs<'a> = btree_map::Iter<'a, EnvKey, Option<OsString>>;
100+
101+
// Stores a set of changes to an environment
102+
#[derive(Clone, Debug, Default)]
103+
pub struct CommandEnv {
104+
vars: BTreeMap<EnvKey, Option<OsString>>,
105+
}
106+
107+
impl CommandEnv {
108+
pub fn set(&mut self, key: &OsStr, value: &OsStr) {
109+
self.vars.insert(key.to_owned().into(), Some(value.to_owned()));
110+
}
111+
112+
pub fn remove(&mut self, key: &OsStr) {
113+
self.vars.remove(key);
114+
}
115+
116+
pub fn clear(&mut self) {
117+
self.vars.clear();
118+
}
119+
120+
pub fn iter(&self) -> CommandEnvs<'_> {
121+
self.vars.iter()
122+
}
123+
}
124+
98125
pub struct ExitStatus(!);
99126

100127
impl ExitStatus {

library/std/src/sys/windows/process.rs

+65-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
mod tests;
55

66
use crate::cmp;
7-
use crate::collections::BTreeMap;
7+
use crate::collections::{btree_map, BTreeMap};
88
use crate::convert::{TryFrom, TryInto};
99
use crate::env;
1010
use crate::env::split_paths;
@@ -26,7 +26,6 @@ use crate::sys::handle::Handle;
2626
use crate::sys::pipe::{self, AnonPipe};
2727
use crate::sys::stdio;
2828
use crate::sys_common::mutex::StaticMutex;
29-
use crate::sys_common::process::{CommandEnv, CommandEnvs};
3029
use crate::sys_common::{AsInner, IntoInner};
3130

3231
use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS};
@@ -147,6 +146,70 @@ impl AsRef<OsStr> for EnvKey {
147146
}
148147
}
149148

149+
// An iterator over environment key/values.
150+
pub type CommandEnvs<'a> = btree_map::Iter<'a, EnvKey, Option<OsString>>;
151+
152+
// Stores a set of changes to an environment
153+
#[derive(Clone, Debug)]
154+
pub struct CommandEnv {
155+
clear: bool,
156+
vars: BTreeMap<EnvKey, Option<OsString>>,
157+
}
158+
159+
impl Default for CommandEnv {
160+
fn default() -> Self {
161+
CommandEnv { clear: false, vars: Default::default() }
162+
}
163+
}
164+
165+
impl CommandEnv {
166+
// The following functions build up changes
167+
pub fn set(&mut self, key: &OsStr, value: &OsStr) {
168+
let key = EnvKey::from(key);
169+
self.vars.insert(key, Some(value.to_owned()));
170+
}
171+
172+
pub fn remove(&mut self, key: &OsStr) {
173+
let key = EnvKey::from(key);
174+
if self.clear {
175+
self.vars.remove(&key);
176+
} else {
177+
self.vars.insert(key, None);
178+
}
179+
}
180+
181+
pub fn clear(&mut self) {
182+
self.clear = true;
183+
self.vars.clear();
184+
}
185+
186+
pub fn iter(&self) -> CommandEnvs<'_> {
187+
self.vars.iter()
188+
}
189+
190+
// Capture the current environment with these changes applied if the have been changed.
191+
fn capture_if_changed(&self) -> Option<BTreeMap<EnvKey, OsString>> {
192+
if self.clear || !self.vars.is_empty() {
193+
let mut result = BTreeMap::<EnvKey, OsString>::new();
194+
if !self.clear {
195+
for (k, v) in env::vars_os() {
196+
result.insert(k.into(), v);
197+
}
198+
}
199+
for (k, maybe_v) in &self.vars {
200+
if let &Some(ref v) = maybe_v {
201+
result.insert(k.clone(), v.clone());
202+
} else {
203+
result.remove(k);
204+
}
205+
}
206+
Some(result)
207+
} else {
208+
None
209+
}
210+
}
211+
}
212+
150213
fn ensure_no_nuls<T: AsRef<OsStr>>(str: T) -> io::Result<T> {
151214
if str.as_ref().encode_wide().any(|b| b == 0) {
152215
Err(io::Error::new_const(ErrorKind::InvalidInput, &"nul byte found in provided data"))

library/std/src/sys_common/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ pub mod fs;
2626
pub mod io;
2727
pub mod memchr;
2828
pub mod mutex;
29-
pub mod process;
3029
pub mod remutex;
3130
#[macro_use]
3231
pub mod rt;

0 commit comments

Comments
 (0)