@@ -11,11 +11,10 @@ import (
11
11
"encoding/json"
12
12
"fmt"
13
13
"go/types"
14
- "log"
15
- "os"
16
14
"os/exec"
17
15
"strings"
18
- "time"
16
+
17
+ "golang.org/x/tools/internal/gocommand"
19
18
)
20
19
21
20
var debug = false
@@ -78,97 +77,42 @@ func GetSizes(ctx context.Context, buildFlags, env []string, dir string, usesExp
78
77
}
79
78
80
79
func GetSizesGolist (ctx context.Context , buildFlags , env []string , dir string , usesExportData bool ) (types.Sizes , error ) {
81
- args := []string {"list" , "-f" , "{{context.GOARCH}} {{context.Compiler}}" }
82
- args = append (args , buildFlags ... )
83
- args = append (args , "--" , "unsafe" )
84
- stdout , stderr , err := invokeGo (ctx , env , dir , usesExportData , args ... )
80
+ inv := gocommand.Invocation {
81
+ Verb : "list" ,
82
+ Args : []string {"-f" , "{{context.GOARCH}} {{context.Compiler}}" , "--" , "unsafe" },
83
+ Env : env ,
84
+ BuildFlags : buildFlags ,
85
+ WorkingDir : dir ,
86
+ }
87
+ stdout , stderr , friendlyErr , rawErr := inv .RunRaw (ctx )
85
88
var goarch , compiler string
86
- if err != nil {
87
- if strings .Contains (err .Error (), "cannot find main module" ) {
89
+ if rawErr != nil {
90
+ if strings .Contains (rawErr .Error (), "cannot find main module" ) {
88
91
// User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc.
89
92
// TODO(matloob): Is this a problem in practice?
90
- envout , _ , enverr := invokeGo (ctx , env , dir , usesExportData , "env" , "GOARCH" )
93
+ inv := gocommand.Invocation {
94
+ Verb : "env" ,
95
+ Args : []string {"GOARCH" },
96
+ Env : env ,
97
+ WorkingDir : dir ,
98
+ }
99
+ envout , enverr := inv .Run (ctx )
91
100
if enverr != nil {
92
- return nil , err
101
+ return nil , enverr
93
102
}
94
103
goarch = strings .TrimSpace (envout .String ())
95
104
compiler = "gc"
96
105
} else {
97
- return nil , err
106
+ return nil , friendlyErr
98
107
}
99
108
} else {
100
109
fields := strings .Fields (stdout .String ())
101
110
if len (fields ) < 2 {
102
- return nil , fmt .Errorf ("could not parse GOARCH and Go compiler in format \" <GOARCH> <compiler>\" from stdout of go command: \n %s \n dir: %s \n stdout: <<%s>>\n stderr: <<%s>>" ,
103
- cmdDebugStr ( env , args ... ), dir , stdout .String (), stderr .String ())
111
+ return nil , fmt .Errorf ("could not parse GOARCH and Go compiler in format \" <GOARCH> <compiler>\" : \n stdout: <<%s>>\n stderr: <<%s>>" ,
112
+ stdout .String (), stderr .String ())
104
113
}
105
114
goarch = fields [0 ]
106
115
compiler = fields [1 ]
107
116
}
108
117
return types .SizesFor (compiler , goarch ), nil
109
118
}
110
-
111
- // invokeGo returns the stdout and stderr of a go command invocation.
112
- func invokeGo (ctx context.Context , env []string , dir string , usesExportData bool , args ... string ) (* bytes.Buffer , * bytes.Buffer , error ) {
113
- if debug {
114
- defer func (start time.Time ) { log .Printf ("%s for %v" , time .Since (start ), cmdDebugStr (env , args ... )) }(time .Now ())
115
- }
116
- stdout := new (bytes.Buffer )
117
- stderr := new (bytes.Buffer )
118
- cmd := exec .CommandContext (ctx , "go" , args ... )
119
- // On darwin the cwd gets resolved to the real path, which breaks anything that
120
- // expects the working directory to keep the original path, including the
121
- // go command when dealing with modules.
122
- // The Go stdlib has a special feature where if the cwd and the PWD are the
123
- // same node then it trusts the PWD, so by setting it in the env for the child
124
- // process we fix up all the paths returned by the go command.
125
- cmd .Env = append (append ([]string {}, env ... ), "PWD=" + dir )
126
- cmd .Dir = dir
127
- cmd .Stdout = stdout
128
- cmd .Stderr = stderr
129
- if err := cmd .Run (); err != nil {
130
- exitErr , ok := err .(* exec.ExitError )
131
- if ! ok {
132
- // Catastrophic error:
133
- // - executable not found
134
- // - context cancellation
135
- return nil , nil , fmt .Errorf ("couldn't exec 'go %v': %s %T" , args , err , err )
136
- }
137
-
138
- // Export mode entails a build.
139
- // If that build fails, errors appear on stderr
140
- // (despite the -e flag) and the Export field is blank.
141
- // Do not fail in that case.
142
- if ! usesExportData {
143
- return nil , nil , fmt .Errorf ("go %v: %s: %s" , args , exitErr , stderr )
144
- }
145
- }
146
-
147
- // As of writing, go list -export prints some non-fatal compilation
148
- // errors to stderr, even with -e set. We would prefer that it put
149
- // them in the Package.Error JSON (see https://golang.org/issue/26319).
150
- // In the meantime, there's nowhere good to put them, but they can
151
- // be useful for debugging. Print them if $GOPACKAGESPRINTGOLISTERRORS
152
- // is set.
153
- if len (stderr .Bytes ()) != 0 && os .Getenv ("GOPACKAGESPRINTGOLISTERRORS" ) != "" {
154
- fmt .Fprintf (os .Stderr , "%s stderr: <<%s>>\n " , cmdDebugStr (env , args ... ), stderr )
155
- }
156
-
157
- // debugging
158
- if false {
159
- fmt .Fprintf (os .Stderr , "%s stdout: <<%s>>\n " , cmdDebugStr (env , args ... ), stdout )
160
- }
161
-
162
- return stdout , stderr , nil
163
- }
164
-
165
- func cmdDebugStr (envlist []string , args ... string ) string {
166
- env := make (map [string ]string )
167
- for _ , kv := range envlist {
168
- split := strings .Split (kv , "=" )
169
- k , v := split [0 ], split [1 ]
170
- env [k ] = v
171
- }
172
-
173
- return fmt .Sprintf ("GOROOT=%v GOPATH=%v GO111MODULE=%v PWD=%v go %v" , env ["GOROOT" ], env ["GOPATH" ], env ["GO111MODULE" ], env ["PWD" ], args )
174
- }
0 commit comments