@ -3,7 +3,6 @@ package main
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"net"
@ -11,7 +10,6 @@ import (
"path/filepath"
"runtime"
"strings"
"sync"
"github.com/hashicorp/go-plugin"
"github.com/hashicorp/terraform-svchost/disco"
@ -21,12 +19,10 @@ import (
"github.com/hashicorp/terraform/httpclient"
"github.com/hashicorp/terraform/internal/logging"
"github.com/hashicorp/terraform/version"
"github.com/mattn/go-colorable"
"github.com/mattn/go-shellwords"
"github.com/mitchellh/cli"
"github.com/mitchellh/colorstring"
"github.com/mitchellh/panicwrap"
"github.com/mitchellh/prefixedio"
backendInit "github.com/hashicorp/terraform/backend/init"
)
@ -59,15 +55,8 @@ func realMain() int {
defer os . Remove ( logTempFile . Name ( ) )
defer logTempFile . Close ( )
// Setup the prefixed readers that send data properly to
// stdout/stderr.
doneCh := make ( chan struct { } )
outR , outW := io . Pipe ( )
go copyOutput ( outR , doneCh )
// Create the configuration for panicwrap and wrap our executable
wrapConfig . Handler = logging . PanicHandler ( logTempFile )
wrapConfig . Stdout = outW
wrapConfig . IgnoreSignals = ignoreSignals
wrapConfig . ForwardSignals = forwardSignals
exitStatus , err := panicwrap . Wrap ( & wrapConfig )
@ -76,20 +65,7 @@ func realMain() int {
return 1
}
// If >= 0, we're the parent, so just exit
if exitStatus >= 0 {
// Close the stdout writer so that our copy process can finish
outW . Close ( )
// Wait for the output copying to finish
<- doneCh
return exitStatus
}
// We're the child, so just close the tempfile we made in order to
// save file handles since the tempfile is only used by the parent.
logTempFile . Close ( )
return exitStatus
}
// Call the real main
@ -97,15 +73,10 @@ func realMain() int {
}
func init ( ) {
Ui = & cli . PrefixedUi {
AskPrefix : OutputPrefix ,
OutputPrefix : OutputPrefix ,
InfoPrefix : OutputPrefix ,
ErrorPrefix : ErrorPrefix ,
Ui : & cli . BasicUi {
Writer : os . Stdout ,
Reader : os . Stdin ,
} ,
Ui = & cli . BasicUi {
Writer : os . Stdout ,
ErrorWriter : os . Stderr ,
Reader : os . Stdin ,
}
}
@ -299,65 +270,6 @@ func wrappedMain() int {
return exitCode
}
// copyOutput uses output prefixes to determine whether data on stdout
// should go to stdout or stderr. This is due to panicwrap using stderr
// as the log and error channel.
func copyOutput ( r io . Reader , doneCh chan <- struct { } ) {
defer close ( doneCh )
pr , err := prefixedio . NewReader ( r )
if err != nil {
panic ( err )
}
stderrR , err := pr . Prefix ( ErrorPrefix )
if err != nil {
panic ( err )
}
stdoutR , err := pr . Prefix ( OutputPrefix )
if err != nil {
panic ( err )
}
defaultR , err := pr . Prefix ( "" )
if err != nil {
panic ( err )
}
var stdout io . Writer = os . Stdout
var stderr io . Writer = os . Stderr
if runtime . GOOS == "windows" {
stdout = colorable . NewColorableStdout ( )
stderr = colorable . NewColorableStderr ( )
// colorable is not concurrency-safe when stdout and stderr are the
// same console, so we need to add some synchronization to ensure that
// we can't be concurrently writing to both stderr and stdout at
// once, or else we get intermingled writes that create gibberish
// in the console.
wrapped := synchronizedWriters ( stdout , stderr )
stdout = wrapped [ 0 ]
stderr = wrapped [ 1 ]
}
var wg sync . WaitGroup
wg . Add ( 3 )
go func ( ) {
defer wg . Done ( )
io . Copy ( stderr , stderrR )
} ( )
go func ( ) {
defer wg . Done ( )
io . Copy ( stdout , stdoutR )
} ( )
go func ( ) {
defer wg . Done ( )
io . Copy ( stdout , defaultR )
} ( )
wg . Wait ( )
}
func mergeEnvArgs ( envName string , cmd string , args [ ] string ) ( [ ] string , error ) {
v := os . Getenv ( envName )
if v == "" {