Skip to content

Avoid blocking when o+e> redirects too much stderr message#8784

Merged
fdncred merged 29 commits intonushell:mainfrom
WindSoilder:outerr
May 17, 2023
Merged

Avoid blocking when o+e> redirects too much stderr message#8784
fdncred merged 29 commits intonushell:mainfrom
WindSoilder:outerr

Conversation

@WindSoilder
Copy link
Copy Markdown
Contributor

@WindSoilder WindSoilder commented Apr 6, 2023

Description

Fixes: #8565

Here is another pr #7240 tried to address the issue, but it works in a wrong way.

After this change o+e> won't redirect all stdout message then stderr message and it works more like how bash does.

User-Facing Changes

For the given python code:

# test.py
import sys

print('aa'*300, flush=True)
print('bb'*999999, file=sys.stderr, flush=True)
print('cc'*300, flush=True)

Running python test.py out+err> a.txt shoudn't hang nushell, and a.txt keeps output in the same order

About the change

The core idea is that when doing lite-parsing, introduce a new variant LiteElement::SameTargetRedirection if we meet out+err> redirection token(which is generated by lex function),

During converting from lite block to block, LiteElement::SameTargetRedirection will be converted to PipelineElement::SameTargetRedirection.

Then in the block eval process, if we get PipelineElement::SameTargetRedirection, we'll invoke run-external with --redirect-combine flag, then pipe the result into save command

What happened internally?

Take the following command as example:
^ls o+e> log.txt

lex parsing result(Tokens) are not changed, but LiteBlock and Block is changed after this pr.

LiteBlock before

LiteBlock {
    block: [
        LitePipeline { commands: [
            Command(None, LiteCommand { comments: [], parts: [Span { start: 39041, end: 39044 }] }),
            // actually the span of first Redirection is wrong too..
            Redirection(Span { start: 39058, end: 39062 }, StdoutAndStderr, LiteCommand { comments: [], parts: [Span { start: 39050, end: 39057 }] }),
        ]
    }]
}

LiteBlock after

LiteBlock { 
    block: [
        LitePipeline {
            commands: [
                SameTargetRedirection {
                    cmd: (None, LiteCommand { comments: [], parts: [Span { start: 147945, end: 147948}]}),
                    redirection: (Span { start: 147949, end: 147957 }, LiteCommand { comments: [], parts: [Span { start: 147958, end: 147965 }]})
                }
            ]
        }
    ]
}

Block before

Pipeline {
    elements: [
        Expression(None, Expression {
            expr: ExternalCall(Expression { expr: String("ls"), span: Span { start: 39042, end: 39044 }, ty: String, custom_completion: None }, [], false),
            span: Span { start: 39041, end: 39044 },
            ty: Any, custom_completion: None 
        }),
        Redirection(Span { start: 39058, end: 39062 }, StdoutAndStderr, Expression { expr: String("out.txt"), span: Span { start: 39050, end: 39057 }, ty: String, custom_completion: None })] }

Block after

