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