std/sys_common/
process.rs
1#![allow(dead_code)]
2#![unstable(feature = "process_internals", issue = "none")]
3
4use crate::collections::BTreeMap;
5use crate::ffi::{OsStr, OsString};
6use crate::sys::pipe::read2;
7use crate::sys::process::{EnvKey, ExitStatus, Process, StdioPipes};
8use crate::{env, fmt, io};
9
10#[derive(Clone, Default)]
12pub struct CommandEnv {
13 clear: bool,
14 saw_path: bool,
15 vars: BTreeMap<EnvKey, Option<OsString>>,
16}
17
18impl fmt::Debug for CommandEnv {
19 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20 let mut debug_command_env = f.debug_struct("CommandEnv");
21 debug_command_env.field("clear", &self.clear).field("vars", &self.vars);
22 debug_command_env.finish()
23 }
24}
25
26impl CommandEnv {
27 pub fn capture(&self) -> BTreeMap<EnvKey, OsString> {
29 let mut result = BTreeMap::<EnvKey, OsString>::new();
30 if !self.clear {
31 for (k, v) in env::vars_os() {
32 result.insert(k.into(), v);
33 }
34 }
35 for (k, maybe_v) in &self.vars {
36 if let &Some(ref v) = maybe_v {
37 result.insert(k.clone(), v.clone());
38 } else {
39 result.remove(k);
40 }
41 }
42 result
43 }
44
45 pub fn is_unchanged(&self) -> bool {
46 !self.clear && self.vars.is_empty()
47 }
48
49 pub fn capture_if_changed(&self) -> Option<BTreeMap<EnvKey, OsString>> {
50 if self.is_unchanged() { None } else { Some(self.capture()) }
51 }
52
53 pub fn set(&mut self, key: &OsStr, value: &OsStr) {
55 let key = EnvKey::from(key);
56 self.maybe_saw_path(&key);
57 self.vars.insert(key, Some(value.to_owned()));
58 }
59
60 pub fn remove(&mut self, key: &OsStr) {
61 let key = EnvKey::from(key);
62 self.maybe_saw_path(&key);
63 if self.clear {
64 self.vars.remove(&key);
65 } else {
66 self.vars.insert(key, None);
67 }
68 }
69
70 pub fn clear(&mut self) {
71 self.clear = true;
72 self.vars.clear();
73 }
74
75 pub fn does_clear(&self) -> bool {
76 self.clear
77 }
78
79 pub fn have_changed_path(&self) -> bool {
80 self.saw_path || self.clear
81 }
82
83 fn maybe_saw_path(&mut self, key: &EnvKey) {
84 if !self.saw_path && key == "PATH" {
85 self.saw_path = true;
86 }
87 }
88
89 pub fn iter(&self) -> CommandEnvs<'_> {
90 let iter = self.vars.iter();
91 CommandEnvs { iter }
92 }
93}
94
95#[must_use = "iterators are lazy and do nothing unless consumed"]
101#[stable(feature = "command_access", since = "1.57.0")]
102#[derive(Debug)]
103pub struct CommandEnvs<'a> {
104 iter: crate::collections::btree_map::Iter<'a, EnvKey, Option<OsString>>,
105}
106
107#[stable(feature = "command_access", since = "1.57.0")]
108impl<'a> Iterator for CommandEnvs<'a> {
109 type Item = (&'a OsStr, Option<&'a OsStr>);
110 fn next(&mut self) -> Option<Self::Item> {
111 self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref()))
112 }
113 fn size_hint(&self) -> (usize, Option<usize>) {
114 self.iter.size_hint()
115 }
116}
117
118#[stable(feature = "command_access", since = "1.57.0")]
119impl<'a> ExactSizeIterator for CommandEnvs<'a> {
120 fn len(&self) -> usize {
121 self.iter.len()
122 }
123 fn is_empty(&self) -> bool {
124 self.iter.is_empty()
125 }
126}
127
128pub fn wait_with_output(
129 mut process: Process,
130 mut pipes: StdioPipes,
131) -> io::Result<(ExitStatus, Vec<u8>, Vec<u8>)> {
132 drop(pipes.stdin.take());
133
134 let (mut stdout, mut stderr) = (Vec::new(), Vec::new());
135 match (pipes.stdout.take(), pipes.stderr.take()) {
136 (None, None) => {}
137 (Some(out), None) => {
138 let res = out.read_to_end(&mut stdout);
139 res.unwrap();
140 }
141 (None, Some(err)) => {
142 let res = err.read_to_end(&mut stderr);
143 res.unwrap();
144 }
145 (Some(out), Some(err)) => {
146 let res = read2(out, &mut stdout, err, &mut stderr);
147 res.unwrap();
148 }
149 }
150
151 let status = process.wait()?;
152 Ok((status, stdout, stderr))
153}