1 // Copyright 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.
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.
11 //! A thin wrapper around `Command` in the standard library which allows us to
12 //! read the arguments that are built up.
14 use std::ffi::{OsStr, OsString};
18 use std::process::{self, Output};
24 env: Vec<(OsString, OsString)>,
30 CmdBatScript(OsString),
34 pub fn new<P: AsRef<OsStr>>(program: P) -> Command {
35 Command::_new(Program::Normal(program.as_ref().to_owned()))
38 pub fn bat_script<P: AsRef<OsStr>>(program: P) -> Command {
39 Command::_new(Program::CmdBatScript(program.as_ref().to_owned()))
42 fn _new(program: Program) -> Command {
50 pub fn arg<P: AsRef<OsStr>>(&mut self, arg: P) -> &mut Command {
51 self._arg(arg.as_ref());
55 pub fn args<I>(&mut self, args: I) -> &mut Command
56 where I: IntoIterator,
57 I::Item: AsRef<OsStr>,
60 self._arg(arg.as_ref());
65 fn _arg(&mut self, arg: &OsStr) {
66 self.args.push(arg.to_owned());
69 pub fn env<K, V>(&mut self, key: K, value: V) -> &mut Command
70 where K: AsRef<OsStr>,
73 self._env(key.as_ref(), value.as_ref());
77 pub fn envs<I, K, V>(&mut self, envs: I) -> &mut Command
78 where I: IntoIterator<Item=(K, V)>,
82 for (key, value) in envs {
83 self._env(key.as_ref(), value.as_ref());
88 fn _env(&mut self, key: &OsStr, value: &OsStr) {
89 self.env.push((key.to_owned(), value.to_owned()));
92 pub fn output(&mut self) -> io::Result<Output> {
93 self.command().output()
96 pub fn command(&self) -> process::Command {
97 let mut ret = match self.program {
98 Program::Normal(ref p) => process::Command::new(p),
99 Program::CmdBatScript(ref p) => {
100 let mut c = process::Command::new("cmd");
105 ret.args(&self.args);
106 ret.envs(self.env.clone());
112 pub fn take_args(&mut self) -> Vec<OsString> {
113 mem::replace(&mut self.args, Vec::new())
116 /// Returns a `true` if we're pretty sure that this'll blow OS spawn limits,
117 /// or `false` if we should attempt to spawn and see what the OS says.
118 pub fn very_likely_to_exceed_some_spawn_limit(&self) -> bool {
119 // We mostly only care about Windows in this method, on Unix the limits
120 // can be gargantuan anyway so we're pretty unlikely to hit them
125 // Ok so on Windows to spawn a process is 32,768 characters in its
126 // command line [1]. Unfortunately we don't actually have access to that
127 // as it's calculated just before spawning. Instead we perform a
128 // poor-man's guess as to how long our command line will be. We're
129 // assuming here that we don't have to escape every character...
131 // Turns out though that `cmd.exe` has even smaller limits, 8192
132 // characters [2]. Linkers can often be batch scripts (for example
133 // Emscripten, Gecko's current build system) which means that we're
134 // running through batch scripts. These linkers often just forward
135 // arguments elsewhere (and maybe tack on more), so if we blow 8192
136 // bytes we'll typically cause them to blow as well.
138 // Basically as a result just perform an inflated estimate of what our
139 // command line will look like and test if it's > 8192 (we actually
140 // test against 6k to artificially inflate our estimate). If all else
141 // fails we'll fall back to the normal unix logic of testing the OS
142 // error code if we fail to spawn and automatically re-spawning the
143 // linker with smaller arguments.
145 // [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682425(v=vs.85).aspx
146 // [2]: https://blogs.msdn.microsoft.com/oldnewthing/20031210-00/?p=41553
148 let estimated_command_line_len =
149 self.args.iter().map(|a| a.len()).sum::<usize>();
150 estimated_command_line_len > 1024 * 6
154 impl fmt::Debug for Command {
155 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
156 self.command().fmt(f)