avoid freeze for table print (#6688)

* avoid freeze for table print

* make failed_with_proper_exit_code work again

* add test case for table

* fix un-used import on windows
This commit is contained in:
WindSoilder 2022-10-10 20:32:55 +08:00 committed by GitHub
parent 2f1711f783
commit 1998bce19f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 46 additions and 24 deletions

View File

@ -231,23 +231,18 @@ pub fn eval_source(
} }
match eval_block(engine_state, stack, &block, input, false, false) { match eval_block(engine_state, stack, &block, input, false, false) {
Ok(mut pipeline_data) => { Ok(pipeline_data) => {
if let PipelineData::ExternalStream { exit_code, .. } = &mut pipeline_data { match pipeline_data.print(engine_state, stack, false, false) {
if let Some(exit_code) = exit_code.take().and_then(|it| it.last()) { Err(err) => {
stack.add_env_var("LAST_EXIT_CODE".to_string(), exit_code); let working_set = StateWorkingSet::new(engine_state);
} else {
set_last_exit_code(stack, 0); report_error(&working_set, &err);
return false;
}
Ok(exit_code) => {
set_last_exit_code(stack, exit_code);
} }
} else {
set_last_exit_code(stack, 0);
}
if let Err(err) = pipeline_data.print(engine_state, stack, false, false) {
let working_set = StateWorkingSet::new(engine_state);
report_error(&working_set, &err);
return false;
} }
// reset vt processing, aka ansi because illbehaved externals can break it // reset vt processing, aka ansi because illbehaved externals can break it

View File

@ -135,3 +135,28 @@ fn table_expand_flatten_and_deep_1() {
" "
); );
} }
#[test]
#[cfg(not(windows))]
fn external_with_too_much_stdout_should_not_hang_nu() {
use nu_test_support::fs::Stub::FileWithContent;
use nu_test_support::pipeline;
use nu_test_support::playground::Playground;
Playground::setup("external with too much stdout", |dirs, sandbox| {
let bytes: usize = 81920;
let mut large_file_body = String::with_capacity(bytes);
for _ in 0..bytes {
large_file_body.push_str("a");
}
sandbox.with_files(vec![FileWithContent("a_large_file.txt", &large_file_body)]);
let actual = nu!(
cwd: dirs.test(), pipeline(
r#"
cat a_large_file.txt | table
"#
));
assert_eq!(actual.out, large_file_body);
})
}

View File

@ -424,7 +424,7 @@ impl PipelineData {
stack: &mut Stack, stack: &mut Stack,
no_newline: bool, no_newline: bool,
to_stderr: bool, to_stderr: bool,
) -> Result<(), ShellError> { ) -> Result<i64, ShellError> {
// If the table function is in the declarations, then we can use it // If the table function is in the declarations, then we can use it
// to create the table value that will be printed in the terminal // to create the table value that will be printed in the terminal
@ -452,10 +452,13 @@ impl PipelineData {
// Make sure everything has finished // Make sure everything has finished
if let Some(exit_code) = exit_code { if let Some(exit_code) = exit_code {
let _: Vec<_> = exit_code.into_iter().collect(); let mut exit_codes: Vec<_> = exit_code.into_iter().collect();
if let Some(Value::Int { val, .. }) = exit_codes.pop() {
return Ok(val);
}
} }
return Ok(()); return Ok(0);
} }
match engine_state.find_decl("table".as_bytes(), &[]) { match engine_state.find_decl("table".as_bytes(), &[]) {
@ -474,7 +477,7 @@ impl PipelineData {
} }
}; };
Ok(()) Ok(0)
} }
fn write_all_and_flush( fn write_all_and_flush(
@ -483,7 +486,7 @@ impl PipelineData {
config: &Config, config: &Config,
no_newline: bool, no_newline: bool,
to_stderr: bool, to_stderr: bool,
) -> Result<(), ShellError> { ) -> Result<i64, ShellError> {
for item in self { for item in self {
let mut out = if let Value::Error { error } = item { let mut out = if let Value::Error { error } = item {
let working_set = StateWorkingSet::new(engine_state); let working_set = StateWorkingSet::new(engine_state);
@ -506,7 +509,7 @@ impl PipelineData {
} }
} }
Ok(()) Ok(0)
} }
} }

View File

@ -314,11 +314,10 @@ mod nu_commands {
} }
#[test] #[test]
#[ignore = "For now we have no way to check LAST_EXIT_CODE in tests, ignore it for now"]
fn failed_with_proper_exit_code() { fn failed_with_proper_exit_code() {
Playground::setup("external failed", |dirs, _sandbox| { Playground::setup("external failed", |dirs, _sandbox| {
let actual = nu!(cwd: dirs.test(), r#" let actual = nu!(cwd: dirs.test(), r#"
nu -c "cargo build; print $env.LAST_EXIT_CODE" nu -c "cargo build | complete | get exit_code"
"#); "#);
// cargo for non rust project's exit code is 101. // cargo for non rust project's exit code is 101.