terminal

package
v0.0.0-...-45f07fe Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 10, 2022 License: MPL-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package terminal encapsulates some platform-specific logic for detecting if we're running in a terminal and, if so, properly configuring that terminal to meet the assumptions that the rest of Terraform makes.

Specifically, Terraform requires a Terminal which supports virtual terminal sequences and which accepts UTF-8-encoded text.

This is an abstraction only over the platform-specific detection of and possibly initialization of terminals. It's not intended to provide higher-level abstractions of the sort provided by packages like termcap or curses; ultimately we just assume that terminals are "standard" VT100-like terminals and use a subset of control codes that works across the various platforms we support. Our approximate target is "xterm-compatible" virtual terminals.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type InputStream

type InputStream struct {
	File *os.File
	// contains filtered or unexported fields
}

InputStream represents an input stream that might or might not be a terminal.

There is typically only one instance of this type, representing stdin.

func (*InputStream) IsTerminal

func (s *InputStream) IsTerminal() bool

IsTerminal returns true if we expect that the stream is connected to a terminal which can support interactive input.

If this returns false, callers might prefer to skip elaborate input prompt functionality like tab completion and instead just treat the input as a raw byte stream, or perhaps skip prompting for input at all depending on the situation.

type OutputStream

type OutputStream struct {
	File *os.File
	// contains filtered or unexported fields
}

OutputStream represents an output stream that might or might not be connected to a terminal.

There are typically two instances of this: one representing stdout and one representing stderr.

func (*OutputStream) Columns

func (s *OutputStream) Columns() int

Columns returns a number of character cell columns that we expect will fill the width of the terminal that stdout is connected to, or a reasonable placeholder value of 78 if the output doesn't seem to be a terminal.

This is a best-effort sort of function which may give an inaccurate result in various cases. For example, callers storing the result will not react to subsequent changes in the terminal width, and indeed this function itself may not be able to either, depending on the constraints of the current execution context.

func (*OutputStream) IsTerminal

func (s *OutputStream) IsTerminal() bool

IsTerminal returns true if we expect that the stream is connected to a terminal which supports VT100-style formatting and cursor control sequences.

type PrePanicwrapState

type PrePanicwrapState struct {
	StderrIsTerminal bool
	StderrWidth      int
}

PrePanicwrapState is a horrible thing we use to work around panicwrap, related to both Streams.StateForAfterPanicWrap and ReinitInsidePanicwrap.

type Streams

type Streams struct {
	Stdout *OutputStream
	Stderr *OutputStream
	Stdin  *InputStream
}

Streams represents a collection of three streams that each may or may not be connected to a terminal.

If a stream is connected to a terminal then there are more possibilities available, such as detecting the current terminal width. If we're connected to something else, such as a pipe or a file on disk, the stream will typically provide placeholder values or do-nothing stubs for terminal-requiring operatons.

Note that it's possible for only a subset of the streams to be connected to a terminal. For example, this happens if the user runs Terraform with I/O redirection where Stdout might refer to a regular disk file while Stderr refers to a terminal, or various other similar combinations.

func Init

func Init() (*Streams, error)

Init tries to initialize a terminal, if Terraform is running in one, and returns an object describing what it was able to set up.

An error for this function indicates that the current execution context can't meet Terraform's assumptions. For example, on Windows Init will return an error if Terraform is running in a Windows Console that refuses to activate UTF-8 mode, which can happen if we're running on an unsupported old version of Windows.

Note that the success of this function doesn't mean that we're actually running in a terminal. It could also represent successfully detecting that one or more of the input/output streams is not a terminal.

func ReinitInsidePanicwrap

func ReinitInsidePanicwrap(state *PrePanicwrapState) (*Streams, error)

ReinitInsidePanicwrap is part of the workaround for panicwrap that produces a Streams containing a potentially-lying Stderr that might claim to be a terminal even if it's actually a pipe connected to the parent process.

That's an okay lie in practice because the parent process will copy any data it recieves via that pipe verbatim to the real stderr anyway. (The original call to Init in the parent process should've already done any necessary modesetting on the Stderr terminal, if any.)

The state argument can be nil if we're not running in panicwrap mode, in which case this function behaves exactly the same as Init.

func StreamsForTesting

func StreamsForTesting(t *testing.T) (streams *Streams, close func(*testing.T) *TestOutput)

StreamsForTesting is a helper for test code that is aiming to test functions that interact with the input and output streams.

This particular function is for the simple case of a function that only produces output: the returned input stream is connected to the system's "null device", as if a user had run Terraform with I/O redirection like </dev/null on Unix. It also configures the output as a pipe rather than as a terminal, and so can't be used to test whether code is able to adapt to different terminal widths.

The return values are a Streams object ready to pass into a function under test, and a callback function for the test itself to call afterwards in order to obtain any characters that were written to the streams. Once you call the close function, the Streams object becomes invalid and must not be used anymore. Any caller of this function _must_ call close before its test concludes, even if it doesn't intend to check the output, or else it will leak resources.

Since this function is for testing only, for convenience it will react to any setup errors by logging a message to the given testing.T object and then failing the test, preventing any later code from running.

func (*Streams) Eprint

func (s *Streams) Eprint(a ...interface{}) (n int, err error)

Eprint is a helper for conveniently calling fmt.Fprint on the Stderr stream.

func (*Streams) Eprintf

func (s *Streams) Eprintf(format string, a ...interface{}) (n int, err error)

Eprintf is a helper for conveniently calling fmt.Fprintf on the Stderr stream.

func (*Streams) Eprintln

func (s *Streams) Eprintln(a ...interface{}) (n int, err error)

Eprintln is a helper for conveniently calling fmt.Fprintln on the Stderr stream.

func (*Streams) Print

func (s *Streams) Print(a ...interface{}) (n int, err error)

Print is a helper for conveniently calling fmt.Fprint on the Stdout stream.

func (*Streams) Printf

func (s *Streams) Printf(format string, a ...interface{}) (n int, err error)

Printf is a helper for conveniently calling fmt.Fprintf on the Stdout stream.

func (*Streams) Println

func (s *Streams) Println(a ...interface{}) (n int, err error)

Println is a helper for conveniently calling fmt.Fprintln on the Stdout stream.

func (*Streams) StateForAfterPanicWrap

func (s *Streams) StateForAfterPanicWrap() *PrePanicwrapState

StateForAfterPanicWrap is part of the workaround for panicwrap that captures some characteristics of stderr that the caller can pass to the panicwrap child process somehow and then use ReinitInsidePanicWrap.

type TestOutput

type TestOutput struct {
	// contains filtered or unexported fields
}

TestOutput is a type used to return the results from the various stream testing helpers. It encapsulates any captured writes to the output and error streams, and has methods to consume that data in some different ways to allow for a few different styles of testing.

func (TestOutput) All

func (o TestOutput) All() string

All returns the output written to both the Stdout and Stderr streams, interleaved together in the order of writing in a single string.

func (TestOutput) Stderr

func (o TestOutput) Stderr() string

Stderr returns the output written to just the Stderr stream, ignoring anything that was written to the Stdout stream.

func (TestOutput) Stdout

func (o TestOutput) Stdout() string

Stdout returns the output written to just the Stdout stream, ignoring anything that was written to the Stderr stream.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL