forked from constabulary/gb
/
build.go
160 lines (136 loc) · 4.3 KB
/
build.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package main
import (
"flag"
"go/build"
"os"
"path/filepath"
"runtime"
"github.com/constabulary/gb"
"github.com/constabulary/gb/cmd"
"github.com/pkg/errors"
)
func init() {
registerCommand(buildCmd)
}
var (
// build flags
// should we perform a release build +release tag ?
// defaults to false, +debug.
R bool
// force rebuild of packages
F bool
// skip caching of packages
FF bool
// enable race runtime
race bool
ldflags, gcflags []string
P int // number of executors to run in parallel
dotfile string // path to dot output file
buildtags []string
)
func addBuildFlags(fs *flag.FlagSet) {
// TODO(dfc) this should accept a *gb.Context
fs.BoolVar(&R, "r", false, "perform a release build")
fs.BoolVar(&F, "f", false, "rebuild up-to-date packages")
fs.BoolVar(&FF, "F", false, "do not cache built packages")
fs.BoolVar(&race, "race", false, "enable race detector")
fs.IntVar(&P, "P", runtime.NumCPU(), "number of parallel jobs")
fs.Var((*stringsFlag)(&ldflags), "ldflags", "flags passed to the linker")
fs.Var((*stringsFlag)(&gcflags), "gcflags", "flags passed to the compiler")
fs.StringVar(&dotfile, "dotfile", "", "path to dot output file")
fs.Var((*stringsFlag)(&buildtags), "tags", "")
}
var buildCmd = &cmd.Command{
Name: "build",
Short: "build a package",
UsageLine: "build [build flags] [packages]",
Long: `
Build compiles the packages named by the import paths, along with their
dependencies.
Flags:
-f
ignore cached packages if present, new packages built will overwrite
any cached packages. This effectively disables incremental
compilation.
-F
do not cache packages, cached packages will still be used for
incremental compilation. -f -F is advised to disable the package
caching system.
-P
The number of build jobs to run in parallel, including test execution.
By default this is the number of CPUs visible to gb.
-R
sets the base of the project root search path from the current working
directory to the value supplied. Effectively gb changes working
directory to this path before searching for the project root.
-dotfile
if provided, gb will output a dot formatted file of the build steps to
be performed.
-ldflags 'flag list'
arguments to pass on each linker invocation.
-gcflags 'arg list'
arguments to pass on each compile invocation.
-race
enable data race detection.
Supported only on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64.
-tags 'tag list'
additional build tags.
The list flags accept a space-separated list of strings. To embed spaces in an
element in the list, surround it with either single or double quotes.
For more about where packages and binaries are installed, run 'gb help project'.
`,
Run: func(ctx *gb.Context, args []string) error {
// TODO(dfc) run should take a *gb.Context not a *gb.Project
ctx.Force = F
ctx.Install = !FF
pkgs, err := resolveRootPackages(ctx, args...)
if err != nil {
return err
}
build, err := gb.BuildPackages(pkgs...)
if err != nil {
return err
}
if dotfile != "" {
f, err := os.Create(dotfile)
if err != nil {
return err
}
defer f.Close()
printActions(f, build)
}
startSigHandlers()
return gb.ExecuteConcurrent(build, P, interrupted)
},
AddFlags: addBuildFlags,
}
// Resolver resolves packages.
type Resolver interface {
ResolvePackage(path string) (*gb.Package, error)
}
// resolveRootPackages resolves import paths into packages.
// Only packages which exist inside $PROJECT/src are elegable to be
// roots to build or test. Other import paths are discarded.
func resolveRootPackages(r Resolver, paths ...string) ([]*gb.Package, error) {
var pkgs []*gb.Package
for _, path := range paths {
pkg, err := r.ResolvePackage(path)
if _, nogo := errors.Cause(err).(*build.NoGoError); nogo {
// if the package is empty, to no Go files are in scope
// ignore it.
// TODO(dfc) ResolvePackage should return an empty *Package
// and build/test should ignore them.
continue
}
if err != nil {
return pkgs, errors.Wrapf(err, "failed to resolve import path %q", path)
}
if pkg.SrcRoot == filepath.Join(runtime.GOROOT(), "src") {
// skip package roots that are not part of this project.
// TODO(dfc) should gb return an error here?
continue
}
pkgs = append(pkgs, pkg)
}
return pkgs, nil
}