1// Copyright 2018 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// This file enables an external tool to intercept package requests.
6// If the tool is present then its results are used in preference to
7// the go list command.
8
9package packages
10
11import (
12	"bytes"
13	"encoding/json"
14	"fmt"
15	"os/exec"
16	"strings"
17)
18
19// findExternalTool returns the file path of a tool that supplies
20// the build system package structure, or "" if not found."
21// If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
22// value, otherwise it searches for a binary named gopackagesdriver on the PATH.
23func findExternalDriver(cfg *Config) driver {
24	const toolPrefix = "GOPACKAGESDRIVER="
25	tool := ""
26	for _, env := range cfg.Env {
27		if val := strings.TrimPrefix(env, toolPrefix); val != env {
28			tool = val
29		}
30	}
31	if tool != "" && tool == "off" {
32		return nil
33	}
34	if tool == "" {
35		var err error
36		tool, err = exec.LookPath("gopackagesdriver")
37		if err != nil {
38			return nil
39		}
40	}
41	return func(cfg *Config, words ...string) (*driverResponse, error) {
42		buf := new(bytes.Buffer)
43		fullargs := []string{
44			"list",
45			fmt.Sprintf("-test=%t", cfg.Tests),
46			fmt.Sprintf("-export=%t", usesExportData(cfg)),
47			fmt.Sprintf("-deps=%t", cfg.Mode >= LoadImports),
48		}
49		for _, f := range cfg.BuildFlags {
50			fullargs = append(fullargs, fmt.Sprintf("-buildflag=%v", f))
51		}
52		fullargs = append(fullargs, "--")
53		fullargs = append(fullargs, words...)
54		cmd := exec.CommandContext(cfg.Context, tool, fullargs...)
55		cmd.Env = cfg.Env
56		cmd.Dir = cfg.Dir
57		cmd.Stdout = buf
58		cmd.Stderr = new(bytes.Buffer)
59		if err := cmd.Run(); err != nil {
60			return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr)
61		}
62		var response driverResponse
63		if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
64			return nil, err
65		}
66		return &response, nil
67	}
68}
69