mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-26 08:51:02 -06:00
ffe056bacb
This is part of a general effort to move all of Terraform's non-library package surface under internal in order to reinforce that these are for internal use within Terraform only. If you were previously importing packages under this prefix into an external codebase, you could pin to an earlier release tag as an interim solution until you've make a plan to achieve the same functionality some other way.
163 lines
5.3 KiB
Go
163 lines
5.3 KiB
Go
package views
|
|
|
|
import (
|
|
"github.com/hashicorp/terraform/internal/command/arguments"
|
|
"github.com/hashicorp/terraform/internal/command/format"
|
|
"github.com/hashicorp/terraform/internal/terminal"
|
|
"github.com/hashicorp/terraform/internal/tfdiags"
|
|
"github.com/mitchellh/colorstring"
|
|
)
|
|
|
|
// View is the base layer for command views, encapsulating a set of I/O
|
|
// streams, a colorize implementation, and implementing a human friendly view
|
|
// for diagnostics.
|
|
type View struct {
|
|
streams *terminal.Streams
|
|
colorize *colorstring.Colorize
|
|
|
|
compactWarnings bool
|
|
|
|
// When this is true it's a hint that Terraform is being run indirectly
|
|
// via a wrapper script or other automation and so we may wish to replace
|
|
// direct examples of commands to run with more conceptual directions.
|
|
// However, we only do this on a best-effort basis, typically prioritizing
|
|
// the messages that users are most likely to see.
|
|
runningInAutomation bool
|
|
|
|
// This unfortunate wart is required to enable rendering of diagnostics which
|
|
// have associated source code in the configuration. This function pointer
|
|
// will be dereferenced as late as possible when rendering diagnostics in
|
|
// order to access the config loader cache.
|
|
configSources func() map[string][]byte
|
|
}
|
|
|
|
// Initialize a View with the given streams, a disabled colorize object, and a
|
|
// no-op configSources callback.
|
|
func NewView(streams *terminal.Streams) *View {
|
|
return &View{
|
|
streams: streams,
|
|
colorize: &colorstring.Colorize{
|
|
Colors: colorstring.DefaultColors,
|
|
Disable: true,
|
|
Reset: true,
|
|
},
|
|
configSources: func() map[string][]byte { return nil },
|
|
}
|
|
}
|
|
|
|
// SetRunningInAutomation modifies the view's "running in automation" flag,
|
|
// which causes some slight adjustments to certain messages that would normally
|
|
// suggest specific Terraform commands to run, to make more conceptual gestures
|
|
// instead for situations where the user isn't running Terraform directly.
|
|
//
|
|
// For convenient use during initialization (in conjunction with NewView),
|
|
// SetRunningInAutomation returns the reciever after modifying it.
|
|
func (v *View) SetRunningInAutomation(new bool) *View {
|
|
v.runningInAutomation = new
|
|
return v
|
|
}
|
|
|
|
func (v *View) RunningInAutomation() bool {
|
|
return v.runningInAutomation
|
|
}
|
|
|
|
// Configure applies the global view configuration flags.
|
|
func (v *View) Configure(view *arguments.View) {
|
|
v.colorize.Disable = view.NoColor
|
|
v.compactWarnings = view.CompactWarnings
|
|
}
|
|
|
|
// SetConfigSources overrides the default no-op callback with a new function
|
|
// pointer, and should be called when the config loader is initialized.
|
|
func (v *View) SetConfigSources(cb func() map[string][]byte) {
|
|
v.configSources = cb
|
|
}
|
|
|
|
// Diagnostics renders a set of warnings and errors in human-readable form.
|
|
// Warnings are printed to stdout, and errors to stderr.
|
|
func (v *View) Diagnostics(diags tfdiags.Diagnostics) {
|
|
diags.Sort()
|
|
|
|
if len(diags) == 0 {
|
|
return
|
|
}
|
|
|
|
diags = diags.ConsolidateWarnings(1)
|
|
|
|
// Since warning messages are generally competing
|
|
if v.compactWarnings {
|
|
// If the user selected compact warnings and all of the diagnostics are
|
|
// warnings then we'll use a more compact representation of the warnings
|
|
// that only includes their summaries.
|
|
// We show full warnings if there are also errors, because a warning
|
|
// can sometimes serve as good context for a subsequent error.
|
|
useCompact := true
|
|
for _, diag := range diags {
|
|
if diag.Severity() != tfdiags.Warning {
|
|
useCompact = false
|
|
break
|
|
}
|
|
}
|
|
if useCompact {
|
|
msg := format.DiagnosticWarningsCompact(diags, v.colorize)
|
|
msg = "\n" + msg + "\nTo see the full warning notes, run Terraform without -compact-warnings.\n"
|
|
v.streams.Print(msg)
|
|
return
|
|
}
|
|
}
|
|
|
|
for _, diag := range diags {
|
|
var msg string
|
|
if v.colorize.Disable {
|
|
msg = format.DiagnosticPlain(diag, v.configSources(), v.streams.Stderr.Columns())
|
|
} else {
|
|
msg = format.Diagnostic(diag, v.configSources(), v.colorize, v.streams.Stderr.Columns())
|
|
}
|
|
|
|
if diag.Severity() == tfdiags.Error {
|
|
v.streams.Eprint(msg)
|
|
} else {
|
|
v.streams.Print(msg)
|
|
}
|
|
}
|
|
}
|
|
|
|
// HelpPrompt is intended to be called from commands which fail to parse all
|
|
// of their CLI arguments successfully. It refers users to the full help output
|
|
// rather than rendering it directly, which can be overwhelming and confusing.
|
|
func (v *View) HelpPrompt(command string) {
|
|
v.streams.Eprintf(helpPrompt, command)
|
|
}
|
|
|
|
const helpPrompt = `
|
|
For more help on using this command, run:
|
|
terraform %s -help
|
|
`
|
|
|
|
// 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 v.streams.Print or
|
|
// related functions.
|
|
func (v *View) outputColumns() int {
|
|
return v.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 v.streams.Eprint
|
|
// or related functions.
|
|
func (v *View) errorColumns() int {
|
|
return v.streams.Stderr.Columns()
|
|
}
|
|
|
|
// outputHorizRule will call v.streams.Println with enough horizontal line
|
|
// characters to fill an entire row of output.
|
|
//
|
|
// If UI color is enabled, the rule will get a dark grey coloring to try to
|
|
// visually de-emphasize it.
|
|
func (v *View) outputHorizRule() {
|
|
v.streams.Println(format.HorizontalRule(v.colorize, v.outputColumns()))
|
|
}
|