Skip to content

Commit d913e46

Browse files
authored
Chore: move build command to importable package (#38726)
* move build command to importable package & clean up
1 parent 68c7d05 commit d913e46

File tree

8 files changed

+602
-464
lines changed

8 files changed

+602
-464
lines changed

build.go

+2-464
Large diffs are not rendered by default.

pkg/build/cmd.go

+314
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,314 @@
1+
package build
2+
3+
import (
4+
"bytes"
5+
"flag"
6+
"fmt"
7+
"go/build"
8+
"io/ioutil"
9+
"log"
10+
"os"
11+
"path"
12+
"path/filepath"
13+
"strconv"
14+
"strings"
15+
"time"
16+
)
17+
18+
const (
19+
GoOSWindows = "windows"
20+
GoOSLinux = "linux"
21+
22+
ServerBinary = "grafana-server"
23+
CLIBinary = "grafana-cli"
24+
)
25+
26+
var binaries = []string{ServerBinary, CLIBinary}
27+
28+
func logError(message string, err error) int {
29+
log.Println(message, err)
30+
31+
return 1
32+
}
33+
34+
// RunCmd runs the build command and returns the exit code
35+
func RunCmd() int {
36+
opts := BuildOptsFromFlags()
37+
38+
wd, err := os.Getwd()
39+
if err != nil {
40+
return logError("Error getting working directory", err)
41+
}
42+
43+
packageJSON, err := OpenPackageJSON(wd)
44+
if err != nil {
45+
return logError("Error opening package json", err)
46+
}
47+
48+
version, iteration := LinuxPackageVersion(packageJSON.Version, opts.buildID)
49+
50+
if opts.printGenVersion {
51+
fmt.Print(genPackageVersion(version, iteration))
52+
return 0
53+
}
54+
55+
log.Printf("Version: %s, Linux Version: %s, Package Iteration: %s\n", version, version, iteration)
56+
57+
if flag.NArg() == 0 {
58+
log.Println("Usage: go run build.go build")
59+
return 1
60+
}
61+
62+
for _, cmd := range flag.Args() {
63+
switch cmd {
64+
case "setup":
65+
setup(opts.goos)
66+
67+
case "build-srv", "build-server":
68+
if !opts.isDev {
69+
clean(opts)
70+
}
71+
72+
if err := doBuild("grafana-server", "./pkg/cmd/grafana-server", opts); err != nil {
73+
log.Println(err)
74+
return 1
75+
}
76+
77+
case "build-cli":
78+
clean(opts)
79+
if err := doBuild("grafana-cli", "./pkg/cmd/grafana-cli", opts); err != nil {
80+
log.Println(err)
81+
return 1
82+
}
83+
84+
case "build":
85+
//clean()
86+
for _, binary := range binaries {
87+
log.Println("building binaries", cmd)
88+
// Can't use filepath.Join here because filepath.Join calls filepath.Clean, which removes the `./` from this path, which upsets `go build`
89+
if err := doBuild(binary, fmt.Sprintf("./pkg/cmd/%s", binary), opts); err != nil {
90+
log.Println(err)
91+
return 1
92+
}
93+
}
94+
95+
case "build-frontend":
96+
yarn("build")
97+
98+
case "sha-dist":
99+
if err := shaDir("dist"); err != nil {
100+
return logError("error packaging dist directory", err)
101+
}
102+
103+
case "latest":
104+
makeLatestDistCopies()
105+
106+
case "clean":
107+
clean(opts)
108+
109+
default:
110+
log.Println("Unknown command", cmd)
111+
return 1
112+
}
113+
}
114+
115+
return 0
116+
}
117+
118+
func makeLatestDistCopies() {
119+
files, err := ioutil.ReadDir("dist")
120+
if err != nil {
121+
log.Fatalf("failed to create latest copies. Cannot read from /dist")
122+
}
123+
124+
latestMapping := map[string]string{
125+
"_amd64.deb": "dist/grafana_latest_amd64.deb",
126+
".x86_64.rpm": "dist/grafana-latest-1.x86_64.rpm",
127+
".linux-amd64.tar.gz": "dist/grafana-latest.linux-x64.tar.gz",
128+
".linux-amd64-musl.tar.gz": "dist/grafana-latest.linux-x64-musl.tar.gz",
129+
".linux-armv7.tar.gz": "dist/grafana-latest.linux-armv7.tar.gz",
130+
".linux-armv7-musl.tar.gz": "dist/grafana-latest.linux-armv7-musl.tar.gz",
131+
".linux-armv6.tar.gz": "dist/grafana-latest.linux-armv6.tar.gz",
132+
".linux-arm64.tar.gz": "dist/grafana-latest.linux-arm64.tar.gz",
133+
".linux-arm64-musl.tar.gz": "dist/grafana-latest.linux-arm64-musl.tar.gz",
134+
}
135+
136+
for _, file := range files {
137+
for extension, fullName := range latestMapping {
138+
if strings.HasSuffix(file.Name(), extension) {
139+
if _, err := runError("cp", path.Join("dist", file.Name()), fullName); err != nil {
140+
log.Println("error running cp command:", err)
141+
}
142+
}
143+
}
144+
}
145+
}
146+
147+
func yarn(params ...string) {
148+
runPrint(`yarn run`, params...)
149+
}
150+
151+
func genPackageVersion(version string, iteration string) string {
152+
if iteration != "" {
153+
return fmt.Sprintf("%v-%v", version, iteration)
154+
} else {
155+
return version
156+
}
157+
}
158+
159+
func setup(goos string) {
160+
args := []string{"install", "-v"}
161+
if goos == GoOSWindows {
162+
args = append(args, "-buildmode=exe")
163+
}
164+
args = append(args, "./pkg/cmd/grafana-server")
165+
runPrint("go", args...)
166+
}
167+
168+
func doBuild(binaryName, pkg string, opts BuildOpts) error {
169+
log.Println("building", binaryName, pkg)
170+
libcPart := ""
171+
if opts.libc != "" {
172+
libcPart = fmt.Sprintf("-%s", opts.libc)
173+
}
174+
binary := fmt.Sprintf("./bin/%s", binaryName)
175+
176+
//don't include os/arch/libc in output path in dev environment
177+
if !opts.isDev {
178+
binary = fmt.Sprintf("./bin/%s-%s%s/%s", opts.goos, opts.goarch, libcPart, binaryName)
179+
}
180+
181+
if opts.goos == GoOSWindows {
182+
binary += ".exe"
183+
}
184+
185+
if !opts.isDev {
186+
rmr(binary, binary+".md5")
187+
}
188+
189+
lf, err := ldflags(opts)
190+
if err != nil {
191+
return err
192+
}
193+
194+
args := []string{"build", "-ldflags", lf}
195+
196+
if opts.goos == GoOSWindows {
197+
// Work around a linking error on Windows: "export ordinal too large"
198+
args = append(args, "-buildmode=exe")
199+
}
200+
201+
if len(opts.buildTags) > 0 {
202+
args = append(args, "-tags", strings.Join(opts.buildTags, ","))
203+
}
204+
205+
if opts.race {
206+
args = append(args, "-race")
207+
}
208+
209+
args = append(args, "-o", binary)
210+
args = append(args, pkg)
211+
212+
runPrint("go", args...)
213+
214+
if opts.isDev {
215+
return nil
216+
}
217+
218+
if err := setBuildEnv(opts); err != nil {
219+
return err
220+
}
221+
runPrint("go", "version")
222+
libcPart = ""
223+
if opts.libc != "" {
224+
libcPart = fmt.Sprintf("/%s", opts.libc)
225+
}
226+
fmt.Printf("Targeting %s/%s%s\n", opts.goos, opts.goarch, libcPart)
227+
228+
// Create an md5 checksum of the binary, to be included in the archive for
229+
// automatic upgrades.
230+
return md5File(binary)
231+
}
232+
233+
func ldflags(opts BuildOpts) (string, error) {
234+
buildStamp, err := buildStamp()
235+
if err != nil {
236+
return "", err
237+
}
238+
239+
var b bytes.Buffer
240+
b.WriteString("-w")
241+
b.WriteString(fmt.Sprintf(" -X main.version=%s", opts.version))
242+
b.WriteString(fmt.Sprintf(" -X main.commit=%s", getGitSha()))
243+
b.WriteString(fmt.Sprintf(" -X main.buildstamp=%d", buildStamp))
244+
b.WriteString(fmt.Sprintf(" -X main.buildBranch=%s", getGitBranch()))
245+
if v := os.Getenv("LDFLAGS"); v != "" {
246+
b.WriteString(fmt.Sprintf(" -extldflags \"%s\"", v))
247+
}
248+
249+
return b.String(), nil
250+
}
251+
252+
func setBuildEnv(opts BuildOpts) error {
253+
if err := os.Setenv("GOOS", opts.goos); err != nil {
254+
return err
255+
}
256+
257+
if opts.goos == GoOSWindows {
258+
// require windows >=7
259+
if err := os.Setenv("CGO_CFLAGS", "-D_WIN32_WINNT=0x0601"); err != nil {
260+
return err
261+
}
262+
}
263+
264+
if opts.goarch != "amd64" || opts.goos != GoOSLinux {
265+
// needed for all other archs
266+
opts.cgo = true
267+
}
268+
269+
if strings.HasPrefix(opts.goarch, "armv") {
270+
if err := os.Setenv("GOARCH", "arm"); err != nil {
271+
return err
272+
}
273+
274+
if err := os.Setenv("GOARM", opts.goarch[4:]); err != nil {
275+
return err
276+
}
277+
} else {
278+
if err := os.Setenv("GOARCH", opts.goarch); err != nil {
279+
return err
280+
}
281+
}
282+
283+
if opts.cgo {
284+
if err := os.Setenv("CGO_ENABLED", "1"); err != nil {
285+
return err
286+
}
287+
}
288+
289+
if opts.gocc == "" {
290+
return nil
291+
}
292+
293+
return os.Setenv("CC", opts.gocc)
294+
}
295+
296+
func buildStamp() (int64, error) {
297+
// use SOURCE_DATE_EPOCH if set.
298+
if v, ok := os.LookupEnv("SOURCE_DATE_EPOCH"); ok {
299+
return strconv.ParseInt(v, 10, 64)
300+
}
301+
302+
bs, err := runError("git", "show", "-s", "--format=%ct")
303+
if err != nil {
304+
return time.Now().Unix(), nil
305+
}
306+
307+
return strconv.ParseInt(string(bs), 10, 64)
308+
}
309+
310+
func clean(opts BuildOpts) {
311+
rmr("dist")
312+
rmr("tmp")
313+
rmr(filepath.Join(build.Default.GOPATH, fmt.Sprintf("pkg/%s_%s/github.com/grafana", opts.goos, opts.goarch)))
314+
}

pkg/build/docs.go

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Package build contains the command / functions for the Grafana build process used when running the "build" target in the makefile
2+
package build

pkg/build/exec.go

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package build
2+
3+
import (
4+
"bytes"
5+
"log"
6+
"os"
7+
"os/exec"
8+
"strings"
9+
)
10+
11+
func runError(cmd string, args ...string) ([]byte, error) {
12+
// Can ignore gosec G204 because this function is not used in Grafana, only in the build process.
13+
//nolint:gosec
14+
ecmd := exec.Command(cmd, args...)
15+
bs, err := ecmd.CombinedOutput()
16+
if err != nil {
17+
return nil, err
18+
}
19+
20+
return bytes.TrimSpace(bs), nil
21+
}
22+
23+
func runPrint(cmd string, args ...string) {
24+
log.Println(cmd, strings.Join(args, " "))
25+
// Can ignore gosec G204 because this function is not used in Grafana, only in the build process.
26+
//nolint:gosec
27+
ecmd := exec.Command(cmd, args...)
28+
ecmd.Stdout = os.Stdout
29+
ecmd.Stderr = os.Stderr
30+
err := ecmd.Run()
31+
if err != nil {
32+
log.Fatal(err)
33+
}
34+
}

0 commit comments

Comments
 (0)