gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

external.go (3472B)


      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 }