command: Use the new terminal.Streams object
Here we propagate in the initialized terminal.Streams from package main, and then onwards to backends running in CLI mode. This also replaces our use of helper/wrappedstreams to determine whether stdin is a terminal or a pipe. helper/wrappedstreams returns incorrect file descriptors on Windows, causing StdinPiped to always return false on that platform and thus causing one of the odd behaviors discussed in Finally, this includes some wrappers around the ability to look up the number of columns in the terminal in preparation for use elsewhere. These wrappers deal with the fact that our unit tests typically won't populate meta.Streams.
This commit is contained in:
parent
15c0645bd5
commit
d2c3403ab6
|
@ -1,9 +1,11 @@
|
|||
package backend
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/mitchellh/cli"
|
||||
"github.com/mitchellh/colorstring"
|
||||
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
// CLI is an optional interface that can be implemented to be initialized
|
||||
|
@ -48,6 +50,12 @@ type CLIOpts struct {
|
|||
CLI cli.Ui
|
||||
CLIColor *colorstring.Colorize
|
||||
|
||||
// Streams describes the low-level streams for Stdout, Stderr and Stdin,
|
||||
// including some metadata about whether they are terminals. Most output
|
||||
// should go via the object in field CLI above, but Streams can be useful
|
||||
// for tailoring the output to fit the attached terminal, for example.
|
||||
Streams *terminal.Streams
|
||||
|
||||
// ShowDiagnostics is a function that will format and print diagnostic
|
||||
// messages to the UI.
|
||||
ShowDiagnostics func(vals ...interface{})
|
||||
|
|
|
@ -14,6 +14,7 @@ import (
|
|||
"github.com/hashicorp/terraform/backend"
|
||||
"github.com/hashicorp/terraform/command/clistate"
|
||||
"github.com/hashicorp/terraform/configs/configschema"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/states/statemgr"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"github.com/hashicorp/terraform/tfdiags"
|
||||
|
@ -38,6 +39,10 @@ type Local struct {
|
|||
CLI cli.Ui
|
||||
CLIColor *colorstring.Colorize
|
||||
|
||||
// If CLI is set then Streams might also be set, to describe the physical
|
||||
// input/output handles that CLI is connected to.
|
||||
Streams *terminal.Streams
|
||||
|
||||
// ShowDiagnostics prints diagnostic messages to the UI.
|
||||
ShowDiagnostics func(vals ...interface{})
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
func (b *Local) CLIInit(opts *backend.CLIOpts) error {
|
||||
b.CLI = opts.CLI
|
||||
b.CLIColor = opts.CLIColor
|
||||
b.Streams = opts.Streams
|
||||
b.ShowDiagnostics = opts.ShowDiagnostics
|
||||
b.ContextOpts = opts.ContextOpts
|
||||
b.OpInput = opts.Input
|
||||
|
@ -34,3 +35,31 @@ func (b *Local) CLIInit(opts *backend.CLIOpts) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
// outputColumns returns the number of text character cells any non-error
|
||||
// output should be wrapped to.
|
||||
//
|
||||
// This is the number of columns to use if you are calling b.CLI.Output or
|
||||
// b.CLI.Info.
|
||||
func (b *Local) outputColumns() int {
|
||||
if b.Streams == nil {
|
||||
// We can potentially get here in tests, if they don't populate the
|
||||
// CLIOpts fully.
|
||||
return 78 // placeholder just so we don't panic
|
||||
}
|
||||
return b.Streams.Stdout.Columns()
|
||||
}
|
||||
|
||||
// errorColumns returns the number of text character cells any error
|
||||
// output should be wrapped to.
|
||||
//
|
||||
// This is the number of columns to use if you are calling b.CLI.Error or
|
||||
// b.CLI.Warn.
|
||||
func (b *Local) errorColumns() int {
|
||||
if b.Streams == nil {
|
||||
// We can potentially get here in tests, if they don't populate the
|
||||
// CLIOpts fully.
|
||||
return 78 // placeholder just so we don't panic
|
||||
}
|
||||
return b.Streams.Stderr.Columns()
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ import (
|
|||
"github.com/hashicorp/terraform/command/format"
|
||||
"github.com/hashicorp/terraform/command/webbrowser"
|
||||
"github.com/hashicorp/terraform/configs/configload"
|
||||
"github.com/hashicorp/terraform/helper/wrappedstreams"
|
||||
"github.com/hashicorp/terraform/internal/getproviders"
|
||||
"github.com/hashicorp/terraform/internal/terminal"
|
||||
"github.com/hashicorp/terraform/providers"
|
||||
"github.com/hashicorp/terraform/provisioners"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
|
@ -51,6 +51,15 @@ type Meta struct {
|
|||
// for some reason.
|
||||
OriginalWorkingDir string
|
||||
|
||||
// Streams tracks the raw Stdout, Stderr, and Stdin handles along with
|
||||
// some basic metadata about them, such as whether each is connected to
|
||||
// a terminal, how wide the possible terminal is, etc.
|
||||
//
|
||||
// For historical reasons this might not be set in unit test code, and
|
||||
// so functions working with this field must check if it's nil and
|
||||
// do some default behavior instead if so, rather than panicking.
|
||||
Streams *terminal.Streams
|
||||
|
||||
Color bool // True if output should be colored
|
||||
GlobalPluginDirs []string // Additional paths to search for plugins
|
||||
Ui cli.Ui // Ui for output
|
||||
|
@ -288,15 +297,42 @@ func (m *Meta) UIInput() terraform.UIInput {
|
|||
}
|
||||
}
|
||||
|
||||
// StdinPiped returns true if the input is piped.
|
||||
func (m *Meta) StdinPiped() bool {
|
||||
fi, err := wrappedstreams.Stdin().Stat()
|
||||
if err != nil {
|
||||
// If there is an error, let's just say its not piped
|
||||
return false
|
||||
// OutputColumns returns the number of columns that normal (non-error) UI
|
||||
// output should be wrapped to fill.
|
||||
//
|
||||
// This is the column count to use if you'll be printing your message via
|
||||
// the Output or Info methods of m.Ui.
|
||||
func (m *Meta) OutputColumns() int {
|
||||
if m.Streams == nil {
|
||||
// A default for unit tests that don't populate Meta fully.
|
||||
return 78
|
||||
}
|
||||
return m.Streams.Stdout.Columns()
|
||||
}
|
||||
|
||||
return fi.Mode()&os.ModeNamedPipe != 0
|
||||
// ErrorColumns returns the number of columns that error UI output should be
|
||||
// wrapped to fill.
|
||||
//
|
||||
// This is the column count to use if you'll be printing your message via
|
||||
// the Error or Warn methods of m.Ui.
|
||||
func (m *Meta) ErrorColumns() int {
|
||||
if m.Streams == nil {
|
||||
// A default for unit tests that don't populate Meta fully.
|
||||
return 78
|
||||
}
|
||||
return m.Streams.Stderr.Columns()
|
||||
}
|
||||
|
||||
// StdinPiped returns true if the input is piped.
|
||||
func (m *Meta) StdinPiped() bool {
|
||||
if m.Streams == nil {
|
||||
// If we don't have m.Streams populated then we're presumably in a unit
|
||||
// test that doesn't properly populate Meta, so we'll just say the
|
||||
// output _isn't_ piped because that's the common case and so most likely
|
||||
// to be useful to a unit test.
|
||||
return false
|
||||
}
|
||||
return !m.Streams.Stdin.IsTerminal()
|
||||
}
|
||||
|
||||
// InterruptibleContext returns a context.Context that will be cancelled
|
||||
|
|
|
@ -308,6 +308,7 @@ func (m *Meta) backendCLIOpts() (*backend.CLIOpts, error) {
|
|||
return &backend.CLIOpts{
|
||||
CLI: m.Ui,
|
||||
CLIColor: m.Colorize(),
|
||||
Streams: m.Streams,
|
||||
ShowDiagnostics: m.showDiagnostics,
|
||||
StatePath: m.statePath,
|
||||
StateOutPath: m.stateOutPath,
|
||||
|
|
|
@ -80,6 +80,7 @@ func initCommands(
|
|||
|
||||
meta := command.Meta{
|
||||
OriginalWorkingDir: originalWorkingDir,
|
||||
Streams: streams,
|
||||
|
||||
Color: true,
|
||||
GlobalPluginDirs: globalPluginDirs(),
|
||||
|
|
1
go.mod
1
go.mod
|
@ -80,7 +80,6 @@ require (
|
|||
github.com/lusis/go-artifactory v0.0.0-20160115162124-7e4ce345df82
|
||||
github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786 // indirect
|
||||
github.com/masterzen/winrm v0.0.0-20200615185753-c42b5136ff88
|
||||
github.com/mattn/go-colorable v0.1.8 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12
|
||||
github.com/mattn/go-shellwords v1.0.4
|
||||
github.com/miekg/dns v1.0.8 // indirect
|
||||
|
|
3
go.sum
3
go.sum
|
@ -420,9 +420,8 @@ github.com/masterzen/simplexml v0.0.0-20190410153822-31eea3082786/go.mod h1:kCEb
|
|||
github.com/masterzen/winrm v0.0.0-20200615185753-c42b5136ff88 h1:cxuVcCvCLD9yYDbRCWw0jSgh1oT6P6mv3aJDKK5o7X4=
|
||||
github.com/masterzen/winrm v0.0.0-20200615185753-c42b5136ff88/go.mod h1:a2HXwefeat3evJHxFXSayvRHpYEPJYtErl4uIzfaUqY=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
|
||||
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
|
|
Loading…
Reference in New Issue