podman
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
5package packages6
7// This file defines the protocol that enables an external "driver"
8// tool to supply package metadata in place of 'go list'.
9
10import (11"bytes"12"encoding/json"13"fmt"14"os"15"os/exec"16"strings"17)
18
19// DriverRequest defines the schema of a request for package metadata
20// from an external driver program. The JSON-encoded DriverRequest
21// message is provided to the driver program's standard input. The
22// query patterns are provided as command-line arguments.
23//
24// See the package documentation for an overview.
25type DriverRequest struct {26Mode LoadMode `json:"mode"`27
28// Env specifies the environment the underlying build system should be run in.29Env []string `json:"env"`30
31// BuildFlags are flags that should be passed to the underlying build system.32BuildFlags []string `json:"build_flags"`33
34// Tests specifies whether the patterns should also return test packages.35Tests bool `json:"tests"`36
37// Overlay maps file paths (relative to the driver's working directory) to the byte contents38// of overlay files.39Overlay map[string][]byte `json:"overlay"`40}
41
42// DriverResponse defines the schema of a response from an external
43// driver program, providing the results of a query for package
44// metadata. The driver program must write a JSON-encoded
45// DriverResponse message to its standard output.
46//
47// See the package documentation for an overview.
48type DriverResponse struct {49// NotHandled is returned if the request can't be handled by the current50// driver. If an external driver returns a response with NotHandled, the51// rest of the DriverResponse is ignored, and go/packages will fallback52// to the next driver. If go/packages is extended in the future to support53// lists of multiple drivers, go/packages will fall back to the next driver.54NotHandled bool55
56// Compiler and Arch are the arguments pass of types.SizesFor57// to get a types.Sizes to use when type checking.58Compiler string59Arch string60
61// Roots is the set of package IDs that make up the root packages.62// We have to encode this separately because when we encode a single package63// we cannot know if it is one of the roots as that requires knowledge of the64// graph it is part of.65Roots []string `json:",omitempty"`66
67// Packages is the full set of packages in the graph.68// The packages are not connected into a graph.69// The Imports if populated will be stubs that only have their ID set.70// Imports will be connected and then type and syntax information added in a71// later pass (see refine).72Packages []*Package73
74// GoVersion is the minor version number used by the driver75// (e.g. the go command on the PATH) when selecting .go files.76// Zero means unknown.77GoVersion int78}
79
80// driver is the type for functions that query the build system for the
81// packages named by the patterns.
82type driver func(cfg *Config, patterns ...string) (*DriverResponse, error)83
84// findExternalDriver returns the file path of a tool that supplies
85// the build system package structure, or "" if not found."
86// If GOPACKAGESDRIVER is set in the environment findExternalTool returns its
87// value, otherwise it searches for a binary named gopackagesdriver on the PATH.
88func findExternalDriver(cfg *Config) driver {89const toolPrefix = "GOPACKAGESDRIVER="90tool := ""91for _, env := range cfg.Env {92if val := strings.TrimPrefix(env, toolPrefix); val != env {93tool = val94}95}96if tool != "" && tool == "off" {97return nil98}99if tool == "" {100var err error101tool, err = exec.LookPath("gopackagesdriver")102if err != nil {103return nil104}105}106return func(cfg *Config, words ...string) (*DriverResponse, error) {107req, err := json.Marshal(DriverRequest{108Mode: cfg.Mode,109Env: cfg.Env,110BuildFlags: cfg.BuildFlags,111Tests: cfg.Tests,112Overlay: cfg.Overlay,113})114if err != nil {115return nil, fmt.Errorf("failed to encode message to driver tool: %v", err)116}117
118buf := new(bytes.Buffer)119stderr := new(bytes.Buffer)120cmd := exec.CommandContext(cfg.Context, tool, words...)121cmd.Dir = cfg.Dir122cmd.Env = cfg.Env123cmd.Stdin = bytes.NewReader(req)124cmd.Stdout = buf125cmd.Stderr = stderr126
127if err := cmd.Run(); err != nil {128return nil, fmt.Errorf("%v: %v: %s", tool, err, cmd.Stderr)129}130if len(stderr.Bytes()) != 0 && os.Getenv("GOPACKAGESPRINTDRIVERERRORS") != "" {131fmt.Fprintf(os.Stderr, "%s stderr: <<%s>>\n", cmdDebugStr(cmd), stderr)132}133
134var response DriverResponse135if err := json.Unmarshal(buf.Bytes(), &response); err != nil {136return nil, err137}138return &response, nil139}140}
141