mirror of
https://github.com/nushell/nushell.git
synced 2024-11-22 08:23:24 +01:00
Only spawn external once when no $it argument (#1358)
This commit is contained in:
parent
643b532537
commit
3687603799
@ -8,12 +8,9 @@ fn main() {
|
|||||||
|
|
||||||
// if no arguments given, chop from standard input and exit.
|
// if no arguments given, chop from standard input and exit.
|
||||||
let stdin = io::stdin();
|
let stdin = io::stdin();
|
||||||
let mut input = stdin.lock().lines();
|
for line in stdin.lock().lines() {
|
||||||
|
if let Ok(given) = line {
|
||||||
if let Some(Ok(given)) = input.next() {
|
|
||||||
if !given.is_empty() {
|
|
||||||
println!("{}", chop(&given));
|
println!("{}", chop(&given));
|
||||||
std::process::exit(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,9 +18,12 @@ fn main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn chop(word: &str) -> &str {
|
fn chop(word: &str) -> &str {
|
||||||
let to = word.len() - 1;
|
if word.is_empty() {
|
||||||
|
word
|
||||||
&word[..to]
|
} else {
|
||||||
|
let to = word.len() - 1;
|
||||||
|
&word[..to]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn did_chop_arguments() -> bool {
|
fn did_chop_arguments() -> bool {
|
||||||
|
@ -121,7 +121,7 @@ async fn run_with_iterator_arg(
|
|||||||
}
|
}
|
||||||
}).collect::<Vec<String>>();
|
}).collect::<Vec<String>>();
|
||||||
|
|
||||||
match spawn(&command, &path, &process_args[..], None, is_last).await {
|
match spawn(&command, &path, &process_args[..], None, is_last) {
|
||||||
Ok(res) => {
|
Ok(res) => {
|
||||||
if let Some(mut res) = res {
|
if let Some(mut res) = res {
|
||||||
while let Some(item) = res.next().await {
|
while let Some(item) = res.next().await {
|
||||||
@ -151,83 +151,46 @@ async fn run_with_stdin(
|
|||||||
) -> Result<Option<InputStream>, ShellError> {
|
) -> Result<Option<InputStream>, ShellError> {
|
||||||
let path = context.shell_manager.path();
|
let path = context.shell_manager.path();
|
||||||
|
|
||||||
let mut inputs: InputStream = if let Some(input) = input {
|
let input = input
|
||||||
trace_stream!(target: "nu::trace_stream::external::stdin", "input" = input)
|
.map(|input| trace_stream!(target: "nu::trace_stream::external::stdin", "input" = input));
|
||||||
} else {
|
|
||||||
InputStream::empty()
|
|
||||||
};
|
|
||||||
|
|
||||||
let stream = async_stream! {
|
let process_args = command
|
||||||
while let Some(value) = inputs.next().await {
|
.args
|
||||||
let name = command.name.clone();
|
.iter()
|
||||||
let name_tag = command.name_tag.clone();
|
.map(|arg| {
|
||||||
let home_dir = dirs::home_dir();
|
let arg = expand_tilde(arg.deref(), dirs::home_dir);
|
||||||
let path = &path;
|
|
||||||
let args = command.args.clone();
|
|
||||||
|
|
||||||
let value_for_stdin = match nu_value_to_string_for_stdin(&command, &value) {
|
#[cfg(not(windows))]
|
||||||
Ok(value) => value,
|
{
|
||||||
Err(reason) => {
|
if argument_contains_whitespace(&arg) && argument_is_quoted(&arg) {
|
||||||
yield Ok(Value {
|
|
||||||
value: UntaggedValue::Error(reason),
|
|
||||||
tag: name_tag
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let process_args = args.iter().map(|arg| {
|
|
||||||
let arg = expand_tilde(arg.deref(), || home_dir.as_ref());
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
{
|
|
||||||
if argument_contains_whitespace(&arg) && argument_is_quoted(&arg) {
|
|
||||||
if let Some(unquoted) = remove_quotes(&arg) {
|
|
||||||
format!(r#""{}""#, unquoted)
|
|
||||||
} else {
|
|
||||||
arg.as_ref().to_string()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
arg.as_ref().to_string()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
if let Some(unquoted) = remove_quotes(&arg) {
|
if let Some(unquoted) = remove_quotes(&arg) {
|
||||||
unquoted.to_string()
|
format!(r#""{}""#, unquoted)
|
||||||
} else {
|
} else {
|
||||||
arg.as_ref().to_string()
|
arg.as_ref().to_string()
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
}).collect::<Vec<String>>();
|
arg.as_ref().to_string()
|
||||||
|
|
||||||
match spawn(&command, &path, &process_args[..], value_for_stdin, is_last).await {
|
|
||||||
Ok(res) => {
|
|
||||||
if let Some(mut res) = res {
|
|
||||||
while let Some(item) = res.next().await {
|
|
||||||
yield Ok(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(reason) => {
|
|
||||||
yield Ok(Value {
|
|
||||||
value: UntaggedValue::Error(reason),
|
|
||||||
tag: name_tag
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
#[cfg(windows)]
|
||||||
};
|
{
|
||||||
|
if let Some(unquoted) = remove_quotes(&arg) {
|
||||||
|
unquoted.to_string()
|
||||||
|
} else {
|
||||||
|
arg.as_ref().to_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
|
||||||
Ok(Some(stream.to_input_stream()))
|
spawn(&command, &path, &process_args[..], input, is_last)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn spawn(
|
fn spawn(
|
||||||
command: &ExternalCommand,
|
command: &ExternalCommand,
|
||||||
path: &str,
|
path: &str,
|
||||||
args: &[String],
|
args: &[String],
|
||||||
stdin_contents: Option<String>,
|
input: Option<InputStream>,
|
||||||
is_last: bool,
|
is_last: bool,
|
||||||
) -> Result<Option<InputStream>, ShellError> {
|
) -> Result<Option<InputStream>, ShellError> {
|
||||||
let command = command.clone();
|
let command = command.clone();
|
||||||
@ -265,7 +228,7 @@ async fn spawn(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// open since we have some contents for stdin
|
// open since we have some contents for stdin
|
||||||
if stdin_contents.is_some() {
|
if input.is_some() {
|
||||||
process.stdin(Stdio::piped());
|
process.stdin(Stdio::piped());
|
||||||
trace!(target: "nu::run::external", "set up stdin pipe");
|
trace!(target: "nu::run::external", "set up stdin pipe");
|
||||||
}
|
}
|
||||||
@ -274,52 +237,37 @@ async fn spawn(
|
|||||||
|
|
||||||
if let Ok(mut child) = process.spawn() {
|
if let Ok(mut child) = process.spawn() {
|
||||||
let stream = async_stream! {
|
let stream = async_stream! {
|
||||||
if let Some(mut input) = stdin_contents.as_ref() {
|
if let Some(mut input) = input {
|
||||||
let mut stdin_write = child.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");
|
||||||
|
|
||||||
if let Err(e) = stdin_write.write(input.as_bytes()) {
|
while let Some(value) = input.next().await {
|
||||||
let message = format!("Unable to write to stdin (error = {})", e);
|
let input_string = match nu_value_to_string_for_stdin(&command, &value) {
|
||||||
|
Ok(None) => continue,
|
||||||
|
Ok(Some(v)) => v,
|
||||||
|
Err(e) => {
|
||||||
|
yield Ok(Value {
|
||||||
|
value: UntaggedValue::Error(e),
|
||||||
|
tag: name_tag
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
yield Ok(Value {
|
if let Err(e) = stdin_write.write(input_string.as_bytes()) {
|
||||||
value: UntaggedValue::Error(ShellError::labeled_error(
|
let message = format!("Unable to write to stdin (error = {})", e);
|
||||||
message,
|
|
||||||
"application may have closed before completing pipeline",
|
|
||||||
&name_tag)),
|
|
||||||
tag: name_tag
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
drop(stdin_write);
|
yield Ok(Value {
|
||||||
}
|
value: UntaggedValue::Error(ShellError::labeled_error(
|
||||||
|
message,
|
||||||
if is_last && command.has_it_argument() {
|
"application may have closed before completing pipeline",
|
||||||
if let Ok(status) = child.wait() {
|
&name_tag)),
|
||||||
if status.success() {
|
tag: name_tag
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We can give an error when we see a non-zero exit code, but this is different
|
|
||||||
// than what other shells will do.
|
|
||||||
let cfg = crate::data::config::config(Tag::unknown());
|
|
||||||
if let Ok(cfg) = cfg {
|
|
||||||
if cfg.contains_key("nonzero_exit_errors") {
|
|
||||||
yield Ok(Value {
|
|
||||||
value: UntaggedValue::Error(
|
|
||||||
ShellError::labeled_error(
|
|
||||||
"External command failed",
|
|
||||||
"command failed",
|
|
||||||
&name_tag,
|
|
||||||
)
|
|
||||||
),
|
|
||||||
tag: name_tag,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_last {
|
if !is_last {
|
||||||
@ -340,7 +288,7 @@ async fn spawn(
|
|||||||
let mut stream = FramedRead::new(file, LinesCodec).map(|line| {
|
let mut stream = FramedRead::new(file, LinesCodec).map(|line| {
|
||||||
if let Ok(line) = line {
|
if let Ok(line) = line {
|
||||||
Value {
|
Value {
|
||||||
value: UntaggedValue::Primitive(Primitive::String(line)),
|
value: UntaggedValue::Primitive(Primitive::Line(line)),
|
||||||
tag: name_tag.clone(),
|
tag: name_tag.clone(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -353,6 +301,8 @@ async fn spawn(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We can give an error when we see a non-zero exit code, but this is different
|
||||||
|
// than what other shells will do.
|
||||||
if child.wait().is_err() {
|
if child.wait().is_err() {
|
||||||
let cfg = crate::data::config::config(Tag::unknown());
|
let cfg = crate::data::config::config(Tag::unknown());
|
||||||
if let Ok(cfg) = cfg {
|
if let Ok(cfg) = cfg {
|
||||||
|
@ -21,8 +21,8 @@ fn takes_rows_of_nu_value_strings_and_pipes_it_to_stdin_of_external() {
|
|||||||
r#"
|
r#"
|
||||||
open nu_times.csv
|
open nu_times.csv
|
||||||
| get name
|
| get name
|
||||||
|
| ^echo $it
|
||||||
| chop
|
| chop
|
||||||
| lines
|
|
||||||
| nth 3
|
| nth 3
|
||||||
| echo $it
|
| echo $it
|
||||||
"#
|
"#
|
||||||
|
Loading…
Reference in New Issue
Block a user