Switch from subprocess crate to the builtin std::process (#1284)

* Switch from subprocess crate to the builtin std::process

* Update external.rs

* Update external.rs

* Update external.rs

Co-authored-by: Jonathan Turner <jonathandturner@users.noreply.github.com>
This commit is contained in:
Jason Gedge 2020-01-25 22:03:21 -05:00 committed by Jonathan Turner
parent d48f99cb0e
commit 32dfb32741
8 changed files with 32 additions and 67 deletions

14
Cargo.lock generated
View file

@ -2282,7 +2282,6 @@ dependencies = [
"shellexpand", "shellexpand",
"starship", "starship",
"strip-ansi-escapes", "strip-ansi-escapes",
"subprocess",
"syntect", "syntect",
"tempfile", "tempfile",
"term", "term",
@ -2326,7 +2325,6 @@ dependencies = [
"serde 1.0.104", "serde 1.0.104",
"serde_json", "serde_json",
"serde_yaml", "serde_yaml",
"subprocess",
"toml 0.5.6", "toml 0.5.6",
] ]
@ -2411,7 +2409,6 @@ dependencies = [
"serde_bytes", "serde_bytes",
"serde_json", "serde_json",
"serde_yaml", "serde_yaml",
"subprocess",
"toml 0.5.6", "toml 0.5.6",
"typetag", "typetag",
] ]
@ -3795,17 +3792,6 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
[[package]]
name = "subprocess"
version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68713fc0f9d941642c1e020d622e6421dfe09e8891ddd4bfa2109fda9a40431d"
dependencies = [
"crossbeam-utils 0.7.0",
"libc",
"winapi 0.3.8",
]
[[package]] [[package]]
name = "surf" name = "surf"
version = "1.0.3" version = "1.0.3"

View file

@ -101,7 +101,6 @@ nom_locate = "1.0.0"
nom-tracable = "0.4.1" nom-tracable = "0.4.1"
unicode-xid = "0.2.0" unicode-xid = "0.2.0"
serde_ini = "0.2.0" serde_ini = "0.2.0"
subprocess = "0.1.20"
pretty-hex = "0.1.1" pretty-hex = "0.1.1"
hex = "0.4" hex = "0.4"
tempfile = "3.1.0" tempfile = "3.1.0"

View file

@ -24,7 +24,6 @@ nom_locate = "1.0.0"
getset = "0.0.9" getset = "0.0.9"
# implement conversions # implement conversions
subprocess = "0.1.18"
serde_yaml = "0.8" serde_yaml = "0.8"
toml = "0.5.5" toml = "0.5.5"
serde_json = "1.0.44" serde_json = "1.0.44"

View file

