diff options
Diffstat (limited to 'library/std/src/sys/process/env.rs')
| -rw-r--r-- | library/std/src/sys/process/env.rs | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/library/std/src/sys/process/env.rs b/library/std/src/sys/process/env.rs new file mode 100644 index 00000000000..e08b476540e --- /dev/null +++ b/library/std/src/sys/process/env.rs @@ -0,0 +1,115 @@ +use crate::collections::BTreeMap; +use crate::ffi::{OsStr, OsString}; +use crate::sys::process::EnvKey; +use crate::{env, fmt}; + +/// Stores a set of changes to an environment +#[derive(Clone, Default)] +pub struct CommandEnv { + clear: bool, + saw_path: bool, + vars: BTreeMap<EnvKey, Option<OsString>>, +} + +impl fmt::Debug for CommandEnv { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut debug_command_env = f.debug_struct("CommandEnv"); + debug_command_env.field("clear", &self.clear).field("vars", &self.vars); + debug_command_env.finish() + } +} + +impl CommandEnv { + // Capture the current environment with these changes applied + pub fn capture(&self) -> BTreeMap<EnvKey, OsString> { + let mut result = BTreeMap::<EnvKey, OsString>::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 + } + + pub fn is_unchanged(&self) -> bool { + !self.clear && self.vars.is_empty() + } + + pub fn capture_if_changed(&self) -> Option<BTreeMap<EnvKey, OsString>> { + 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 does_clear(&self) -> bool { + self.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 } + } +} + +#[derive(Debug)] +pub struct CommandEnvs<'a> { + iter: crate::collections::btree_map::Iter<'a, EnvKey, Option<OsString>>, +} + +impl<'a> Iterator for CommandEnvs<'a> { + type Item = (&'a OsStr, Option<&'a OsStr>); + + fn next(&mut self) -> Option<Self::Item> { + self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) + } + + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandEnvs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} |