Pipeline {
    elements: [
        SameTargetRedirection { 
            cmd: (None, Expression {
                expr: ExternalCall(Expression { expr: String("ls"), span: Span { start: 147946, end: 147948 }, ty: String, custom_completion: None}, [], false),
                span: Span { start: 147945, end: 147948},
                ty: Any, custom_completion: None
            }),
            redirection: (Span { start: 147949, end: 147957}, Expression {expr: String("log.txt"), span: Span { start: 147958, end: 147965 },ty: String,custom_completion: None}
        }
    ]
}

Tests + Formatting

Don't forget to add tests that cover your changes.

Make sure you've run and fixed any issues with these commands:

  • cargo fmt --all -- --check to check standard code formatting (cargo fmt --all applies these changes)
  • cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A clippy::needless_collect to check that you're using the standard code style
  • cargo test --workspace to check that all tests pass
  • cargo run -- crates/nu-utils/standard_library/tests.nu to run the tests for the standard library

Note
from nushell you can also use the toolkit as follows

use toolkit.nu  # or use an `env_change` hook to activate it automatically
toolkit check pr

After Submitting

If your PR had any user-facing changes, update the documentation after the PR is merged, if necessary. This will help us keep the docs up to date.

@sholderbach
Copy link
Copy Markdown
Member

Thank you for this detailed PR description!

call: &Call,
redirect_stdout: bool,
redirect_stderr: bool,
out_file: Option<Spanned<String>>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't feel right to me. create_external_command shouldn't need to know that its output will be going to a file.

@sophiajt
Copy link
Copy Markdown
Contributor

sophiajt commented Apr 9, 2023

I'm glad we're trying to fix this issue. I'm not sure if this is quite the right approach. run_external is already pretty complex, and it doesn't feel like the right direction to make it aware that it will be writing to a file too.

@WindSoilder
Copy link
Copy Markdown
Contributor Author

WindSoilder commented Apr 9, 2023

it doesn't feel like the right direction to make it aware that it will be writing to a file too

Yeah I know about your concern, but I think if we write piped() external commands' output, we'd never have a chance to write both message to a file in a correct way.
How bash implements redirection is using something like dup call to clone file handler.
So I think the external result handling should be done at the beginning of process creation, and tell OS to write these message to relative file directly.

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 15, 2023

Codecov Report

Merging #8784 (604b596) into main (a45bd03) will decrease coverage by 0.02%.
The diff coverage is 63.37%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main    #8784      +/-   ##
==========================================
- Coverage   68.96%   68.94%   -0.02%     
==========================================
  Files         641      641              
  Lines      102434   102540     +106     
==========================================
+ Hits        70646    70701      +55     
- Misses      31788    31839      +51     
Impacted Files Coverage Δ
crates/nu-cli/src/completions/completer.rs 88.52% <0.00%> (-0.20%) ⬇️
crates/nu-cli/src/syntax_highlight.rs 65.56% <0.00%> (-0.20%) ⬇️
crates/nu-command/src/formats/from/nuon.rs 34.32% <0.00%> (-0.08%) ⬇️
crates/nu-parser/src/flatten.rs 52.53% <0.00%> (-1.19%) ⬇️
crates/nu-parser/src/parse_keywords.rs 77.70% <0.00%> (-0.06%) ⬇️
crates/nu-protocol/src/ast/pipeline.rs 34.90% <12.50%> (-4.05%) ⬇️
crates/nu-parser/src/parser.rs 85.15% <51.06%> (-0.41%) ⬇️
crates/nu-engine/src/eval.rs 75.26% <84.84%> (+1.51%) ⬆️
crates/nu-parser/src/lite_parser.rs 69.51% <96.42%> (+2.33%) ⬆️

... and 1 file with indirect coverage changes

@amtoine
Copy link
Copy Markdown
Member

amtoine commented Apr 15, 2023

i see you have made quite a few merges @WindSoilder 😮

if it's ready, maybe this PR should land to avoid more conflicts? 😋

@WindSoilder
Copy link
Copy Markdown
Contributor Author

i see you have made quite a few merges

Ah yeah, I merged from main frequently because I want to have latest main with the fix installed on my machine :-)

@WindSoilder WindSoilder marked this pull request as draft April 28, 2023 01:05
@WindSoilder WindSoilder marked this pull request as ready for review May 1, 2023 05:33
@WindSoilder
Copy link
Copy Markdown
Contributor Author

Finally I think it's ready to review, it only involves parsing change, and we don't need to change run-external

@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented May 12, 2023

@WindSoilder glad to see you arrived and a green ci, let's wait until the release and land this early on in the dev cycle so it can get ample testing. thanks!

@WindSoilder
Copy link
Copy Markdown
Contributor Author

So...I think it's ready and we can have full test under current version :-)

@fdncred fdncred merged commit b150f9f into nushell:main May 17, 2023
@fdncred
Copy link
Copy Markdown
Contributor

fdncred commented May 17, 2023

thanks @WindSoilder. let's give it a try.

@WindSoilder WindSoilder deleted the outerr branch May 17, 2023 23:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Redirect "out+err" hangs

5 participants