@ -821,12 +821,6 @@ impl std::convert::From<std::io::Error> for ShellError {
} }
} }
impl std::convert::From<subprocess::PopenError> for ShellError {
fn from(input: subprocess::PopenError) -> ShellError {
ShellError::untagged_runtime_error(format!("{}", input))
}
}
impl std::convert::From<serde_yaml::Error> for ShellError { impl std::convert::From<serde_yaml::Error> for ShellError {
fn from(input: serde_yaml::Error) -> ShellError { fn from(input: serde_yaml::Error) -> ShellError {
ShellError::untagged_runtime_error(format!("{:?}", input)) ShellError::untagged_runtime_error(format!("{:?}", input))

View file

@ -33,7 +33,6 @@ byte-unit = "3.0.3"
natural = "0.3.0" natural = "0.3.0"
# implement conversions # implement conversions
subprocess = "0.1.18"
serde_yaml = "0.8" serde_yaml = "0.8"
toml = "0.5.5" toml = "0.5.5"
serde_json = "1.0.44" serde_json = "1.0.44"

View file

@ -70,7 +70,6 @@ rustyline = "4.1.0"
serde = "1.0.91" serde = "1.0.91"
serde_derive = "1.0.91" serde_derive = "1.0.91"
serde_json = "1.0.39" serde_json = "1.0.39"
subprocess = "0.1.18"
sysinfo = "0.8.4" sysinfo = "0.8.4"
term = "0.5.2" term = "0.5.2"
tokio-fs = "0.1.6" tokio-fs = "0.1.6"

View file

@ -1,14 +1,14 @@
use crate::prelude::*; use crate::prelude::*;
use bytes::{BufMut, BytesMut}; use bytes::{BufMut, BytesMut};
use futures::stream::StreamExt; use futures::stream::StreamExt;
use futures_codec::{Decoder, Encoder, Framed}; use futures_codec::{Decoder, Encoder, FramedRead};
use log::trace; use log::trace;
use nu_errors::ShellError; use nu_errors::ShellError;
use nu_parser::ExternalCommand; use nu_parser::ExternalCommand;
use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value}; use nu_protocol::{Primitive, ShellTypeName, UntaggedValue, Value};
use std::io::{Error, ErrorKind, Write}; use std::io::{Error, ErrorKind, Write};
use std::ops::Deref; use std::ops::Deref;
use subprocess::Exec; use std::process::{Command, Stdio};
/// A simple `Codec` implementation that splits up data into lines. /// A simple `Codec` implementation that splits up data into lines.
pub struct LinesCodec {} pub struct LinesCodec {}
@ -275,11 +275,11 @@ async fn spawn(
let mut process = { let mut process = {
#[cfg(windows)] #[cfg(windows)]
{ {
let mut process = Exec::cmd("cmd"); let mut process = Command::new("cmd");
process = process.arg("/c"); process.arg("/c");
process = process.arg(&command.name); process.arg(&command.name);
for arg in args { for arg in args {
process = process.arg(&arg); process.arg(&arg);
} }
process process
} }
@ -287,34 +287,34 @@ async fn spawn(
#[cfg(not(windows))] #[cfg(not(windows))]
{ {
let cmd_with_args = vec![command.name.clone(), args.join(" ")].join(" "); let cmd_with_args = vec![command.name.clone(), args.join(" ")].join(" ");
Exec::shell(&cmd_with_args) let mut process = Command::new("sh");
process.arg("-c").arg(cmd_with_args);
process
} }
}; };
process = process.cwd(path); process.current_dir(path);
trace!(target: "nu::run::external", "cwd = {:?}", &path); trace!(target: "nu::run::external", "cwd = {:?}", &path);
// We want stdout regardless of what // We want stdout regardless of what
// we are doing ($it case or pipe stdin) // we are doing ($it case or pipe stdin)
if !is_last { if !is_last {
process = process.stdout(subprocess::Redirection::Pipe); process.stdout(Stdio::piped());
trace!(target: "nu::run::external", "set up stdout pipe"); trace!(target: "nu::run::external", "set up stdout pipe");
} }
// open since we have some contents for stdin // open since we have some contents for stdin
if stdin_contents.is_some() { if stdin_contents.is_some() {
process = process.stdin(subprocess::Redirection::Pipe); process.stdin(Stdio::piped());
trace!(target: "nu::run::external", "set up stdin pipe"); trace!(target: "nu::run::external", "set up stdin pipe");
} }
trace!(target: "nu::run::external", "built process {:?}", process); trace!(target: "nu::run::external", "built command {:?}", process);
let popen = process.detached().popen(); if let Ok(mut child) = process.spawn() {
if let Ok(mut popen) = popen {
let stream = async_stream! { let stream = async_stream! {
if let Some(mut input) = stdin_contents.as_ref() { if let Some(mut input) = stdin_contents.as_ref() {
let mut stdin_write = popen.stdin let mut stdin_write = child.stdin
.take() .take()
.expect("Internal error: could not get stdin pipe for external command"); .expect("Internal error: could not get stdin pipe for external command");
@ -335,7 +335,7 @@ async fn spawn(
} }
if is_last && command.has_it_argument() { if is_last && command.has_it_argument() {
if let Ok(status) = popen.wait() { if let Ok(status) = child.wait() {
if status.success() { if status.success() {
return; return;
} }
@ -362,7 +362,7 @@ async fn spawn(
} }
if !is_last { if !is_last {
let stdout = if let Some(stdout) = popen.stdout.take() { let stdout = if let Some(stdout) = child.stdout.take() {
stdout stdout
} else { } else {
yield Ok(Value { yield Ok(Value {
@ -376,7 +376,7 @@ async fn spawn(
}; };
let file = futures::io::AllowStdIo::new(stdout); let file = futures::io::AllowStdIo::new(stdout);
let stream = Framed::new(file, LinesCodec {}); let stream = FramedRead::new(file, LinesCodec {});
let mut stream = stream.map(|line| { let mut stream = stream.map(|line| {
if let Ok(line) = line { if let Ok(line) = line {
@ -394,30 +394,20 @@ async fn spawn(
} }
} }
loop { if child.wait().is_err() {
match popen.poll() { let cfg = crate::data::config::config(Tag::unknown());
None => futures_timer::Delay::new(std::time::Duration::from_millis(10)).await, if let Ok(cfg) = cfg {
Some(status) => { if cfg.contains_key("nonzero_exit_errors") {
if !status.success() { yield Ok(Value {
// We can give an error when we see a non-zero exit code, but this is different value: UntaggedValue::Error(
// than what other shells will do. ShellError::labeled_error(
let cfg = crate::data::config::config(Tag::unknown()); "External command failed",
if let Ok(cfg) = cfg { "command failed",
if cfg.contains_key("nonzero_exit_errors") { &name_tag,
yield Ok(Value { )
value: UntaggedValue::Error( ),
ShellError::labeled_error( tag: name_tag,
"External command failed", });
"command failed",
&name_tag,
)
),
tag: name_tag,
});
}
}
}
break;
} }
} }
} }

View file

@ -19,7 +19,6 @@ itertools = "0.8.0"
ansi_term = "0.11.0" ansi_term = "0.11.0"
conch-parser = "0.1.1" conch-parser = "0.1.1"
nom = "5.0.0-beta1" nom = "5.0.0-beta1"
subprocess = "0.1.18"
dunce = "1.0.0" dunce = "1.0.0"
indexmap = { version = "1.0.2", features = ["serde-1"] } indexmap = { version = "1.0.2", features = ["serde-1"] }
chrono-humanize = "0.0.11" chrono-humanize = "0.0.11"