-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make it possible again to read STDERR without calling cat
#11919
Conversation
@@ -1149,6 +1149,7 @@ export | |||
ntoh, | |||
open, | |||
pipe, | |||
Pipe, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kinda confusing to export this when it's a rather different thing than the pipe
function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think once processes are readable/writable, this can just be pipe()
(although @vtjnash wants that to return a pair). I think maybe the right design is instead of have another method that creates the other pipe end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe have a real API design discussion about this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'd be ok with calling this pipe()
and adding pipepair()
in the future if necessary. Names that differ only in case are really annoying.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what does the pipe
function do now then? Either connect two commands via a pipe or construct a pipe object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Keno and I both suggested that at the beginning of this thread 17 days ago.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with that is that pipe
with more than one argument is a lazy constructor for a command object, while Pipe()
creates a pipe object that run
modifies.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it might just have to be Pipe
and pipeline
, though I sorta dread having to tell people they have to go from one character to 8 for this functionality.
Of course, I also suggested const 🚰= Pipe
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm. Maybe having pipe
and Pipe
isn't so bad :-\
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One suggestion that I forgot to mention here was pipe
and PipeEnd
. I also considered Piping
(as in to get data out of your pipeline, just add some Piping
).
7a30092
to
491d310
Compare
@@ -311,7 +311,9 @@ macro setup_stdio() | |||
in,out,err = stdios | |||
if isa(stdios[1], Pipe) | |||
if stdios[1].handle == C_NULL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ref #10469 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reminder (this should be using the test isopen(stdios[1])
, now that we have that field)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As per our discussion, the C_NULL here should be fine as this way you get an error in the use-after-close case whereas otherwise it would silently pass /dev/null
.
9f74adf
to
caefce9
Compare
spawn test looks stuck on win32 and win64 appveyor also ref https://github.com/JuliaLang/julia/pull/11919/files#r33425946 |
Renamed |
d6f0076
to
544b9b0
Compare
Hmm, still times out in CI. |
Yeah, I'll take a look. |
Merge the Pipe() and Pipe(C_NULL) constructors having the former just call the latter and delaying initialization to the place where it is actually needed. Now passing an empty Pipe to spawn will once again initialize it with the appropriate pipe end.
FWIW, I found the broken test, but the |
@test readall(pipe(`$exename -f -e 'println(STDERR,"Hello World")'`, stderr=`cat`)) == "Hello World\n" | ||
@test readall(pipeline(`$exename -f -e 'println(STDERR,"Hello World")'`, stderr=`cat`)) == "Hello World\n" | ||
p = Pipe() | ||
run(pipeline(`$exename -f -e 'println(STDERR,"Hello World")'`, stderr = p)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the problem i have with this API is that it looks like you could use p
repeated to aggregate the stderr for many processes, but in fact you can't even call run
twice on this Cmd
object, since run
mutates the p
object when it opens it. What is the disadvantage to making Pipe
refer to the entire pipe, while adding an internal type that represents just one end of the pipe (e.g. what is called Pipe in this PR)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is similar to what I proposed at some point – the idea was that a Pipe
object would be similar to a cat
process but without any process, just going through the kernel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use spawn
not run
here to avoid forcing the kernel to buffer the output (the windows kernel is forcing the process to stay alive until there is a reader for the stderr pipe causing the hang on appveyor).
will push a fix shortly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here's an even better example of why we should never export PipeEnd
to the user:
p = PipeEnd()
spawn(pipeline(`foo` & `bar`, stdout=p)) # this expression has undefined behavior, since bar may get the wrong end of the pipe
(i'm most of the way done with a cleanup effort to add a Pipe
object which tracks a pair of pipe ends)
…. also rename Pipe to PipeEndpoint
Merge the Pipe() and Pipe(C_NULL) constructors having the former just
call the latter and delaying initialization to the place where it is
actually needed. Now passing an empty Pipe to spawn will once again
initialize it with the appropriate pipe end. Fixes #11824.