|
- // 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.
-
- // This file enables an external tool to intercept package requests.
- // If the tool is present then its results are used in preference to
- // the go list command.
-
- package packages
-
- import (
- "bytes"
- "encoding/json"
- "fmt"
- "os/exec"
- "strings"
- )
-
- // The Driver Protocol
- //
- // The driver, given the inputs to a call to Load, returns metadata about the packages specified.
- // This allows for different build systems to support go/packages by telling go/packages how the
- // packages' source is organized.
- // The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in
- // the path as gopackagesdriver. It's given the inputs to load in its argv. See the package
- // documentation in doc.go for the full description of the patterns that need to be supported.
- // A driver receives as a JSON-serialized driverRequest struct in standard input and will
- // produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output.
-
- // driverRequest is used to provide the portion of Load's Config that is needed by a driver.
- type driverRequest struct {
- Mode LoadMode `json:"mode"`
- // Env specifies the environment the underlying build system should be run in.
- Env []string `json:"env"`
- // BuildFlags are flags that should be passed to the underlying build system.
- BuildFlags []string `json:"build_flags"`
- // Tests specifies whether the patterns should also return test packages.
- Tests bool `json:"tests"`
- // Overlay maps file paths (relative to the driver's working directory) to the byte contents
- // of overlay files.
- Overlay map[string][]byte `json:"overlay"`
- }
-
- // findExternalDriver returns the file path of a tool that supplies
- // the build system package structure, or "" if not found."
- // If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
- // value, otherwise it searches for a binary named gopackagesdriver on the PATH.
- func findExternalDriver(cfg *Config) driver {
- const toolPrefix = "GOPACKAGESDRIVER="
- tool := ""
- for _, env := range cfg.Env {
- if val := strings.TrimPrefix(env, toolPrefix); val != env {
- tool = val
- }
- }
- if tool != "" && tool == "off" {
- return nil
- }
- if tool == "" {
- var err error
- tool, err = exec.LookPath("gopackagesdriver")
- if err != nil {
- return nil
- }
- }
- return func(cfg *Config, words ...string) (*driverResponse, error) {
- req, err := json.Marshal(driverRequest{
- Mode: cfg.Mode,
- Env: cfg.Env,
- BuildFlags: cfg.BuildFlags,
- Tests: cfg.Tests,
- Overlay: cfg.Overlay,
- })
- if err != nil {
- return nil, fmt.Errorf("failed to encode message to driver tool: %v", err)
- }
-
- buf := new(bytes.Buffer)
- cmd := exec.CommandContext(cfg.Context, tool, words...)
- cmd.Dir = cfg.Dir
- cmd.Env = cfg.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 driverResponse
- if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
- return nil, err
- }
- return &response, nil
- }
- }
|