github.com/rck/u-root@v0.0.0-20180106144920-7eb602e381bb/pkg/golang/build.go (about)

     1  package golang
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"go/build"
     7  	"os"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strings"
    11  )
    12  
    13  type Environ struct {
    14  	build.Context
    15  }
    16  
    17  // Default is the default build environment comprised of the default GOPATH,
    18  // GOROOT, GOOS, GOARCH, and CGO_ENABLED values.
    19  func Default() Environ {
    20  	return Environ{Context: build.Default}
    21  }
    22  
    23  // PackageByPath retrieves information about a package by its file system path.
    24  //
    25  // `path` is assumed to be the directory containing the package.
    26  func (c Environ) PackageByPath(path string) (*build.Package, error) {
    27  	abs, err := filepath.Abs(path)
    28  	if err != nil {
    29  		return nil, err
    30  	}
    31  	return c.Context.ImportDir(abs, 0)
    32  }
    33  
    34  // Package retrieves information about a package by its Go import path.
    35  func (c Environ) Package(importPath string) (*build.Package, error) {
    36  	return c.Context.Import(importPath, "", 0)
    37  }
    38  
    39  // ListPackage matches a subset of the JSON output of the `go list -json`
    40  // command.
    41  //
    42  // See `go help list` for the full structure.
    43  //
    44  // This currently contains an incomplete list of dependencies.
    45  type ListPackage struct {
    46  	Dir        string
    47  	Deps       []string
    48  	GoFiles    []string
    49  	SFiles     []string
    50  	HFiles     []string
    51  	Goroot     bool
    52  	Root       string
    53  	ImportPath string
    54  }
    55  
    56  // Deps lists all dependencies of the package given by `importPath`.
    57  func (c Environ) Deps(importPath string) (*ListPackage, error) {
    58  	// The output of this is almost the same as build.Import, except for
    59  	// the dependencies.
    60  	cmd := exec.Command("go", "list", "-json", importPath)
    61  	env := os.Environ()
    62  	env = append(env, c.Env()...)
    63  	cmd.Env = env
    64  	out, err := cmd.CombinedOutput()
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	var p ListPackage
    70  	if err := json.Unmarshal(out, &p); err != nil {
    71  		return nil, err
    72  	}
    73  	return &p, nil
    74  }
    75  
    76  func (c Environ) Env() []string {
    77  	var env []string
    78  	if c.GOARCH != "" {
    79  		env = append(env, fmt.Sprintf("GOARCH=%s", c.GOARCH))
    80  	}
    81  	if c.GOOS != "" {
    82  		env = append(env, fmt.Sprintf("GOOS=%s", c.GOOS))
    83  	}
    84  	if c.GOROOT != "" {
    85  		env = append(env, fmt.Sprintf("GOROOT=%s", c.GOROOT))
    86  	}
    87  	if c.GOPATH != "" {
    88  		env = append(env, fmt.Sprintf("GOPATH=%s", c.GOPATH))
    89  	}
    90  	var cgo int8
    91  	if c.CgoEnabled {
    92  		cgo = 1
    93  	}
    94  	env = append(env, fmt.Sprintf("CGO_ENABLED=%d", cgo))
    95  	return env
    96  }
    97  
    98  func (c Environ) String() string {
    99  	return strings.Join(c.Env(), " ")
   100  }
   101  
   102  // Optional arguments to Environ.Build.
   103  type BuildOpts struct {
   104  	// ExtraArgs to `go build`.
   105  	ExtraArgs []string
   106  }
   107  
   108  // Build compiles the package given by `importPath`, writing the build object
   109  // to `binaryPath`.
   110  func (c Environ) Build(importPath string, binaryPath string, opts BuildOpts) error {
   111  	p, err := c.Package(importPath)
   112  	if err != nil {
   113  		return err
   114  	}
   115  
   116  	args := []string{
   117  		"build",
   118  		"-a", // Force rebuilding of packages.
   119  		"-o", binaryPath,
   120  		"-installsuffix", "uroot",
   121  		"-ldflags", "-s -w", // Strip all symbols.
   122  	}
   123  	if opts.ExtraArgs != nil {
   124  		args = append(args, opts.ExtraArgs...)
   125  	}
   126  	// We always set the working directory, so this is always '.'.
   127  	args = append(args, ".")
   128  
   129  	cmd := exec.Command("go", args...)
   130  	cmd.Dir = p.Dir
   131  	cmd.Env = append(os.Environ(), c.Env()...)
   132  
   133  	if o, err := cmd.CombinedOutput(); err != nil {
   134  		return fmt.Errorf("error building go package %v: %v, %v", importPath, string(o), err)
   135  	}
   136  	return nil
   137  }