aboutsummaryrefslogtreecommitdiff
path: root/vendor/k8s.io/kubernetes/pkg/util/term
diff options
context:
space:
mode:
authorMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
committerMatthew Heon <matthew.heon@gmail.com>2017-11-01 11:24:59 -0400
commita031b83a09a8628435317a03f199cdc18b78262f (patch)
treebc017a96769ce6de33745b8b0b1304ccf38e9df0 /vendor/k8s.io/kubernetes/pkg/util/term
parent2b74391cd5281f6fdf391ff8ad50fd1490f6bf89 (diff)
downloadpodman-a031b83a09a8628435317a03f199cdc18b78262f.tar.gz
podman-a031b83a09a8628435317a03f199cdc18b78262f.tar.bz2
podman-a031b83a09a8628435317a03f199cdc18b78262f.zip
Initial checkin from CRI-O repo
Signed-off-by: Matthew Heon <matthew.heon@gmail.com>
Diffstat (limited to 'vendor/k8s.io/kubernetes/pkg/util/term')
-rw-r--r--vendor/k8s.io/kubernetes/pkg/util/term/resize.go132
-rw-r--r--vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go61
-rw-r--r--vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go62
-rw-r--r--vendor/k8s.io/kubernetes/pkg/util/term/setsize.go29
-rw-r--r--vendor/k8s.io/kubernetes/pkg/util/term/setsize_unsupported.go28
-rw-r--r--vendor/k8s.io/kubernetes/pkg/util/term/term.go110
-rw-r--r--vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go124
7 files changed, 546 insertions, 0 deletions
diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/resize.go b/vendor/k8s.io/kubernetes/pkg/util/term/resize.go
new file mode 100644
index 000000000..7ca09a858
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/util/term/resize.go
@@ -0,0 +1,132 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package term
+
+import (
+ "fmt"
+
+ "github.com/docker/docker/pkg/term"
+ "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/client-go/tools/remotecommand"
+)
+
+// GetSize returns the current size of the user's terminal. If it isn't a terminal,
+// nil is returned.
+func (t TTY) GetSize() *remotecommand.TerminalSize {
+ outFd, isTerminal := term.GetFdInfo(t.Out)
+ if !isTerminal {
+ return nil
+ }
+ return GetSize(outFd)
+}
+
+// GetSize returns the current size of the terminal associated with fd.
+func GetSize(fd uintptr) *remotecommand.TerminalSize {
+ winsize, err := term.GetWinsize(fd)
+ if err != nil {
+ runtime.HandleError(fmt.Errorf("unable to get terminal size: %v", err))
+ return nil
+ }
+
+ return &remotecommand.TerminalSize{Width: winsize.Width, Height: winsize.Height}
+}
+
+// MonitorSize monitors the terminal's size. It returns a TerminalSizeQueue primed with
+// initialSizes, or nil if there's no TTY present.
+func (t *TTY) MonitorSize(initialSizes ...*remotecommand.TerminalSize) remotecommand.TerminalSizeQueue {
+ outFd, isTerminal := term.GetFdInfo(t.Out)
+ if !isTerminal {
+ return nil
+ }
+
+ t.sizeQueue = &sizeQueue{
+ t: *t,
+ // make it buffered so we can send the initial terminal sizes without blocking, prior to starting
+ // the streaming below
+ resizeChan: make(chan remotecommand.TerminalSize, len(initialSizes)),
+ stopResizing: make(chan struct{}),
+ }
+
+ t.sizeQueue.monitorSize(outFd, initialSizes...)
+
+ return t.sizeQueue
+}
+
+// sizeQueue implements remotecommand.TerminalSizeQueue
+type sizeQueue struct {
+ t TTY
+ // resizeChan receives a Size each time the user's terminal is resized.
+ resizeChan chan remotecommand.TerminalSize
+ stopResizing chan struct{}
+}
+
+// make sure sizeQueue implements the resize.TerminalSizeQueue interface
+var _ remotecommand.TerminalSizeQueue = &sizeQueue{}
+
+// monitorSize primes resizeChan with initialSizes and then monitors for resize events. With each
+// new event, it sends the current terminal size to resizeChan.
+func (s *sizeQueue) monitorSize(outFd uintptr, initialSizes ...*remotecommand.TerminalSize) {
+ // send the initial sizes
+ for i := range initialSizes {
+ if initialSizes[i] != nil {
+ s.resizeChan <- *initialSizes[i]
+ }
+ }
+
+ resizeEvents := make(chan remotecommand.TerminalSize, 1)
+
+ monitorResizeEvents(outFd, resizeEvents, s.stopResizing)
+
+ // listen for resize events in the background
+ go func() {
+ defer runtime.HandleCrash()
+
+ for {
+ select {
+ case size, ok := <-resizeEvents:
+ if !ok {
+ return
+ }
+
+ select {
+ // try to send the size to resizeChan, but don't block
+ case s.resizeChan <- size:
+ // send successful
+ default:
+ // unable to send / no-op
+ }
+ case <-s.stopResizing:
+ return
+ }
+ }
+ }()
+}
+
+// Next returns the new terminal size after the terminal has been resized. It returns nil when
+// monitoring has been stopped.
+func (s *sizeQueue) Next() *remotecommand.TerminalSize {
+ size, ok := <-s.resizeChan
+ if !ok {
+ return nil
+ }
+ return &size
+}
+
+// stop stops the background goroutine that is monitoring for terminal resizes.
+func (s *sizeQueue) stop() {
+ close(s.stopResizing)
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go b/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go
new file mode 100644
index 000000000..75e9690df
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents.go
@@ -0,0 +1,61 @@
+// +build !windows
+
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package term
+
+import (
+ "os"
+ "os/signal"
+ "syscall"
+
+ "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/client-go/tools/remotecommand"
+)
+
+// monitorResizeEvents spawns a goroutine that waits for SIGWINCH signals (these indicate the
+// terminal has resized). After receiving a SIGWINCH, this gets the terminal size and tries to send
+// it to the resizeEvents channel. The goroutine stops when the stop channel is closed.
+func monitorResizeEvents(fd uintptr, resizeEvents chan<- remotecommand.TerminalSize, stop chan struct{}) {
+ go func() {
+ defer runtime.HandleCrash()
+
+ winch := make(chan os.Signal, 1)
+ signal.Notify(winch, syscall.SIGWINCH)
+ defer signal.Stop(winch)
+
+ for {
+ select {
+ case <-winch:
+ size := GetSize(fd)
+ if size == nil {
+ return
+ }
+
+ // try to send size
+ select {
+ case resizeEvents <- *size:
+ // success
+ default:
+ // not sent
+ }
+ case <-stop:
+ return
+ }
+ }
+ }()
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go b/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go
new file mode 100644
index 000000000..adccf8734
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/util/term/resizeevents_windows.go
@@ -0,0 +1,62 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package term
+
+import (
+ "time"
+
+ "k8s.io/apimachinery/pkg/util/runtime"
+ "k8s.io/client-go/tools/remotecommand"
+)
+
+// monitorResizeEvents spawns a goroutine that periodically gets the terminal size and tries to send
+// it to the resizeEvents channel if the size has changed. The goroutine stops when the stop channel
+// is closed.
+func monitorResizeEvents(fd uintptr, resizeEvents chan<- remotecommand.TerminalSize, stop chan struct{}) {
+ go func() {
+ defer runtime.HandleCrash()
+
+ size := GetSize(fd)
+ if size == nil {
+ return
+ }
+ lastSize := *size
+
+ for {
+ // see if we need to stop running
+ select {
+ case <-stop:
+ return
+ default:
+ }
+
+ size := GetSize(fd)
+ if size == nil {
+ return
+ }
+
+ if size.Height != lastSize.Height || size.Width != lastSize.Width {
+ lastSize.Height = size.Height
+ lastSize.Width = size.Width
+ resizeEvents <- *size
+ }
+
+ // sleep to avoid hot looping
+ time.Sleep(250 * time.Millisecond)
+ }
+ }()
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/setsize.go b/vendor/k8s.io/kubernetes/pkg/util/term/setsize.go
new file mode 100644
index 000000000..8cccd431a
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/util/term/setsize.go
@@ -0,0 +1,29 @@
+// +build !windows
+
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package term
+
+import (
+ "github.com/docker/docker/pkg/term"
+ "k8s.io/client-go/tools/remotecommand"
+)
+
+// SetSize sets the terminal size associated with fd.
+func SetSize(fd uintptr, size remotecommand.TerminalSize) error {
+ return term.SetWinsize(fd, &term.Winsize{Height: size.Height, Width: size.Width})
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/setsize_unsupported.go b/vendor/k8s.io/kubernetes/pkg/util/term/setsize_unsupported.go
new file mode 100644
index 000000000..82220217a
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/util/term/setsize_unsupported.go
@@ -0,0 +1,28 @@
+// +build windows
+
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package term
+
+import (
+ "k8s.io/client-go/tools/remotecommand"
+)
+
+func SetSize(fd uintptr, size remotecommand.TerminalSize) error {
+ // NOP
+ return nil
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/term.go b/vendor/k8s.io/kubernetes/pkg/util/term/term.go
new file mode 100644
index 000000000..58baee831
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/util/term/term.go
@@ -0,0 +1,110 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package term
+
+import (
+ "io"
+ "os"
+
+ "github.com/docker/docker/pkg/term"
+
+ "k8s.io/kubernetes/pkg/util/interrupt"
+)
+
+// SafeFunc is a function to be invoked by TTY.
+type SafeFunc func() error
+
+// TTY helps invoke a function and preserve the state of the terminal, even if the process is
+// terminated during execution. It also provides support for terminal resizing for remote command
+// execution/attachment.
+type TTY struct {
+ // In is a reader representing stdin. It is a required field.
+ In io.Reader
+ // Out is a writer representing stdout. It must be set to support terminal resizing. It is an
+ // optional field.
+ Out io.Writer
+ // Raw is true if the terminal should be set raw.
+ Raw bool
+ // TryDev indicates the TTY should try to open /dev/tty if the provided input
+ // is not a file descriptor.
+ TryDev bool
+ // Parent is an optional interrupt handler provided to this function - if provided
+ // it will be invoked after the terminal state is restored. If it is not provided,
+ // a signal received during the TTY will result in os.Exit(0) being invoked.
+ Parent *interrupt.Handler
+
+ // sizeQueue is set after a call to MonitorSize() and is used to monitor SIGWINCH signals when the
+ // user's terminal resizes.
+ sizeQueue *sizeQueue
+}
+
+// IsTerminalIn returns true if t.In is a terminal. Does not check /dev/tty
+// even if TryDev is set.
+func (t TTY) IsTerminalIn() bool {
+ return IsTerminal(t.In)
+}
+
+// IsTerminalOut returns true if t.Out is a terminal. Does not check /dev/tty
+// even if TryDev is set.
+func (t TTY) IsTerminalOut() bool {
+ return IsTerminal(t.Out)
+}
+
+// IsTerminal returns whether the passed object is a terminal or not
+func IsTerminal(i interface{}) bool {
+ _, terminal := term.GetFdInfo(i)
+ return terminal
+}
+
+// Safe invokes the provided function and will attempt to ensure that when the
+// function returns (or a termination signal is sent) that the terminal state
+// is reset to the condition it was in prior to the function being invoked. If
+// t.Raw is true the terminal will be put into raw mode prior to calling the function.
+// If the input file descriptor is not a TTY and TryDev is true, the /dev/tty file
+// will be opened (if available).
+func (t TTY) Safe(fn SafeFunc) error {
+ inFd, isTerminal := term.GetFdInfo(t.In)
+
+ if !isTerminal && t.TryDev {
+ if f, err := os.Open("/dev/tty"); err == nil {
+ defer f.Close()
+ inFd = f.Fd()
+ isTerminal = term.IsTerminal(inFd)
+ }
+ }
+ if !isTerminal {
+ return fn()
+ }
+
+ var state *term.State
+ var err error
+ if t.Raw {
+ state, err = term.MakeRaw(inFd)
+ } else {
+ state, err = term.SaveState(inFd)
+ }
+ if err != nil {
+ return err
+ }
+ return interrupt.Chain(t.Parent, func() {
+ if t.sizeQueue != nil {
+ t.sizeQueue.stop()
+ }
+
+ term.RestoreTerminal(inFd, state)
+ }).Run(fn)
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go b/vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go
new file mode 100644
index 000000000..2d72d1e45
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/util/term/term_writer.go
@@ -0,0 +1,124 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package term
+
+import (
+ "io"
+ "os"
+
+ "github.com/docker/docker/pkg/term"
+ wordwrap "github.com/mitchellh/go-wordwrap"
+)
+
+type wordWrapWriter struct {
+ limit uint
+ writer io.Writer
+}
+
+// NewResponsiveWriter creates a Writer that detects the column width of the
+// terminal we are in, and adjusts every line width to fit and use recommended
+// terminal sizes for better readability. Does proper word wrapping automatically.
+// if terminal width >= 120 columns use 120 columns
+// if terminal width >= 100 columns use 100 columns
+// if terminal width >= 80 columns use 80 columns
+// In case we're not in a terminal or if it's smaller than 80 columns width,
+// doesn't do any wrapping.
+func NewResponsiveWriter(w io.Writer) io.Writer {
+ file, ok := w.(*os.File)
+ if !ok {
+ return w
+ }
+ fd := file.Fd()
+ if !term.IsTerminal(fd) {
+ return w
+ }
+
+ terminalSize := GetSize(fd)
+ if terminalSize == nil {
+ return w
+ }
+
+ var limit uint
+ switch {
+ case terminalSize.Width >= 120:
+ limit = 120
+ case terminalSize.Width >= 100:
+ limit = 100
+ case terminalSize.Width >= 80:
+ limit = 80
+ }
+
+ return NewWordWrapWriter(w, limit)
+}
+
+// NewWordWrapWriter is a Writer that supports a limit of characters on every line
+// and does auto word wrapping that respects that limit.
+func NewWordWrapWriter(w io.Writer, limit uint) io.Writer {
+ return &wordWrapWriter{
+ limit: limit,
+ writer: w,
+ }
+}
+
+func (w wordWrapWriter) Write(p []byte) (nn int, err error) {
+ if w.limit == 0 {
+ return w.writer.Write(p)
+ }
+ original := string(p)
+ wrapped := wordwrap.WrapString(original, w.limit)
+ return w.writer.Write([]byte(wrapped))
+}
+
+// NewPunchCardWriter is a NewWordWrapWriter that limits the line width to 80 columns.
+func NewPunchCardWriter(w io.Writer) io.Writer {
+ return NewWordWrapWriter(w, 80)
+}
+
+type maxWidthWriter struct {
+ maxWidth uint
+ currentWidth uint
+ written uint
+ writer io.Writer
+}
+
+// NewMaxWidthWriter is a Writer that supports a limit of characters on every
+// line, but doesn't do any word wrapping automatically.
+func NewMaxWidthWriter(w io.Writer, maxWidth uint) io.Writer {
+ return &maxWidthWriter{
+ maxWidth: maxWidth,
+ writer: w,
+ }
+}
+
+func (m maxWidthWriter) Write(p []byte) (nn int, err error) {
+ for _, b := range p {
+ if m.currentWidth == m.maxWidth {
+ m.writer.Write([]byte{'\n'})
+ m.currentWidth = 0
+ }
+ if b == '\n' {
+ m.currentWidth = 0
+ }
+ _, err := m.writer.Write([]byte{b})
+ if err != nil {
+ return int(m.written), err
+ }
+ m.written++
+ m.currentWidth++
+ }
+ return len(p), nil
+}