Skip to content

Commit 94d4589

Browse files
committed
Auto merge of #38856 - zackw:process-envs, r=aturon
Add std::process::Command::envs() `Command::envs()` adds a vector of key-value pairs to the child process environment all at once. Suggested in #38526. This is not fully baked and frankly I'm not sure it even _works_, but I need some help finishing it up, and this is the simplest way to show you what I've got. The problems I know exist and don't know how to solve, from most to least important, are: * [ ] I don't know if the type signature of the new function is correct. * [x] The new test might not be getting run. I didn't see it go by in the output of `x.py test src/libstd --stage 1`. * [x] The tidy check says ``process.rs:402: different `since` than before`` which I don't know what it means. r? @brson
2 parents fc57e40 + 2580950 commit 94d4589

File tree

3 files changed

+99
-3
lines changed

3 files changed

+99
-3
lines changed

src/libstd/process.rs

+36-1
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,9 @@ impl Command {
352352
/// .expect("ls command failed to start");
353353
/// ```
354354
#[stable(feature = "process", since = "1.0.0")]
355-
pub fn args<S: AsRef<OsStr>>(&mut self, args: &[S]) -> &mut Command {
355+
pub fn args<I, S>(&mut self, args: I) -> &mut Command
356+
where I: IntoIterator<Item=S>, S: AsRef<OsStr>
357+
{
356358
for arg in args {
357359
self.arg(arg.as_ref());
358360
}
@@ -384,6 +386,39 @@ impl Command {
384386
self
385387
}
386388

389+
/// Add or update multiple environment variable mappings.
390+
///
391+
/// # Examples
392+
///
393+
/// Basic usage:
394+
/// ```no_run
395+
/// use std::process::{Command, Stdio};
396+
/// use std::env;
397+
/// use std::collections::HashMap;
398+
///
399+
/// let filtered_env : HashMap<String, String> =
400+
/// env::vars().filter(|&(ref k, _)|
401+
/// k == "TERM" || k == "TZ" || k == "LANG" || k == "PATH"
402+
/// ).collect();
403+
///
404+
/// Command::new("printenv")
405+
/// .stdin(Stdio::null())
406+
/// .stdout(Stdio::inherit())
407+
/// .env_clear()
408+
/// .envs(&filtered_env)
409+
/// .spawn()
410+
/// .expect("printenv failed to start");
411+
/// ```
412+
#[unstable(feature = "command_envs", issue = "38526")]
413+
pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Command
414+
where I: IntoIterator<Item=(K, V)>, K: AsRef<OsStr>, V: AsRef<OsStr>
415+
{
416+
for (ref key, ref val) in vars {
417+
self.inner.env(key.as_ref(), val.as_ref());
418+
}
419+
self
420+
}
421+
387422
/// Removes an environment variable mapping.
388423
///
389424
/// # Examples

src/test/run-pass/process-envs.rs

+62
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright 2014, 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// ignore-emscripten
12+
13+
#![feature(command_envs)]
14+
15+
use std::process::Command;
16+
use std::env;
17+
use std::collections::HashMap;
18+
19+
#[cfg(all(unix, not(target_os="android")))]
20+
pub fn env_cmd() -> Command {
21+
Command::new("env")
22+
}
23+
#[cfg(target_os="android")]
24+
pub fn env_cmd() -> Command {
25+
let mut cmd = Command::new("/system/bin/sh");
26+
cmd.arg("-c").arg("set");
27+
cmd
28+
}
29+
30+
#[cfg(windows)]
31+
pub fn env_cmd() -> Command {
32+
let mut cmd = Command::new("cmd");
33+
cmd.arg("/c").arg("set");
34+
cmd
35+
}
36+
37+
fn main() {
38+
// save original environment
39+
let old_env = env::var_os("RUN_TEST_NEW_ENV");
40+
41+
env::set_var("RUN_TEST_NEW_ENV", "123");
42+
43+
// create filtered environment vector
44+
let filtered_env : HashMap<String, String> =
45+
env::vars().filter(|&(ref k, _)| k == "PATH").collect();
46+
47+
let mut cmd = env_cmd();
48+
cmd.env_clear();
49+
cmd.envs(&filtered_env);
50+
51+
// restore original environment
52+
match old_env {
53+
None => env::remove_var("RUN_TEST_NEW_ENV"),
54+
Some(val) => env::set_var("RUN_TEST_NEW_ENV", &val)
55+
}
56+
57+
let result = cmd.output().unwrap();
58+
let output = String::from_utf8_lossy(&result.stdout);
59+
60+
assert!(!output.contains("RUN_TEST_NEW_ENV"),
61+
"found RUN_TEST_NEW_ENV inside of:\n\n{}", output);
62+
}

src/test/run-pass/process-remove-from-env.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ fn main() {
4646
Some(val) => env::set_var("RUN_TEST_NEW_ENV", &val)
4747
}
4848

49-
let prog = cmd.spawn().unwrap();
50-
let result = prog.wait_with_output().unwrap();
49+
let result = cmd.output().unwrap();
5150
let output = String::from_utf8_lossy(&result.stdout);
5251

5352
assert!(!output.contains("RUN_TEST_NEW_ENV"),

0 commit comments

Comments
 (0)