gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/golang.org/x/tools/go/packages/external.go (about)

     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  
     9  package packages
    10  
    11  import (
    12  	"bytes"
    13  	"encoding/json"
    14  	"fmt"
    15  	"os/exec"
    16  	"strings"
    17  )
    18  
    19  // Driver
    20  type driverRequest struct {
    21  	Command    string            `json "command"`
    22  	Mode       LoadMode          `json:"mode"`
    23  	Env        []string          `json:"env"`
    24  	BuildFlags []string          `json:"build_flags"`
    25  	Tests      bool              `json:"tests"`
    26  	Overlay    map[string][]byte `json:"overlay"`
    27  }
    28  
    29  // findExternalDriver returns the file path of a tool that supplies
    30  // the build system package structure, or "" if not found."
    31  // If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
    32  // value, otherwise it searches for a binary named gopackagesdriver on the PATH.
    33  func findExternalDriver(cfg *Config) driver {
    34  	const toolPrefix = "GOPACKAGESDRIVER="
    35  	tool := ""
    36  	for _, env := range cfg.Env {
    37  		if val := strings.TrimPrefix(env, toolPrefix); val != env {
    38  			tool = val
    39  		}
    40  	}
    41  	if tool != "" && tool == "off" {
    42  		return nil
    43  	}
    44  	if tool == "" {
    45  		var err error
    46  		tool, err = exec.LookPath("gopackagesdriver")
    47  		if err != nil {
    48  			return nil
    49  		}
    50  	}
    51  	return func(cfg *Config, words ...string) (*driverResponse, error) {
    52  		req, err := json.Marshal(driverRequest{
    53  			Mode:       cfg.Mode,
    54  			Env:        cfg.Env,
    55  			BuildFlags: cfg.BuildFlags,
    56  			Tests:      cfg.Tests,
    57  			Overlay:    cfg.Overlay,
    58  		})
    59  		if err != nil {
    60  			return nil, fmt.Errorf("failed to encode message to driver tool: %v", err)
    61  		}
    62  
    63  		buf := new(bytes.Buffer)
    64  		cmd := exec.CommandContext(cfg.Context, tool, words...)
    65  		cmd.Dir = cfg.Dir
    66  		cmd.Env = cfg.Env
    67  		cmd.Stdin = bytes.NewReader(req)
    68  		cmd.Stdout = buf
    69  		cmd.Stderr = new(bytes.Buffer)
    70  		if err := cmd.Run(); err != nil {
    71  			return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr)
    72  		}
    73  		var response driverResponse
    74  		if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
    75  			return nil, err
    76  		}
    77  		return &response, nil
    78  	}
    79  }