...

Source file src/golang.org/x/tools/go/packages/external.go

Documentation: golang.org/x/tools/go/packages

     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  	exec "golang.org/x/sys/execabs"
    16  	"os"
    17  	"strings"
    18  )
    19  
    20  // The Driver Protocol
    21  //
    22  // The driver, given the inputs to a call to Load, returns metadata about the packages specified.
    23  // This allows for different build systems to support go/packages by telling go/packages how the
    24  // packages' source is organized.
    25  // The driver is a binary, either specified by the GOPACKAGESDRIVER environment variable or in
    26  // the path as gopackagesdriver. It's given the inputs to load in its argv. See the package
    27  // documentation in doc.go for the full description of the patterns that need to be supported.
    28  // A driver receives as a JSON-serialized driverRequest struct in standard input and will
    29  // produce a JSON-serialized driverResponse (see definition in packages.go) in its standard output.
    30  
    31  // driverRequest is used to provide the portion of Load's Config that is needed by a driver.
    32  type driverRequest struct {
    33  	Mode LoadMode `json:"mode"`
    34  	// Env specifies the environment the underlying build system should be run in.
    35  	Env []string `json:"env"`
    36  	// BuildFlags are flags that should be passed to the underlying build system.
    37  	BuildFlags []string `json:"build_flags"`
    38  	// Tests specifies whether the patterns should also return test packages.
    39  	Tests bool `json:"tests"`
    40  	// Overlay maps file paths (relative to the driver's working directory) to the byte contents
    41  	// of overlay files.
    42  	Overlay map[string][]byte `json:"overlay"`
    43  }
    44  
    45  // findExternalDriver returns the file path of a tool that supplies
    46  // the build system package structure, or "" if not found."
    47  // If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
    48  // value, otherwise it searches for a binary named gopackagesdriver on the PATH.
    49  func findExternalDriver(cfg *Config) driver {
    50  	const toolPrefix = "GOPACKAGESDRIVER="
    51  	tool := ""
    52  	for _, env := range cfg.Env {
    53  		if val := strings.TrimPrefix(env, toolPrefix); val != env {
    54  			tool = val
    55  		}
    56  	}
    57  	if tool != "" && tool == "off" {
    58  		return nil
    59  	}
    60  	if tool == "" {
    61  		var err error
    62  		tool, err = exec.LookPath("gopackagesdriver")
    63  		if err != nil {
    64  			return nil
    65  		}
    66  	}
    67  	return func(cfg *Config, words ...string) (*driverResponse, error) {
    68  		req, err := json.Marshal(driverRequest{
    69  			Mode:       cfg.Mode,
    70  			Env:        cfg.Env,
    71  			BuildFlags: cfg.BuildFlags,
    72  			Tests:      cfg.Tests,
    73  			Overlay:    cfg.Overlay,
    74  		})
    75  		if err != nil {
    76  			return nil, fmt.Errorf("failed to encode message to driver tool: %v", err)
    77  		}
    78  
    79  		buf := new(bytes.Buffer)
    80  		stderr := new(bytes.Buffer)
    81  		cmd := exec.CommandContext(cfg.Context, tool, words...)
    82  		cmd.Dir = cfg.Dir
    83  		cmd.Env = cfg.Env
    84  		cmd.Stdin = bytes.NewReader(req)
    85  		cmd.Stdout = buf
    86  		cmd.Stderr = stderr
    87  
    88  		if err := cmd.Run(); err != nil {
    89  			return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr)
    90  		}
    91  		if len(stderr.Bytes()) != 0 && os.Getenv("GOPACKAGESPRINTDRIVERERRORS") != "" {
    92  			fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd), stderr)
    93  		}
    94  
    95  		var response driverResponse
    96  		if err := json.Unmarshal(buf.Bytes(), &response); err != nil {
    97  			return nil, err
    98  		}
    99  		return &response, nil
   100  	}
   101  }
   102  

View as plain text