convert uses of `io.Pipe` to `cmd.Pipe*()`
Created by: camdencheek
There's this great footgun with go subprocesses where, if you use a
non-file io.Writer
for cmd.Stdout
(and Stdin
, and Stderr
),
it spins up a goroutine that reads from the OS pipe and writes to the
writer. Additionally, cmd.Wait
will not complete until that goroutine
completes writing the output of your subcommand. Couple this with a
synchronous io.Pipe
, and cmd.Wait
might never return.
This commit fixes an issue where, in some cancellation situations, there
would be a goroutine leak because of this. Instead of io.Pipe
, we use
os.Pipe
, which is what those above-mentioned background goroutines use
behind the scenes anyways. This allows us to control the lifetime of the
pipe.
Stacked on #25616