summaryrefslogtreecommitdiff
path: root/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go')
-rw-r--r--vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go117
1 files changed, 117 insertions, 0 deletions
diff --git a/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
new file mode 100644
index 0000000..dc6177c
--- /dev/null
+++ b/vendor/golang.org/x/tools/go/internal/packagesdriver/sizes.go
@@ -0,0 +1,117 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package packagesdriver fetches type sizes for go/packages and go/analysis.
+package packagesdriver
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "go/types"
+ "os/exec"
+ "strings"
+
+ "golang.org/x/tools/internal/gocommand"
+)
+
+var debug = false
+
+func GetSizes(ctx context.Context, buildFlags, env []string, gocmdRunner *gocommand.Runner, dir string) (types.Sizes, error) {
+ // TODO(matloob): Clean this up. This code is mostly a copy of packages.findExternalDriver.
+ const toolPrefix = "GOPACKAGESDRIVER="
+ tool := ""
+ for _, env := range env {
+ if val := strings.TrimPrefix(env, toolPrefix); val != env {
+ tool = val
+ }
+ }
+
+ if tool == "" {
+ var err error
+ tool, err = exec.LookPath("gopackagesdriver")
+ if err != nil {
+ // We did not find the driver, so use "go list".
+ tool = "off"
+ }
+ }
+
+ if tool == "off" {
+ return GetSizesGolist(ctx, buildFlags, env, gocmdRunner, dir)
+ }
+
+ req, err := json.Marshal(struct {
+ Command string `json:"command"`
+ Env []string `json:"env"`
+ BuildFlags []string `json:"build_flags"`
+ }{
+ Command: "sizes",
+ Env: env,
+ BuildFlags: buildFlags,
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to encode message to driver tool: %v", err)
+ }
+
+ buf := new(bytes.Buffer)
+ cmd := exec.CommandContext(ctx, tool)
+ cmd.Dir = dir
+ cmd.Env = env
+ cmd.Stdin = bytes.NewReader(req)
+ cmd.Stdout = buf
+ cmd.Stderr = new(bytes.Buffer)
+ if err := cmd.Run(); err != nil {
+ return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr)
+ }
+ var response struct {
+ // Sizes, if not nil, is the types.Sizes to use when type checking.
+ Sizes *types.StdSizes
+ }
+ if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
+ return nil, err
+ }
+ return response.Sizes, nil
+}
+
+func GetSizesGolist(ctx context.Context, buildFlags, env []string, gocmdRunner *gocommand.Runner, dir string) (types.Sizes, error) {
+ inv := gocommand.Invocation{
+ Verb: "list",
+ Args: []string{"-f", "{{context.GOARCH}} {{context.Compiler}}", "--", "unsafe"},
+ Env: env,
+ BuildFlags: buildFlags,
+ WorkingDir: dir,
+ }
+ stdout, stderr, friendlyErr, rawErr := gocmdRunner.RunRaw(ctx, inv)
+ var goarch, compiler string
+ if rawErr != nil {
+ if strings.Contains(rawErr.Error(), "cannot find main module") {
+ // User's running outside of a module. All bets are off. Get GOARCH and guess compiler is gc.
+ // TODO(matloob): Is this a problem in practice?
+ inv := gocommand.Invocation{
+ Verb: "env",
+ Args: []string{"GOARCH"},
+ Env: env,
+ WorkingDir: dir,
+ }
+ envout, enverr := gocmdRunner.Run(ctx, inv)
+ if enverr != nil {
+ return nil, enverr
+ }
+ goarch = strings.TrimSpace(envout.String())
+ compiler = "gc"
+ } else {
+ return nil, friendlyErr
+ }
+ } else {
+ fields := strings.Fields(stdout.String())
+ if len(fields) < 2 {
+ return nil, fmt.Errorf("could not parse GOARCH and Go compiler in format \"<GOARCH> <compiler>\":\nstdout: <<%s>>\nstderr: <<%s>>",
+ stdout.String(), stderr.String())
+ }
+ goarch = fields[0]
+ compiler = fields[1]
+ }
+ return types.SizesFor(compiler, goarch), nil
+}