Skip to content

refactor: write output and diagnostics to the streams passed to Run - #477

Merged
thde merged 5 commits into
mainfrom
refactor/io-streams
Oct 16, 2026
Merged

thde merged 5 commits into
mainfrom
refactor/io-streams

Conversation

@thde

@thde thde commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

cmd.Run already took stdin, stdout and stderr, but commands didn't use them consistently. Some wrote to os.Stderr directly. Warnings, spinners and prompts were mixed into stdout, which broke the JSON from nctl get all -o json and hid prompts when stdout was redirected. Exec subprocesses checked the process's stdin for a terminal instead of the command's. The streams were also bound as a loose io.Writer and io.Reader next to Kong's own writers, so stdout had two sources and a hook couldn't tell which stream it had been given.

This PR introduces a single value that carries a command's streams (a pattern also used by kubectl):

// IOStreams are the standard input, output and error of a command.
type IOStreams struct {
        In     io.Reader // input commands prompt from
        Out    io.Writer // output of a command
        ErrOut io.Writer // diagnostics, see Writer.Err
}

Run builds it once and newParser binds it for the BeforeApply hooks of format.Writer and format.Reader. It also makes those streams Kong's writers, so help text, parse errors and command output share one source. format no longer imports Kong. Writer gains Err() for diagnostics and Out()/In() for the raw streams, so terminal detection and subprocess inheritance keep working. In tests, testutil.KongStreams replaces the hand-built KongContext.

Behaviour changes

Warnings, spinners, confirmation prompts and Run's own errors now go to stderr, and usage output stays on stdout. Scripts that read warnings or errors from stdout need to read stderr instead. main now gets its streams from moby/term.StdStreams(), so on Windows every command runs with virtual terminal sequences enabled.

@thde
thde added this pull request to stack #479 October 15, 2026 13:05
@thde
thde force-pushed the refactor/io-streams branch from 15cbc46 to 67946f3 Compare October 15, 2026 13:08
@thde
thde force-pushed the refactor/io-streams branch from 67946f3 to 1dfee6f Compare October 15, 2026 13:24
Base automatically changed from refactor/root-command to main October 16, 2026 07:03
format.Writer takes the output and diagnostics writers from Kong's context,
and Err returns the latter.
Commands write the image pull progress, subprocess errors,
build log errors and repository check messages to it
instead of os.Stderr,
so all output of a command goes to the writers main passes to Run.

Kong's writers replace the io.Writer binding,
so stdout and stderr have a single source,
also in the test harnesses.
@thde
thde force-pushed the refactor/io-streams branch from 1dfee6f to 0554590 Compare October 16, 2026 08:15
thde added 4 commits October 16, 2026 15:11
format.IOStreams holds the input, output and error of a command.
newParser binds it for the BeforeApply hooks
of format.Writer and format.Reader
and makes its writers those of Kong,
so stdout, stderr and stdin come from the streams passed to Run.

The hooks take the streams instead of the Kong context
and the bound io.Reader,
so format no longer imports Kong
and commands initialize Writer and Reader from a single value.

testutil.KongStreams replaces testutil.KongContext,
which built Kong's internal structs by hand,
and binds the streams for test parsers as newParser does.
Tests parsing structs without hooks drop the writers they never used.
The database exec commands give their subprocess the command's streams
and check the command's stdin for a terminal, instead of the process's.
exec app takes the bound IOStreams.

main gets the streams from dockerterm.StdStreams, so on Windows every
command now runs with the console's virtual terminal mode enabled.
NewWriter takes the writer for diagnostics next to the output,
so a Writer built by hand no longer discards them silently.

The IO wiring test finds the streams of a Writer and Reader by name
rather than by position, and waitForBuildFinish takes its writer
right after the context.
Warnings, spinners and confirmation prompts go to stderr
instead of stdout, so they no longer corrupt the output of a command,
such as the JSON of nctl get all -o json,
and a prompt still shows when stdout is redirected.

Run prints our own errors, the not-logged-in hint
and the missing-command hint to stderr too.
Like Kong on a parse error, the usage stays on stdout.

Scripts reading warnings or errors from stdout
need to read stderr instead.
@thde
thde force-pushed the refactor/io-streams branch from 0554590 to 60415b5 Compare October 16, 2026 13:12
@thde
thde merged commit db32f8d into main Oct 16, 2026
3 checks passed
@thde
thde deleted the refactor/io-streams branch October 16, 2026 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants