command: Require callers to explicitly set up stdout

When not providing an stdout writer to command.New(), we implicitly set up the command such that it writes into a pipe. This has multiple downsides:

- It is not easy to see whether a specific command needs it stdout
  at all.

- Commands whose stdout is never read are wasting CPU time to write
  data that nobody is going to read.

- Commands whose stdout is never read may deadlock when they write a
  sufficient amount of data that fills the pipe's buffer. This is a
  bug waiting to happen.

- We need to discard stdout when calling `command.Wait()` in order
  to discard any potential output in order to unblock commands. This
  is not only a waste of CPU time, but also causes bugs because
  context cancellation may cause any concurrent readers to race with
  this drain.

The only upside of the current code is that it's less verbose given that a lot of callsites actually do want to read stdout.

Refactor the code to require explicit setup of standard output via a new WithSetupStdout() option in both the command and git package that mirrors the preexisting WithSetupStdin() option. This addresses the first three shortcomings while also paving a way to fix the last one, where we should instead be able to just close the stdout pipe instead of draining it.

Part of #5021 (closed).

Merge request reports

Loading