From 5ef612834f3d761632925b46a7d2c92afeb1f891 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 15 Aug 2021 17:51:21 +0100 Subject: [PATCH 1/2] Split `CommandEnv` into OS specific implementations Also add unsupported implementation of `CommandEnv`. --- library/std/src/process.rs | 36 ++++- library/std/src/sys/unix/process/mod.rs | 3 +- .../src/sys/unix/process/process_common.rs | 100 ++++++++++++- library/std/src/sys/unsupported/process.rs | 31 +++- library/std/src/sys/windows/process.rs | 67 ++++++++- library/std/src/sys_common/mod.rs | 1 - library/std/src/sys_common/process.rs | 134 ------------------ 7 files changed, 226 insertions(+), 146 deletions(-) delete mode 100644 library/std/src/sys_common/process.rs diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c9b21fcf9c6d2..07399b3542d67 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -115,8 +115,6 @@ use crate::path::Path; use crate::str; use crate::sys::pipe::{read2, AnonPipe}; use crate::sys::process as imp; -#[unstable(feature = "command_access", issue = "44434")] -pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// Representation of a running or exited child process. @@ -1006,7 +1004,7 @@ impl Command { /// ``` #[unstable(feature = "command_access", issue = "44434")] pub fn get_envs(&self) -> CommandEnvs<'_> { - self.inner.get_envs() + CommandEnvs { iter: self.inner.get_envs() } } /// Returns the working directory for the child process. @@ -2058,3 +2056,35 @@ impl Termination for ExitCode { self.0.as_i32() } } + +/// An iterator over the command environment variables. +/// +/// This struct is created by +/// [`Command::get_envs`][crate::process::Command::get_envs]. See its +/// documentation for more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandEnvs<'a> { + iter: imp::CommandEnvs<'a>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandEnvs<'a> { + type Item = (&'a OsStr, Option<&'a OsStr>); + fn next(&mut self) -> Option { + self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandEnvs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 0165ece849ee5..9eca145cb3c84 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -1,7 +1,6 @@ -pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; +pub use self::process_common::{Command, CommandArgs, CommandEnvs, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::{ExitStatus, ExitStatusError, Process}; pub use crate::ffi::OsString as EnvKey; -pub use crate::sys_common::process::CommandEnvs; mod process_common; diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 7b261a302c33f..e092cc77bae43 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -3,7 +3,8 @@ mod tests; use crate::os::unix::prelude::*; -use crate::collections::BTreeMap; +use crate::collections::{btree_map, BTreeMap}; +use crate::env; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io; @@ -12,7 +13,7 @@ use crate::ptr; use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; +use crate::sys::process::EnvKey; use crate::sys_common::IntoInner; #[cfg(not(target_os = "fuchsia"))] @@ -324,6 +325,101 @@ impl Command { } } +// An iterator over environment key/values. +pub type CommandEnvs<'a> = btree_map::Iter<'a, EnvKey, Option>; + +// Stores a set of changes to an environment +#[derive(Clone, Debug)] +pub struct CommandEnv { + clear: bool, + saw_path: bool, + vars: BTreeMap>, +} + +impl Default for CommandEnv { + fn default() -> Self { + CommandEnv { clear: false, saw_path: false, vars: Default::default() } + } +} + +impl CommandEnv { + // Capture the current environment with these changes applied + pub fn capture(&self) -> BTreeMap { + let mut result = BTreeMap::::new(); + if !self.clear { + for (k, v) in env::vars_os() { + result.insert(k.into(), v); + } + } + for (k, maybe_v) in &self.vars { + if let &Some(ref v) = maybe_v { + result.insert(k.clone(), v.clone()); + } else { + result.remove(k); + } + } + result + } + + // Apply these changes directly to the current environment + pub fn apply(&self) { + if self.clear { + for (k, _) in env::vars_os() { + env::remove_var(k); + } + } + for (key, maybe_val) in self.vars.iter() { + if let Some(ref val) = maybe_val { + env::set_var(key, val); + } else { + env::remove_var(key); + } + } + } + + pub fn is_unchanged(&self) -> bool { + !self.clear && self.vars.is_empty() + } + + pub fn capture_if_changed(&self) -> Option> { + if self.is_unchanged() { None } else { Some(self.capture()) } + } + + // The following functions build up changes + pub fn set(&mut self, key: &OsStr, value: &OsStr) { + self.maybe_saw_path(&key); + self.vars.insert(key.to_owned().into(), Some(value.to_owned())); + } + + pub fn remove(&mut self, key: &OsStr) { + self.maybe_saw_path(&key); + if self.clear { + self.vars.remove(key); + } else { + self.vars.insert(key.to_owned().into(), None); + } + } + + pub fn clear(&mut self) { + self.clear = true; + self.vars.clear(); + } + + pub fn have_changed_path(&self) -> bool { + self.saw_path || self.clear + } + + fn maybe_saw_path(&mut self, key: &OsStr) { + if !self.saw_path && key == "PATH" { + self.saw_path = true; + } + } + + pub fn iter(&self) -> CommandEnvs<'_> { + self.vars.iter() + } +} + fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { CString::new(s.as_bytes()).unwrap_or_else(|_e| { *saw_nul = true; diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 7846e43cfb53e..9c22f65591484 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -1,4 +1,5 @@ -use crate::ffi::OsStr; +use crate::collections::{btree_map, BTreeMap}; +use crate::ffi::{OsStr, OsString}; use crate::fmt; use crate::io; use crate::marker::PhantomData; @@ -7,7 +8,6 @@ use crate::path::Path; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::unsupported; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; pub use crate::ffi::OsString as EnvKey; @@ -95,6 +95,33 @@ impl fmt::Debug for Command { } } +// An iterator over environment key/values. +pub type CommandEnvs<'a> = btree_map::Iter<'a, EnvKey, Option>; + +// Stores a set of changes to an environment +#[derive(Clone, Debug, Default)] +pub struct CommandEnv { + vars: BTreeMap>, +} + +impl CommandEnv { + pub fn set(&mut self, key: &OsStr, value: &OsStr) { + self.vars.insert(key.to_owned().into(), Some(value.to_owned())); + } + + pub fn remove(&mut self, key: &OsStr) { + self.vars.remove(key); + } + + pub fn clear(&mut self) { + self.vars.clear(); + } + + pub fn iter(&self) -> CommandEnvs<'_> { + self.vars.iter() + } +} + pub struct ExitStatus(!); impl ExitStatus { diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index ccff90629a371..c2198ae629f0c 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -4,7 +4,7 @@ mod tests; use crate::cmp; -use crate::collections::BTreeMap; +use crate::collections::{btree_map, BTreeMap}; use crate::convert::{TryFrom, TryInto}; use crate::env; use crate::env::split_paths; @@ -26,7 +26,6 @@ use crate::sys::handle::Handle; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; use crate::sys_common::mutex::StaticMutex; -use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::{AsInner, IntoInner}; use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; @@ -147,6 +146,70 @@ impl AsRef for EnvKey { } } +// An iterator over environment key/values. +pub type CommandEnvs<'a> = btree_map::Iter<'a, EnvKey, Option>; + +// Stores a set of changes to an environment +#[derive(Clone, Debug)] +pub struct CommandEnv { + clear: bool, + vars: BTreeMap>, +} + +impl Default for CommandEnv { + fn default() -> Self { + CommandEnv { clear: false, vars: Default::default() } + } +} + +impl CommandEnv { + // The following functions build up changes + pub fn set(&mut self, key: &OsStr, value: &OsStr) { + let key = EnvKey::from(key); + self.vars.insert(key, Some(value.to_owned())); + } + + pub fn remove(&mut self, key: &OsStr) { + let key = EnvKey::from(key); + if self.clear { + self.vars.remove(&key); + } else { + self.vars.insert(key, None); + } + } + + pub fn clear(&mut self) { + self.clear = true; + self.vars.clear(); + } + + pub fn iter(&self) -> CommandEnvs<'_> { + self.vars.iter() + } + + // Capture the current environment with these changes applied if the have been changed. + fn capture_if_changed(&self) -> Option> { + if self.clear || !self.vars.is_empty() { + let mut result = BTreeMap::::new(); + if !self.clear { + for (k, v) in env::vars_os() { + result.insert(k.into(), v); + } + } + for (k, maybe_v) in &self.vars { + if let &Some(ref v) = maybe_v { + result.insert(k.clone(), v.clone()); + } else { + result.remove(k); + } + } + Some(result) + } else { + None + } + } +} + fn ensure_no_nuls>(str: T) -> io::Result { if str.as_ref().encode_wide().any(|b| b == 0) { Err(io::Error::new_const(ErrorKind::InvalidInput, &"nul byte found in provided data")) diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 894440564b738..b86977a11ab2b 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -26,7 +26,6 @@ pub mod fs; pub mod io; pub mod memchr; pub mod mutex; -pub mod process; pub mod remutex; #[macro_use] pub mod rt; diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs deleted file mode 100644 index 38007d5c414ec..0000000000000 --- a/library/std/src/sys_common/process.rs +++ /dev/null @@ -1,134 +0,0 @@ -#![allow(dead_code)] -#![unstable(feature = "process_internals", issue = "none")] - -use crate::collections::BTreeMap; -use crate::env; -use crate::ffi::{OsStr, OsString}; -use crate::sys::process::EnvKey; - -// Stores a set of changes to an environment -#[derive(Clone, Debug)] -pub struct CommandEnv { - clear: bool, - saw_path: bool, - vars: BTreeMap>, -} - -impl Default for CommandEnv { - fn default() -> Self { - CommandEnv { clear: false, saw_path: false, vars: Default::default() } - } -} - -impl CommandEnv { - // Capture the current environment with these changes applied - pub fn capture(&self) -> BTreeMap { - let mut result = BTreeMap::::new(); - if !self.clear { - for (k, v) in env::vars_os() { - result.insert(k.into(), v); - } - } - for (k, maybe_v) in &self.vars { - if let &Some(ref v) = maybe_v { - result.insert(k.clone(), v.clone()); - } else { - result.remove(k); - } - } - result - } - - // Apply these changes directly to the current environment - pub fn apply(&self) { - if self.clear { - for (k, _) in env::vars_os() { - env::remove_var(k); - } - } - for (key, maybe_val) in self.vars.iter() { - if let Some(ref val) = maybe_val { - env::set_var(key, val); - } else { - env::remove_var(key); - } - } - } - - pub fn is_unchanged(&self) -> bool { - !self.clear && self.vars.is_empty() - } - - pub fn capture_if_changed(&self) -> Option> { - if self.is_unchanged() { None } else { Some(self.capture()) } - } - - // The following functions build up changes - pub fn set(&mut self, key: &OsStr, value: &OsStr) { - let key = EnvKey::from(key); - self.maybe_saw_path(&key); - self.vars.insert(key, Some(value.to_owned())); - } - - pub fn remove(&mut self, key: &OsStr) { - let key = EnvKey::from(key); - self.maybe_saw_path(&key); - if self.clear { - self.vars.remove(&key); - } else { - self.vars.insert(key, None); - } - } - - pub fn clear(&mut self) { - self.clear = true; - self.vars.clear(); - } - - pub fn have_changed_path(&self) -> bool { - self.saw_path || self.clear - } - - fn maybe_saw_path(&mut self, key: &EnvKey) { - if !self.saw_path && key == "PATH" { - self.saw_path = true; - } - } - - pub fn iter(&self) -> CommandEnvs<'_> { - let iter = self.vars.iter(); - CommandEnvs { iter } - } -} - -/// An iterator over the command environment variables. -/// -/// This struct is created by -/// [`Command::get_envs`][crate::process::Command::get_envs]. See its -/// documentation for more. -#[unstable(feature = "command_access", issue = "44434")] -#[derive(Debug)] -pub struct CommandEnvs<'a> { - iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, -} - -#[unstable(feature = "command_access", issue = "44434")] -impl<'a> Iterator for CommandEnvs<'a> { - type Item = (&'a OsStr, Option<&'a OsStr>); - fn next(&mut self) -> Option { - self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) - } - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -#[unstable(feature = "command_access", issue = "44434")] -impl<'a> ExactSizeIterator for CommandEnvs<'a> { - fn len(&self) -> usize { - self.iter.len() - } - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} From 176d0bff52613ef8a0131f4ef3899005a9f0be80 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sun, 15 Aug 2021 17:59:40 +0100 Subject: [PATCH 2/2] Remove unused `CommandEnv::apply` --- .../std/src/sys/unix/process/process_common.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index e092cc77bae43..a70c24dcc9e6e 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -361,22 +361,6 @@ impl CommandEnv { result } - // Apply these changes directly to the current environment - pub fn apply(&self) { - if self.clear { - for (k, _) in env::vars_os() { - env::remove_var(k); - } - } - for (key, maybe_val) in self.vars.iter() { - if let Some(ref val) = maybe_val { - env::set_var(key, val); - } else { - env::remove_var(key); - } - } - } - pub fn is_unchanged(&self) -> bool { !self.clear && self.vars.is_empty() }