mirror of
https://github.com/larksuite/cli.git
synced 2026-07-07 00:55:53 +08:00
75 lines
2.2 KiB
Go
75 lines
2.2 KiB
Go
// Copyright (c) 2026 Lark Technologies Pte. Ltd.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
package cmdutil
|
|
|
|
import (
|
|
"io"
|
|
"os"
|
|
|
|
"golang.org/x/term"
|
|
)
|
|
|
|
// IOStreams provides the standard input/output/error streams.
|
|
// Commands should use these instead of os.Stdin/Stdout/Stderr
|
|
// to enable testing and output capture.
|
|
type IOStreams struct {
|
|
In io.Reader
|
|
Out io.Writer
|
|
ErrOut io.Writer
|
|
IsTerminal bool
|
|
// StderrIsTerminal reports whether ErrOut is an interactive terminal.
|
|
// Advisory warnings written to stderr (e.g. the proxy notice) gate on this
|
|
// so they stay out of non-interactive output (pipes, CI, agent runs).
|
|
// Computed once in NewIOStreams, mirroring IsTerminal; tests assign it
|
|
// directly like cmd/config/bind_test.go does for IsTerminal.
|
|
StderrIsTerminal bool
|
|
}
|
|
|
|
// NewIOStreams builds an IOStreams from arbitrary readers/writers.
|
|
// IsTerminal / StderrIsTerminal are derived from in's / errOut's underlying
|
|
// *os.File, if any; non-file streams (bytes.Buffer, strings.Reader, …) yield
|
|
// false.
|
|
func NewIOStreams(in io.Reader, out, errOut io.Writer) *IOStreams {
|
|
isTerminal := false
|
|
if f, ok := in.(*os.File); ok {
|
|
isTerminal = term.IsTerminal(int(f.Fd()))
|
|
}
|
|
stderrIsTerminal := false
|
|
if f, ok := errOut.(*os.File); ok {
|
|
stderrIsTerminal = term.IsTerminal(int(f.Fd()))
|
|
}
|
|
return &IOStreams{In: in, Out: out, ErrOut: errOut, IsTerminal: isTerminal, StderrIsTerminal: stderrIsTerminal}
|
|
}
|
|
|
|
// SystemIO creates an IOStreams wired to the process's standard file descriptors.
|
|
//
|
|
//nolint:forbidigo // entry point for real stdio
|
|
func SystemIO() *IOStreams {
|
|
return NewIOStreams(os.Stdin, os.Stdout, os.Stderr)
|
|
}
|
|
|
|
// normalizeStreams returns a fresh IOStreams with any nil field filled from
|
|
// SystemIO(). Callers constructing a partial struct like &IOStreams{Out: buf}
|
|
// get a usable result without nil writers leaking into RoundTripper warnings,
|
|
// Cobra I/O, or credential-provider error paths.
|
|
func normalizeStreams(s *IOStreams) *IOStreams {
|
|
if s == nil {
|
|
return SystemIO()
|
|
}
|
|
out := *s
|
|
if out.In == nil || out.Out == nil || out.ErrOut == nil {
|
|
sys := SystemIO()
|
|
if out.In == nil {
|
|
out.In = sys.In
|
|
}
|
|
if out.Out == nil {
|
|
out.Out = sys.Out
|
|
}
|
|
if out.ErrOut == nil {
|
|
out.ErrOut = sys.ErrOut
|
|
}
|
|
}
|
|
return &out
|
|
}
|