| // 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. |
| package terminal |
| |
| import ( |
| "fmt" |
| "os" |
| ) |
| |
| // 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. |
| type Streams struct { |
| Stdout *OutputStream |
| Stderr *OutputStream |
| Stdin *InputStream |
| } |
| |
| // 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 Init() (*Streams, error) { |
| // These configure* functions are platform-specific functions in other |
| // files that use //+build constraints to vary based on target OS. |
| |
| stderr, err := configureOutputHandle(os.Stderr) |
| if err != nil { |
| return nil, err |
| } |
| stdout, err := configureOutputHandle(os.Stdout) |
| if err != nil { |
| return nil, err |
| } |
| stdin, err := configureInputHandle(os.Stdin) |
| if err != nil { |
| return nil, err |
| } |
| |
| return &Streams{ |
| Stdout: stdout, |
| Stderr: stderr, |
| Stdin: stdin, |
| }, nil |
| } |
| |
| // Print is a helper for conveniently calling fmt.Fprint on the Stdout stream. |
| func (s *Streams) Print(a ...interface{}) (n int, err error) { |
| return fmt.Fprint(s.Stdout.File, a...) |
| } |
| |
| // Printf is a helper for conveniently calling fmt.Fprintf on the Stdout stream. |
| func (s *Streams) Printf(format string, a ...interface{}) (n int, err error) { |
| return fmt.Fprintf(s.Stdout.File, format, a...) |
| } |
| |
| // Println is a helper for conveniently calling fmt.Fprintln on the Stdout stream. |
| func (s *Streams) Println(a ...interface{}) (n int, err error) { |
| return fmt.Fprintln(s.Stdout.File, a...) |
| } |
| |
| // Eprint is a helper for conveniently calling fmt.Fprint on the Stderr stream. |
| func (s *Streams) Eprint(a ...interface{}) (n int, err error) { |
| return fmt.Fprint(s.Stderr.File, a...) |
| } |
| |
| // Eprintf is a helper for conveniently calling fmt.Fprintf on the Stderr stream. |
| func (s *Streams) Eprintf(format string, a ...interface{}) (n int, err error) { |
| return fmt.Fprintf(s.Stderr.File, format, a...) |
| } |
| |
| // Eprintln is a helper for conveniently calling fmt.Fprintln on the Stderr stream. |
| func (s *Streams) Eprintln(a ...interface{}) (n int, err error) { |
| return fmt.Fprintln(s.Stderr.File, a...) |
| } |