main: initialize the terminal (if any) using internal/terminal
We need to call into terminal.Init in early startup to make sure that we either have a suitable Terminal or that we disable attempts to use virtual terminal escape sequences. This commit gets the terminal initialized but doesn't do much with it after that. Subsequent commits will make more use of this.
This commit is contained in:
parent
17728c8fe8
commit
15c0645bd5
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/command/cliconfig"
|
"github.com/hashicorp/terraform/command/cliconfig"
|
||||||
"github.com/hashicorp/terraform/command/webbrowser"
|
"github.com/hashicorp/terraform/command/webbrowser"
|
||||||
"github.com/hashicorp/terraform/internal/getproviders"
|
"github.com/hashicorp/terraform/internal/getproviders"
|
||||||
|
"github.com/hashicorp/terraform/internal/terminal"
|
||||||
pluginDiscovery "github.com/hashicorp/terraform/plugin/discovery"
|
pluginDiscovery "github.com/hashicorp/terraform/plugin/discovery"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -48,6 +49,7 @@ var Ui cli.Ui
|
||||||
|
|
||||||
func initCommands(
|
func initCommands(
|
||||||
originalWorkingDir string,
|
originalWorkingDir string,
|
||||||
|
streams *terminal.Streams,
|
||||||
config *cliconfig.Config,
|
config *cliconfig.Config,
|
||||||
services *disco.Disco,
|
services *disco.Disco,
|
||||||
providerSrc getproviders.Source,
|
providerSrc getproviders.Source,
|
||||||
|
|
58
main.go
58
main.go
|
@ -19,6 +19,7 @@ import (
|
||||||
"github.com/hashicorp/terraform/httpclient"
|
"github.com/hashicorp/terraform/httpclient"
|
||||||
"github.com/hashicorp/terraform/internal/didyoumean"
|
"github.com/hashicorp/terraform/internal/didyoumean"
|
||||||
"github.com/hashicorp/terraform/internal/logging"
|
"github.com/hashicorp/terraform/internal/logging"
|
||||||
|
"github.com/hashicorp/terraform/internal/terminal"
|
||||||
"github.com/hashicorp/terraform/version"
|
"github.com/hashicorp/terraform/version"
|
||||||
"github.com/mattn/go-shellwords"
|
"github.com/mattn/go-shellwords"
|
||||||
"github.com/mitchellh/cli"
|
"github.com/mitchellh/cli"
|
||||||
|
@ -34,6 +35,12 @@ const (
|
||||||
|
|
||||||
// The parent process will create a file to collect crash logs
|
// The parent process will create a file to collect crash logs
|
||||||
envTmpLogPath = "TF_TEMP_LOG_PATH"
|
envTmpLogPath = "TF_TEMP_LOG_PATH"
|
||||||
|
|
||||||
|
// Environment variable name used for smuggling true stderr terminal
|
||||||
|
// settings into a panicwrap child process. This is an implementation
|
||||||
|
// detail, subject to change in future, and should not ever be directly
|
||||||
|
// set by an end-user.
|
||||||
|
envTerminalPanicwrapWorkaround = "TF_PANICWRAP_STDERR"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ui wraps the primary output cli.Ui, and redirects Warn calls to Output
|
// ui wraps the primary output cli.Ui, and redirects Warn calls to Output
|
||||||
|
@ -75,6 +82,22 @@ func realMain() int {
|
||||||
// store the path in the environment for the wrapped executable
|
// store the path in the environment for the wrapped executable
|
||||||
os.Setenv(envTmpLogPath, logTempFile.Name())
|
os.Setenv(envTmpLogPath, logTempFile.Name())
|
||||||
|
|
||||||
|
// We also need to do our terminal initialization before we fork,
|
||||||
|
// because the child process doesn't necessarily have access to
|
||||||
|
// the true stderr in order to initialize it.
|
||||||
|
streams, err := terminal.Init()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "Failed to initialize terminal: %s", err)
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need the child process to behave _as if_ connected to the real
|
||||||
|
// stderr, even though panicwrap is about to add a pipe in the way,
|
||||||
|
// so we'll smuggle the true stderr information in an environment
|
||||||
|
// varible.
|
||||||
|
streamState := streams.StateForAfterPanicWrap()
|
||||||
|
os.Setenv(envTerminalPanicwrapWorkaround, fmt.Sprintf("%t:%d", streamState.StderrIsTerminal, streamState.StderrWidth))
|
||||||
|
|
||||||
// Create the configuration for panicwrap and wrap our executable
|
// Create the configuration for panicwrap and wrap our executable
|
||||||
wrapConfig.Handler = logging.PanicHandler(logTempFile.Name())
|
wrapConfig.Handler = logging.PanicHandler(logTempFile.Name())
|
||||||
wrapConfig.IgnoreSignals = ignoreSignals
|
wrapConfig.IgnoreSignals = ignoreSignals
|
||||||
|
@ -122,6 +145,39 @@ func wrappedMain() int {
|
||||||
log.Printf("[INFO] Go runtime version: %s", runtime.Version())
|
log.Printf("[INFO] Go runtime version: %s", runtime.Version())
|
||||||
log.Printf("[INFO] CLI args: %#v", os.Args)
|
log.Printf("[INFO] CLI args: %#v", os.Args)
|
||||||
|
|
||||||
|
// This is the recieving end of our workaround to retain the metadata
|
||||||
|
// about the real stderr even though we're talking to it via the panicwrap
|
||||||
|
// pipe. See the call to StateForAfterPanicWrap above for the producer
|
||||||
|
// part of this.
|
||||||
|
var streamState *terminal.PrePanicwrapState
|
||||||
|
if raw := os.Getenv(envTerminalPanicwrapWorkaround); raw != "" {
|
||||||
|
streamState = &terminal.PrePanicwrapState{}
|
||||||
|
if _, err := fmt.Sscanf(raw, "%t:%d", &streamState.StderrIsTerminal, &streamState.StderrWidth); err != nil {
|
||||||
|
log.Printf("[WARN] %s is set but is incorrectly-formatted: %s", envTerminalPanicwrapWorkaround, err)
|
||||||
|
streamState = nil // leave it unset for a normal init, then
|
||||||
|
}
|
||||||
|
}
|
||||||
|
streams, err := terminal.ReinitInsidePanicwrap(streamState)
|
||||||
|
if err != nil {
|
||||||
|
Ui.Error(fmt.Sprintf("Failed to configure the terminal: %s", err))
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if streams.Stdout.IsTerminal() {
|
||||||
|
log.Printf("[TRACE] Stdout is a terminal of width %d", streams.Stdout.Columns())
|
||||||
|
} else {
|
||||||
|
log.Printf("[TRACE] Stdout is not a terminal")
|
||||||
|
}
|
||||||
|
if streams.Stderr.IsTerminal() {
|
||||||
|
log.Printf("[TRACE] Stderr is a terminal of width %d", streams.Stderr.Columns())
|
||||||
|
} else {
|
||||||
|
log.Printf("[TRACE] Stderr is not a terminal")
|
||||||
|
}
|
||||||
|
if streams.Stdin.IsTerminal() {
|
||||||
|
log.Printf("[TRACE] Stdin is a terminal")
|
||||||
|
} else {
|
||||||
|
log.Printf("[TRACE] Stdin is not a terminal")
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: We're intentionally calling LoadConfig _before_ handling a possible
|
// NOTE: We're intentionally calling LoadConfig _before_ handling a possible
|
||||||
// -chdir=... option on the command line, so that a possible relative
|
// -chdir=... option on the command line, so that a possible relative
|
||||||
// path in the TERRAFORM_CONFIG_FILE environment variable (though probably
|
// path in the TERRAFORM_CONFIG_FILE environment variable (though probably
|
||||||
|
@ -235,7 +291,7 @@ func wrappedMain() int {
|
||||||
// in case they need to refer back to it for any special reason, though
|
// in case they need to refer back to it for any special reason, though
|
||||||
// they should primarily be working with the override working directory
|
// they should primarily be working with the override working directory
|
||||||
// that we've now switched to above.
|
// that we've now switched to above.
|
||||||
initCommands(originalWd, config, services, providerSrc, providerDevOverrides, unmanagedProviders)
|
initCommands(originalWd, streams, config, services, providerSrc, providerDevOverrides, unmanagedProviders)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run checkpoint
|
// Run checkpoint
|
||||||
|
|
Loading…
Reference in New Issue