vendor: github.com/docker/cli v29.4.0
full diff: https://github.com/docker/cli/compare/v29.3.1...v29.4.0 Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package command
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package command
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package command
|
||||
|
||||
|
||||
+22
-11
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package formatter
|
||||
|
||||
@@ -141,25 +141,36 @@ func (c *ContainerContext) ID() string {
|
||||
|
||||
// Names returns a comma-separated string of the container's names, with their
|
||||
// slash (/) prefix stripped. Additional names for the container (related to the
|
||||
// legacy `--link` feature) are omitted.
|
||||
// legacy `--link` feature) are omitted when formatting "truncated".
|
||||
func (c *ContainerContext) Names() string {
|
||||
names := StripNamePrefix(c.c.Names)
|
||||
if c.trunc {
|
||||
for _, name := range names {
|
||||
if len(strings.Split(name, "/")) == 1 {
|
||||
names = []string{name}
|
||||
break
|
||||
var b strings.Builder
|
||||
for i, n := range c.c.Names {
|
||||
name := strings.TrimPrefix(n, "/")
|
||||
if c.trunc {
|
||||
// When printing truncated, we only print a single name.
|
||||
//
|
||||
// Pick the first name that's not a legacy link (does not have
|
||||
// slashes inside the name itself (e.g., "/other-container/link")).
|
||||
// Normally this would be the first name found.
|
||||
if strings.IndexByte(name, '/') == -1 {
|
||||
return name
|
||||
}
|
||||
continue
|
||||
}
|
||||
if i > 0 {
|
||||
b.WriteByte(',')
|
||||
}
|
||||
b.WriteString(name)
|
||||
}
|
||||
return strings.Join(names, ",")
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// StripNamePrefix removes prefix from string, typically container names as returned by `ContainersList` API
|
||||
// StripNamePrefix removes any "/" prefix from container names returned
|
||||
// by the "ContainersList" API.
|
||||
func StripNamePrefix(ss []string) []string {
|
||||
sss := make([]string, len(ss))
|
||||
for i, s := range ss {
|
||||
sss[i] = s[1:]
|
||||
sss[i] = strings.TrimPrefix(s, "/")
|
||||
}
|
||||
return sss
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package formatter
|
||||
|
||||
|
||||
-3
@@ -46,7 +46,6 @@ func (ctx *DiskUsageContext) startSubsection(format Format) (*template.Template,
|
||||
ctx.buffer = &bytes.Buffer{}
|
||||
ctx.header = ""
|
||||
ctx.Format = format
|
||||
ctx.preFormat()
|
||||
|
||||
return ctx.parseFormat()
|
||||
}
|
||||
@@ -88,7 +87,6 @@ func (ctx *DiskUsageContext) Write() (err error) {
|
||||
return ctx.verboseWrite()
|
||||
}
|
||||
ctx.buffer = &bytes.Buffer{}
|
||||
ctx.preFormat()
|
||||
|
||||
tmpl, err := ctx.parseFormat()
|
||||
if err != nil {
|
||||
@@ -213,7 +211,6 @@ func (ctx *DiskUsageContext) verboseWrite() error {
|
||||
return ctx.verboseWriteTable(duc)
|
||||
}
|
||||
|
||||
ctx.preFormat()
|
||||
tmpl, err := ctx.parseFormat()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package formatter
|
||||
|
||||
|
||||
+43
-35
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package formatter
|
||||
|
||||
@@ -33,7 +33,7 @@ func (f Format) IsTable() bool {
|
||||
return strings.HasPrefix(string(f), TableFormatKey)
|
||||
}
|
||||
|
||||
// IsJSON returns true if the format is the json format
|
||||
// IsJSON returns true if the format is the JSON format
|
||||
func (f Format) IsJSON() bool {
|
||||
return string(f) == JSONFormatKey
|
||||
}
|
||||
@@ -43,6 +43,31 @@ func (f Format) Contains(sub string) bool {
|
||||
return strings.Contains(string(f), sub)
|
||||
}
|
||||
|
||||
// templateString pre-processes the format and returns it as a string
|
||||
// for templating.
|
||||
func (f Format) templateString() string {
|
||||
out := string(f)
|
||||
switch out {
|
||||
case TableFormatKey:
|
||||
// A bare "--format table" should already be handled before we
|
||||
// hit this; a literal "table" here means a custom "table" format
|
||||
// without template.
|
||||
return ""
|
||||
case JSONFormatKey:
|
||||
// "--format json" only; not JSON formats ("--format '{{json .Field}}'").
|
||||
return JSONFormat
|
||||
}
|
||||
|
||||
// "--format 'table {{.Field}}\t{{.Field}}'" -> "{{.Field}}\t{{.Field}}"
|
||||
if after, isTable := strings.CutPrefix(out, TableFormatKey); isTable {
|
||||
out = after
|
||||
}
|
||||
|
||||
out = strings.Trim(out, " ") // trim spaces, but preserve other whitespace.
|
||||
out = strings.NewReplacer(`\t`, "\t", `\n`, "\n").Replace(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// Context contains information required by the formatter to print the output as desired.
|
||||
type Context struct {
|
||||
// Output is the output stream to which the formatted string is written.
|
||||
@@ -53,28 +78,12 @@ type Context struct {
|
||||
Trunc bool
|
||||
|
||||
// internal element
|
||||
finalFormat string
|
||||
header any
|
||||
buffer *bytes.Buffer
|
||||
}
|
||||
|
||||
func (c *Context) preFormat() {
|
||||
c.finalFormat = string(c.Format)
|
||||
// TODO: handle this in the Format type
|
||||
switch {
|
||||
case c.Format.IsTable():
|
||||
c.finalFormat = c.finalFormat[len(TableFormatKey):]
|
||||
case c.Format.IsJSON():
|
||||
c.finalFormat = JSONFormat
|
||||
}
|
||||
|
||||
c.finalFormat = strings.Trim(c.finalFormat, " ")
|
||||
r := strings.NewReplacer(`\t`, "\t", `\n`, "\n")
|
||||
c.finalFormat = r.Replace(c.finalFormat)
|
||||
header any
|
||||
buffer *bytes.Buffer
|
||||
}
|
||||
|
||||
func (c *Context) parseFormat() (*template.Template, error) {
|
||||
tmpl, err := templates.Parse(c.finalFormat)
|
||||
tmpl, err := templates.Parse(c.Format.templateString())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("template parsing error: %w", err)
|
||||
}
|
||||
@@ -82,20 +91,21 @@ func (c *Context) parseFormat() (*template.Template, error) {
|
||||
}
|
||||
|
||||
func (c *Context) postFormat(tmpl *template.Template, subContext SubContext) {
|
||||
if c.Output == nil {
|
||||
c.Output = io.Discard
|
||||
out := c.Output
|
||||
if out == nil {
|
||||
out = io.Discard
|
||||
}
|
||||
if c.Format.IsTable() {
|
||||
t := tabwriter.NewWriter(c.Output, 10, 1, 3, ' ', 0)
|
||||
buffer := bytes.NewBufferString("")
|
||||
tmpl.Funcs(templates.HeaderFunctions).Execute(buffer, subContext.FullHeader())
|
||||
buffer.WriteTo(t)
|
||||
t.Write([]byte("\n"))
|
||||
c.buffer.WriteTo(t)
|
||||
t.Flush()
|
||||
} else {
|
||||
c.buffer.WriteTo(c.Output)
|
||||
if !c.Format.IsTable() {
|
||||
_, _ = c.buffer.WriteTo(out)
|
||||
return
|
||||
}
|
||||
|
||||
// Write column-headers and rows to the tab-writer buffer, then flush the output.
|
||||
tw := tabwriter.NewWriter(out, 10, 1, 3, ' ', 0)
|
||||
_ = tmpl.Funcs(templates.HeaderFunctions).Execute(tw, subContext.FullHeader())
|
||||
_, _ = tw.Write([]byte{'\n'})
|
||||
_, _ = c.buffer.WriteTo(tw)
|
||||
_ = tw.Flush()
|
||||
}
|
||||
|
||||
func (c *Context) contextFormat(tmpl *template.Template, subContext SubContext) error {
|
||||
@@ -115,8 +125,6 @@ type SubFormat func(func(SubContext) error) error
|
||||
// Write the template to the buffer using this Context
|
||||
func (c *Context) Write(sub SubContext, f SubFormat) error {
|
||||
c.buffer = &bytes.Buffer{}
|
||||
c.preFormat()
|
||||
|
||||
tmpl, err := c.parseFormat()
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package formatter
|
||||
|
||||
@@ -24,7 +24,7 @@ func MarshalJSON(x any) ([]byte, error) {
|
||||
// marshalMap marshals x to map[string]any
|
||||
func marshalMap(x any) (map[string]any, error) {
|
||||
val := reflect.ValueOf(x)
|
||||
if val.Kind() != reflect.Ptr {
|
||||
if val.Kind() != reflect.Pointer {
|
||||
return nil, fmt.Errorf("expected a pointer to a struct, got %v", val.Kind())
|
||||
}
|
||||
if val.IsNil() {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package command
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package command
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package configfile
|
||||
|
||||
|
||||
+8
-3
@@ -99,9 +99,14 @@ func (c *fileStore) Store(authConfig types.AuthConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ConvertToHostname converts a registry url which has http|https prepended
|
||||
// to just an hostname.
|
||||
// Copied from github.com/docker/docker/registry.ConvertToHostname to reduce dependencies.
|
||||
// ConvertToHostname normalizes a registry URL which has http|https prepended
|
||||
// to just its hostname. It is used to match credentials, which may be either
|
||||
// stored as hostname or as hostname including scheme (in legacy configuration
|
||||
// files).
|
||||
//
|
||||
// It's the equivalent to [registry.ConvertToHostname] in the daemon.
|
||||
//
|
||||
// [registry.ConvertToHostname]: https://pkg.go.dev/github.com/moby/moby/v2@v2.0.0-beta.7/daemon/pkg/registry#ConvertToHostname
|
||||
func ConvertToHostname(maybeURL string) string {
|
||||
stripped := maybeURL
|
||||
if strings.Contains(stripped, "://") {
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package memorystore
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
// Package connhelper provides helpers for connecting to a remote daemon host with custom logic.
|
||||
package connhelper
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package store
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package store
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.24
|
||||
//go:build go1.25
|
||||
|
||||
package store
|
||||
|
||||
|
||||
+48
-27
@@ -4,7 +4,6 @@ import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/moby/term"
|
||||
)
|
||||
@@ -12,8 +11,29 @@ import (
|
||||
// In is an input stream to read user input. It implements [io.ReadCloser]
|
||||
// with additional utilities, such as putting the terminal in raw mode.
|
||||
type In struct {
|
||||
commonStream
|
||||
in io.ReadCloser
|
||||
cs commonStream
|
||||
}
|
||||
|
||||
// NewIn returns a new [In] from an [io.ReadCloser]. If in is an [*os.File],
|
||||
// a reference is kept to the file, and accessible through [In.File].
|
||||
func NewIn(in io.ReadCloser) *In {
|
||||
return &In{
|
||||
in: in,
|
||||
cs: newCommonStream(in),
|
||||
}
|
||||
}
|
||||
|
||||
// FD returns the file descriptor number for this stream.
|
||||
func (i *In) FD() uintptr {
|
||||
return i.cs.fd
|
||||
}
|
||||
|
||||
// File returns the underlying *os.File if the stream was constructed from one.
|
||||
// If the stream was created from a non-file (e.g., a pipe, buffer, or wrapper),
|
||||
// the returned boolean will be false.
|
||||
func (i *In) File() (*os.File, bool) {
|
||||
return i.cs.file()
|
||||
}
|
||||
|
||||
// Read implements the [io.Reader] interface.
|
||||
@@ -26,36 +46,37 @@ func (i *In) Close() error {
|
||||
return i.in.Close()
|
||||
}
|
||||
|
||||
// IsTerminal returns whether this stream is connected to a terminal.
|
||||
func (i *In) IsTerminal() bool {
|
||||
return i.cs.isTerminal()
|
||||
}
|
||||
|
||||
// SetRawTerminal sets raw mode on the input terminal. It is a no-op if In
|
||||
// is not a TTY, or if the "NORAW" environment variable is set to a non-empty
|
||||
// value.
|
||||
func (i *In) SetRawTerminal() (err error) {
|
||||
if !i.isTerminal || os.Getenv("NORAW") != "" {
|
||||
func (i *In) SetRawTerminal() error {
|
||||
return i.cs.setRawTerminal(term.SetRawTerminal)
|
||||
}
|
||||
|
||||
// RestoreTerminal restores the terminal state if SetRawTerminal succeeded earlier.
|
||||
func (i *In) RestoreTerminal() {
|
||||
i.cs.restoreTerminal()
|
||||
}
|
||||
|
||||
// CheckTty reports an error when stdin is requested for a TTY-enabled
|
||||
// container, but the client stdin is not itself a terminal (for example,
|
||||
// when input is piped or redirected).
|
||||
func (i *In) CheckTty(attachStdin, ttyMode bool) error {
|
||||
// TODO(thaJeztah): consider inlining this code and deprecating the method.
|
||||
if !ttyMode || !attachStdin || i.cs.isTerminal() {
|
||||
return nil
|
||||
}
|
||||
i.state, err = term.SetRawTerminal(i.fd)
|
||||
return err
|
||||
return errors.New("cannot attach stdin to a TTY-enabled container because stdin is not a terminal")
|
||||
}
|
||||
|
||||
// CheckTty checks if we are trying to attach to a container TTY
|
||||
// from a non-TTY client input stream, and if so, returns an error.
|
||||
func (i *In) CheckTty(attachStdin, ttyMode bool) error {
|
||||
// In order to attach to a container tty, input stream for the client must
|
||||
// be a tty itself: redirecting or piping the client standard input is
|
||||
// incompatible with `docker run -t`, `docker exec -t` or `docker attach`.
|
||||
if ttyMode && attachStdin && !i.isTerminal {
|
||||
const eText = "the input device is not a TTY"
|
||||
if runtime.GOOS == "windows" {
|
||||
return errors.New(eText + ". If you are using mintty, try prefixing the command with 'winpty'")
|
||||
}
|
||||
return errors.New(eText)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewIn returns a new [In] from an [io.ReadCloser].
|
||||
func NewIn(in io.ReadCloser) *In {
|
||||
i := &In{in: in}
|
||||
i.fd, i.isTerminal = term.GetFdInfo(in)
|
||||
return i
|
||||
// SetIsTerminal overrides whether a terminal is connected. It is used to
|
||||
// override this property in unit-tests, and should not be depended on for
|
||||
// other purposes.
|
||||
func (i *In) SetIsTerminal(isTerminal bool) {
|
||||
i.cs.setIsTerminal(isTerminal)
|
||||
}
|
||||
|
||||
+41
-24
@@ -5,54 +5,71 @@ import (
|
||||
"os"
|
||||
|
||||
"github.com/moby/term"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// Out is an output stream to write normal program output. It implements
|
||||
// an [io.Writer], with additional utilities for detecting whether a terminal
|
||||
// is connected, getting the TTY size, and putting the terminal in raw mode.
|
||||
type Out struct {
|
||||
commonStream
|
||||
out io.Writer
|
||||
cs commonStream
|
||||
}
|
||||
|
||||
// NewOut returns a new [Out] from an [io.Writer]. If out is an [*os.File],
|
||||
// a reference is kept to the file, and accessible through [Out.File].
|
||||
func NewOut(out io.Writer) *Out {
|
||||
return &Out{
|
||||
out: out,
|
||||
cs: newCommonStream(out),
|
||||
}
|
||||
}
|
||||
|
||||
// FD returns the file descriptor number for this stream.
|
||||
func (o *Out) FD() uintptr {
|
||||
return o.cs.FD()
|
||||
}
|
||||
|
||||
// File returns the underlying *os.File if the stream was constructed from one.
|
||||
// If the stream was created from a non-file (e.g., a pipe, buffer, or wrapper),
|
||||
// the returned boolean will be false.
|
||||
func (o *Out) File() (*os.File, bool) {
|
||||
return o.cs.file()
|
||||
}
|
||||
|
||||
// Write writes to the output stream.
|
||||
func (o *Out) Write(p []byte) (int, error) {
|
||||
return o.out.Write(p)
|
||||
}
|
||||
|
||||
// IsTerminal returns whether this stream is connected to a terminal.
|
||||
func (o *Out) IsTerminal() bool {
|
||||
return o.cs.isTerminal()
|
||||
}
|
||||
|
||||
// SetRawTerminal puts the output of the terminal connected to the stream
|
||||
// into raw mode.
|
||||
//
|
||||
// On UNIX, this does nothing. On Windows, it disables LF -> CRLF/ translation.
|
||||
// It is a no-op if Out is not a TTY, or if the "NORAW" environment variable is
|
||||
// set to a non-empty value.
|
||||
func (o *Out) SetRawTerminal() (err error) {
|
||||
if !o.isTerminal || os.Getenv("NORAW") != "" {
|
||||
return nil
|
||||
}
|
||||
o.state, err = term.SetRawTerminalOutput(o.fd)
|
||||
return err
|
||||
func (o *Out) SetRawTerminal() error {
|
||||
return o.cs.setRawTerminal(term.SetRawTerminalOutput)
|
||||
}
|
||||
|
||||
// RestoreTerminal restores the terminal state if SetRawTerminal succeeded earlier.
|
||||
func (o *Out) RestoreTerminal() {
|
||||
o.cs.restoreTerminal()
|
||||
}
|
||||
|
||||
// GetTtySize returns the height and width in characters of the TTY, or
|
||||
// zero for both if no TTY is connected.
|
||||
func (o *Out) GetTtySize() (height uint, width uint) {
|
||||
if !o.isTerminal {
|
||||
return 0, 0
|
||||
}
|
||||
ws, err := term.GetWinsize(o.fd)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Debug("Error getting TTY size")
|
||||
if ws == nil {
|
||||
return 0, 0
|
||||
}
|
||||
}
|
||||
return uint(ws.Height), uint(ws.Width)
|
||||
return o.cs.terminalSize()
|
||||
}
|
||||
|
||||
// NewOut returns a new [Out] from an [io.Writer].
|
||||
func NewOut(out io.Writer) *Out {
|
||||
o := &Out{out: out}
|
||||
o.fd, o.isTerminal = term.GetFdInfo(out)
|
||||
return o
|
||||
// SetIsTerminal overrides whether a terminal is connected. It is used to
|
||||
// override this property in unit-tests, and should not be depended on for
|
||||
// other purposes.
|
||||
func (o *Out) SetIsTerminal(isTerminal bool) {
|
||||
o.cs.setIsTerminal(isTerminal)
|
||||
}
|
||||
|
||||
+59
-17
@@ -1,35 +1,77 @@
|
||||
// FIXME(thaJeztah): remove once we are a module; the go:build directive prevents go from downgrading language version to go1.16:
|
||||
//go:build go1.25
|
||||
|
||||
package streams
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/moby/term"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
func newCommonStream(stream any) commonStream {
|
||||
var f *os.File
|
||||
if v, ok := stream.(*os.File); ok {
|
||||
f = v
|
||||
}
|
||||
|
||||
fd, tty := term.GetFdInfo(stream)
|
||||
return commonStream{
|
||||
f: f,
|
||||
fd: fd,
|
||||
tty: tty,
|
||||
}
|
||||
}
|
||||
|
||||
type commonStream struct {
|
||||
fd uintptr
|
||||
isTerminal bool
|
||||
state *term.State
|
||||
f *os.File
|
||||
fd uintptr
|
||||
tty bool
|
||||
state *term.State
|
||||
}
|
||||
|
||||
// FD returns the file descriptor number for this stream.
|
||||
func (s *commonStream) FD() uintptr {
|
||||
return s.fd
|
||||
}
|
||||
func (s *commonStream) FD() uintptr { return s.fd }
|
||||
|
||||
// IsTerminal returns true if this stream is connected to a terminal.
|
||||
func (s *commonStream) IsTerminal() bool {
|
||||
return s.isTerminal
|
||||
}
|
||||
// file returns the underlying *os.File if the stream was constructed from one.
|
||||
func (s *commonStream) file() (*os.File, bool) { return s.f, s.f != nil }
|
||||
|
||||
// RestoreTerminal restores normal mode to the terminal.
|
||||
func (s *commonStream) RestoreTerminal() {
|
||||
// isTerminal returns whether this stream is connected to a terminal.
|
||||
func (s *commonStream) isTerminal() bool { return s.tty }
|
||||
|
||||
// setIsTerminal overrides whether a terminal is connected for testing.
|
||||
func (s *commonStream) setIsTerminal(isTerminal bool) { s.tty = isTerminal }
|
||||
|
||||
// restoreTerminal restores the terminal state if SetRawTerminal succeeded earlier.
|
||||
func (s *commonStream) restoreTerminal() {
|
||||
if s.state != nil {
|
||||
_ = term.RestoreTerminal(s.fd, s.state)
|
||||
}
|
||||
}
|
||||
|
||||
// SetIsTerminal overrides whether a terminal is connected. It is used to
|
||||
// override this property in unit-tests, and should not be depended on for
|
||||
// other purposes.
|
||||
func (s *commonStream) SetIsTerminal(isTerminal bool) {
|
||||
s.isTerminal = isTerminal
|
||||
func (s *commonStream) setRawTerminal(setter func(uintptr) (*term.State, error)) error {
|
||||
if !s.tty || os.Getenv("NORAW") != "" {
|
||||
return nil
|
||||
}
|
||||
state, err := setter(s.fd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.state = state
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *commonStream) terminalSize() (height uint, width uint) {
|
||||
if !s.tty {
|
||||
return 0, 0
|
||||
}
|
||||
ws, err := term.GetWinsize(s.fd)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Debug("Error getting TTY size")
|
||||
if ws == nil {
|
||||
return 0, 0
|
||||
}
|
||||
}
|
||||
return uint(ws.Height), uint(ws.Width)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user