mirror of
https://github.com/go-gitea/gitea.git
synced 2024-11-01 08:47:40 -04:00
95 lines
3.2 KiB
Go
95 lines
3.2 KiB
Go
|
// 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
|
||
|
}
|
||
|
}
|