blob: 7b624c5d8d17885786afc347ad16aa638e9b6f6e [file] [log] [blame]
Andrew Gerrandf83f3e42015-02-02 12:05:01 +00001// Copyright 2015 The Go 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// Command release builds a Go release.
6package main
7
8import (
Andrew Gerrandde0661e2015-07-13 11:18:56 -06009 "archive/tar"
Andrew Gerrandca5899f2015-07-23 12:30:44 +100010 "archive/zip"
Brad Fitzpatrickb5038352017-02-13 18:15:23 +000011 "bufio"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000012 "bytes"
Andrew Gerrandde0661e2015-07-13 11:18:56 -060013 "compress/gzip"
Kevin Burke392d3a92017-02-12 01:08:39 -080014 "context"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000015 "flag"
16 "fmt"
Andrew Gerrand106fbe92015-07-31 13:14:07 +100017 gobuild "go/build"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000018 "io"
Brad Fitzpatrick4b956612015-07-07 09:57:08 -070019 "io/ioutil"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000020 "log"
Andrew Bonventre82242412017-09-11 14:22:38 -040021 "math/rand"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000022 "os"
Andrew Gerrand319667f2015-02-04 16:04:07 +000023 "path"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000024 "path/filepath"
Brad Fitzpatrick4b956612015-07-07 09:57:08 -070025 "runtime"
Andrew Gerrand319667f2015-02-04 16:04:07 +000026 "strings"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000027 "sync"
Andrew Bonventre82242412017-09-11 14:22:38 -040028 "time"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000029
Brad Fitzpatrick4b956612015-07-07 09:57:08 -070030 "golang.org/x/build"
Andrew Gerrand8e28dc92016-03-22 09:05:52 +110031 "golang.org/x/build/buildenv"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000032 "golang.org/x/build/buildlet"
33 "golang.org/x/build/dashboard"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000034)
35
36var (
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +000037 target = flag.String("target", "", "If specified, build specific target platform (e.g. 'linux-amd64'). Default is to build all.")
Brad Fitzpatrickdcc7bc32015-12-17 14:53:55 -080038 watch = flag.Bool("watch", false, "Watch the build. Only compatible with -target")
Andrew Gerrand15af43e2015-02-11 11:47:03 +110039
Andrew Gerrandde0661e2015-07-13 11:18:56 -060040 rev = flag.String("rev", "", "Go revision to build")
41 toolsRev = flag.String("tools", "", "Tools revision to build")
42 tourRev = flag.String("tour", "master", "Tour revision to include")
43 blogRev = flag.String("blog", "master", "Blog revision to include")
44 netRev = flag.String("net", "master", "Net revision to include")
45 version = flag.String("version", "", "Version string (go1.5.2)")
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100046 user = flag.String("user", username(), "coordinator username, appended to 'user-'")
Brad Fitzpatrickba6d1092015-12-17 14:21:30 -080047 skipTests = flag.Bool("skip_tests", false, "skip tests; run make.bash instead of all.bash (only use if you ran trybots first)")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000048
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100049 uploadMode = flag.Bool("upload", false, "Upload files (exclusive to all other flags)")
Chris Broadfoot71359ad2017-10-24 12:52:01 -070050 uploadKick = flag.String("edge_kick_command", "", "Command to run to kick off an edge cache update")
Andrew Gerrand15af43e2015-02-11 11:47:03 +110051)
Andrew Gerrand319667f2015-02-04 16:04:07 +000052
Andrew Gerrand8e28dc92016-03-22 09:05:52 +110053var (
54 coordClient *buildlet.CoordinatorClient
55 buildEnv *buildenv.Environment
56)
Brad Fitzpatrick4b956612015-07-07 09:57:08 -070057
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100058func main() {
59 flag.Parse()
Andrew Bonventre82242412017-09-11 14:22:38 -040060 rand.Seed(time.Now().UnixNano())
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100061
62 if *uploadMode {
63 if err := upload(flag.Args()); err != nil {
64 log.Fatal(err)
65 }
66 return
67 }
68
Andrew Gerrand106fbe92015-07-31 13:14:07 +100069 if err := findReleaselet(); err != nil {
70 log.Fatalf("couldn't find releaselet source: %v", err)
Andrew Gerrandca5899f2015-07-23 12:30:44 +100071 }
72
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100073 if *rev == "" {
74 log.Fatal("must specify -rev flag")
75 }
76 if *toolsRev == "" {
77 log.Fatal("must specify -tools flag")
78 }
79 if *version == "" {
80 log.Fatal("must specify -version flag")
81 }
82
83 coordClient = coordinatorClient()
Andrew Gerrand8e28dc92016-03-22 09:05:52 +110084 buildEnv = buildenv.Production
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100085
86 var wg sync.WaitGroup
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +000087 matches := 0
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100088 for _, b := range builds {
89 b := b
90 if *target != "" && b.String() != *target {
91 continue
92 }
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +000093 matches++
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100094 b.logf("Start.")
95 wg.Add(1)
96 go func() {
97 defer wg.Done()
98 if err := b.make(); err != nil {
99 b.logf("Error: %v", err)
100 } else {
101 b.logf("Done.")
102 }
103 }()
104 }
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000105 if *target != "" && matches == 0 {
106 log.Fatalf("no targets matched %q", *target)
107 }
Andrew Gerrand063dc2f2015-07-22 17:21:16 +1000108 wg.Wait()
109}
110
Andrew Gerrand106fbe92015-07-31 13:14:07 +1000111var releaselet = "releaselet.go"
112
113func findReleaselet() error {
114 // First try the working directory.
115 if _, err := os.Stat(releaselet); err == nil {
116 return nil
117 }
118
119 // Then, try to locate the release command in the workspace.
120 const importPath = "golang.org/x/build/cmd/release"
121 pkg, err := gobuild.Import(importPath, "", gobuild.FindOnly)
122 if err != nil {
123 return fmt.Errorf("finding %q: %v", importPath, err)
124 }
125 r := filepath.Join(pkg.Dir, releaselet)
126 if _, err := os.Stat(r); err != nil {
127 return err
128 }
129 releaselet = r
130 return nil
131}
132
Andrew Gerrand319667f2015-02-04 16:04:07 +0000133type Build struct {
134 OS, Arch string
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600135 Source bool
Andrew Gerrand319667f2015-02-04 16:04:07 +0000136
Chris Broadfootc13f7d22015-12-17 14:02:46 -0800137 Race bool // Build race detector.
Andrew Gerrand319667f2015-02-04 16:04:07 +0000138
139 Builder string // Key for dashboard.Builders.
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100140
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000141 Goarm int // GOARM value if set.
142 MakeOnly bool // don't run tests; needed by cross-compile builders (s390x)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000143}
144
Andrew Gerrand319667f2015-02-04 16:04:07 +0000145func (b *Build) String() string {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600146 if b.Source {
147 return "src"
148 }
Chris Broadfootf84ad522015-12-17 16:18:20 -0800149 if b.Goarm != 0 {
Shenghou Ma558ac4f2015-12-20 02:04:40 -0500150 return fmt.Sprintf("%v-%vv%vl", b.OS, b.Arch, b.Goarm)
Chris Broadfootf84ad522015-12-17 16:18:20 -0800151 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000152 return fmt.Sprintf("%v-%v", b.OS, b.Arch)
153}
154
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000155func (b *Build) toolDir() string { return "go/pkg/tool/" + b.OS + "_" + b.Arch }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000156func (b *Build) pkgDir() string { return "go/pkg/" + b.OS + "_" + b.Arch }
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000157
Andrew Gerrand78810b02015-07-07 11:00:09 -0600158func (b *Build) logf(format string, args ...interface{}) {
159 format = fmt.Sprintf("%v: %s", b, format)
160 log.Printf(format, args...)
161}
162
Andrew Gerrand319667f2015-02-04 16:04:07 +0000163var builds = []*Build{
164 {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600165 Source: true,
166 Builder: "linux-amd64",
167 },
168 {
Andrew Gerrand319667f2015-02-04 16:04:07 +0000169 OS: "linux",
170 Arch: "386",
Andrew Gerrand9fb312f2015-07-07 21:46:45 -0600171 Builder: "linux-386",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000172 },
173 {
174 OS: "linux",
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100175 Arch: "arm",
176 Builder: "linux-arm",
177 Goarm: 6, // for compatibility with all Raspberry Pi models.
Russ Cox7b0d8a82017-10-25 16:03:51 -0400178 // The tests take too long for the release packaging.
179 // Much of the time the whole buildlet times out.
180 MakeOnly: true,
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100181 },
182 {
183 OS: "linux",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000184 Arch: "amd64",
185 Race: true,
Andrew Gerrand319667f2015-02-04 16:04:07 +0000186 Builder: "linux-amd64",
187 },
188 {
Brad Fitzpatrick07714b02017-06-15 19:46:22 +0000189 OS: "linux",
190 Arch: "arm64",
191 Builder: "linux-arm64-packet",
192 },
193 {
Andrew Gerrand319667f2015-02-04 16:04:07 +0000194 OS: "freebsd",
195 Arch: "386",
Brad Fitzpatrick873c4122017-11-28 21:51:29 +0000196 Builder: "freebsd-386-11_1",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000197 },
198 {
199 OS: "freebsd",
200 Arch: "amd64",
201 Race: true,
Brad Fitzpatrick873c4122017-11-28 21:51:29 +0000202 Builder: "freebsd-amd64-11_1",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000203 },
Andrew Gerrand78810b02015-07-07 11:00:09 -0600204 {
205 OS: "windows",
206 Arch: "386",
Chris Broadfootffc9f6c2017-08-07 13:50:52 -0700207 Builder: "windows-386-2008",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600208 },
209 {
210 OS: "windows",
211 Arch: "amd64",
212 Race: true,
Brad Fitzpatrick97a4f812017-04-24 20:32:02 +0000213 Builder: "windows-amd64-2008",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600214 },
215 {
216 OS: "darwin",
217 Arch: "amd64",
218 Race: true,
Chris Broadfoot51046002016-09-07 12:41:11 -0700219 Builder: "darwin-amd64-10_11",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600220 },
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000221 {
222 OS: "linux",
223 Arch: "s390x",
224 MakeOnly: true,
225 Builder: "linux-s390x-crosscompile",
226 },
Brad Fitzpatricka6cb7e42016-11-15 21:16:56 -0500227 // TODO(bradfitz): switch this ppc64 builder to a Kubernetes
228 // container cross-compiling ppc64 like the s390x one? For
229 // now, the ppc64le builders (5) are back, so let's see if we
230 // can just depend on them not going away.
231 {
232 OS: "linux",
233 Arch: "ppc64le",
234 MakeOnly: true,
235 Builder: "linux-ppc64le-buildlet",
236 },
Andrew Gerrand319667f2015-02-04 16:04:07 +0000237}
238
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100239const (
240 toolsRepo = "golang.org/x/tools"
241 blogRepo = "golang.org/x/blog"
242 tourRepo = "golang.org/x/tour"
243)
Andrew Gerrand319667f2015-02-04 16:04:07 +0000244
245var toolPaths = []string{
Andrew Gerrand319667f2015-02-04 16:04:07 +0000246 "golang.org/x/tools/cmd/godoc",
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100247 "golang.org/x/tour/gotour",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000248}
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000249
250var preBuildCleanFiles = []string{
251 ".gitattributes",
Andrew Gerrand82423c12016-07-05 09:22:29 +1000252 ".github",
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000253 ".gitignore",
254 ".hgignore",
255 ".hgtags",
256 "misc/dashboard",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600257 "misc/makerelease",
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000258}
259
260var postBuildCleanFiles = []string{
261 "VERSION.cache",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600262 "pkg/bootstrap",
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000263}
264
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700265func (b *Build) buildlet() (*buildlet.Client, error) {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600266 b.logf("Creating buildlet.")
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700267 bc, err := coordClient.CreateBuildlet(b.Builder)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000268 if err != nil {
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700269 return nil, err
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000270 }
Brad Fitzpatrick1e7c6912017-02-13 17:38:27 +0000271 bc.SetReleaseMode(true) // disable pargzip; golang.org/issue/19052
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700272 return bc, nil
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700273}
274
Andrew Gerrand78810b02015-07-07 11:00:09 -0600275func (b *Build) make() error {
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700276 bc, ok := dashboard.Builders[b.Builder]
277 if !ok {
278 return fmt.Errorf("unknown builder: %v", bc)
279 }
280
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000281 var hostArch string // non-empty if we're cross-compiling (s390x)
Brad Fitzpatrick14d99732018-05-05 16:36:05 +0000282 if b.MakeOnly && bc.IsContainer() && (bc.GOARCH() != "amd64" && bc.GOARCH() != "386") {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000283 hostArch = "amd64"
284 }
285
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700286 client, err := b.buildlet()
287 if err != nil {
288 return err
289 }
290 defer client.Close()
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000291
Andrew Gerrand319667f2015-02-04 16:04:07 +0000292 work, err := client.WorkDir()
293 if err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000294 return err
295 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000296
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000297 // Push source to buildlet
298 b.logf("Pushing source to buildlet.")
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100299 const (
300 goDir = "go"
301 goPath = "gopath"
Andrew Gerrand78810b02015-07-07 11:00:09 -0600302 go14 = "go1.4"
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100303 )
304 for _, r := range []struct {
305 repo, rev string
306 }{
307 {"go", *rev},
308 {"tools", *toolsRev},
309 {"blog", *blogRev},
310 {"tour", *tourRev},
311 {"net", *netRev},
312 } {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600313 if b.Source && r.repo != "go" {
314 continue
315 }
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100316 dir := goDir
317 if r.repo != "go" {
318 dir = goPath + "/src/golang.org/x/" + r.repo
319 }
320 tar := "https://go.googlesource.com/" + r.repo + "/+archive/" + r.rev + ".tar.gz"
321 if err := client.PutTarFromURL(tar, dir); err != nil {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000322 b.logf("failed to put tarball %q into dir %q: %v", tar, dir, err)
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100323 return err
324 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000325 }
326
Andrew Gerrand8e28dc92016-03-22 09:05:52 +1100327 if u := bc.GoBootstrapURL(buildEnv); u != "" && !b.Source {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600328 b.logf("Installing go1.4.")
Andrew Gerrand8e28dc92016-03-22 09:05:52 +1100329 if err := client.PutTarFromURL(u, go14); err != nil {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600330 return err
331 }
332 }
333
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000334 // Write out version file.
335 b.logf("Writing VERSION file.")
336 if err := client.Put(strings.NewReader(*version), "go/VERSION", 0644); err != nil {
337 return err
338 }
339
Andrew Gerrand78810b02015-07-07 11:00:09 -0600340 b.logf("Cleaning goroot (pre-build).")
Andrew Gerrand319667f2015-02-04 16:04:07 +0000341 if err := client.RemoveAll(addPrefix(goDir, preBuildCleanFiles)...); err != nil {
342 return err
343 }
344
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600345 if b.Source {
346 b.logf("Skipping build.")
347 return b.fetchTarball(client)
348 }
349
Andrew Gerrand319667f2015-02-04 16:04:07 +0000350 // Set up build environment.
351 sep := "/"
352 if b.OS == "windows" {
353 sep = "\\"
354 }
Andrew Gerrand78810b02015-07-07 11:00:09 -0600355 env := append(bc.Env(),
356 "GOROOT_FINAL="+bc.GorootFinal(),
357 "GOROOT="+work+sep+goDir,
Andrew Gerrand78810b02015-07-07 11:00:09 -0600358 "GOPATH="+work+sep+goPath,
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600359 "GOBIN=",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600360 )
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100361
362 if b.Goarm > 0 {
363 env = append(env, fmt.Sprintf("GOARM=%d", b.Goarm))
Cherry Zhang297480d2017-01-22 19:01:43 -0500364 env = append(env, fmt.Sprintf("CGO_CFLAGS=-march=armv%d", b.Goarm))
365 env = append(env, fmt.Sprintf("CGO_LDFLAGS=-march=armv%d", b.Goarm))
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100366 }
367
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000368 // Execute build
Andrew Gerrand78810b02015-07-07 11:00:09 -0600369 b.logf("Building.")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000370 out := new(bytes.Buffer)
Brad Fitzpatrickba6d1092015-12-17 14:21:30 -0800371 script := bc.AllScript()
372 scriptArgs := bc.AllScriptArgs()
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000373 if *skipTests || b.MakeOnly {
Brad Fitzpatrickba6d1092015-12-17 14:21:30 -0800374 script = bc.MakeScript()
375 scriptArgs = bc.MakeScriptArgs()
376 }
377 all := filepath.Join(goDir, script)
Brad Fitzpatrickdcc7bc32015-12-17 14:53:55 -0800378 var execOut io.Writer = out
379 if *watch && *target != "" {
380 execOut = io.MultiWriter(out, os.Stdout)
381 }
Andrew Gerrandd719d262015-07-31 12:57:43 +1000382 remoteErr, err := client.Exec(all, buildlet.ExecOpts{
Brad Fitzpatrickdcc7bc32015-12-17 14:53:55 -0800383 Output: execOut,
Andrew Gerrand319667f2015-02-04 16:04:07 +0000384 ExtraEnv: env,
Brad Fitzpatrickba6d1092015-12-17 14:21:30 -0800385 Args: scriptArgs,
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000386 })
387 if err != nil {
388 return err
389 }
390 if remoteErr != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000391 return fmt.Errorf("Build failed: %v\nOutput:\n%v", remoteErr, out)
392 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000393
Andrew Gerrand319667f2015-02-04 16:04:07 +0000394 goCmd := path.Join(goDir, "bin/go")
395 if b.OS == "windows" {
396 goCmd += ".exe"
397 }
398 runGo := func(args ...string) error {
399 out := new(bytes.Buffer)
Chris Broadfoote296e7e2015-12-17 15:18:14 -0800400 var execOut io.Writer = out
401 if *watch && *target != "" {
402 execOut = io.MultiWriter(out, os.Stdout)
403 }
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000404 cmdEnv := append([]string(nil), env...)
405 if len(args) > 0 && args[0] == "run" && hostArch != "" {
406 cmdEnv = setGOARCH(cmdEnv, hostArch)
407 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000408 remoteErr, err := client.Exec(goCmd, buildlet.ExecOpts{
Chris Broadfoote296e7e2015-12-17 15:18:14 -0800409 Output: execOut,
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100410 Dir: ".", // root of buildlet work directory
Andrew Gerrand319667f2015-02-04 16:04:07 +0000411 Args: args,
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000412 ExtraEnv: cmdEnv,
Andrew Gerrand319667f2015-02-04 16:04:07 +0000413 })
414 if err != nil {
415 return err
416 }
417 if remoteErr != nil {
418 return fmt.Errorf("go %v: %v\n%s", strings.Join(args, " "), remoteErr, out)
419 }
420 return nil
421 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000422
Andrew Gerrand319667f2015-02-04 16:04:07 +0000423 if b.Race {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600424 b.logf("Building race detector.")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000425
Andrew Gerrand319667f2015-02-04 16:04:07 +0000426 if err := runGo("install", "-race", "std"); err != nil {
427 return err
428 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000429 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000430
Andrew Gerrand78810b02015-07-07 11:00:09 -0600431 b.logf("Building %v.", strings.Join(toolPaths, ", "))
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100432 if err := runGo(append([]string{"install"}, toolPaths...)...); err != nil {
433 return err
Andrew Gerrand319667f2015-02-04 16:04:07 +0000434 }
435
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000436 b.logf("Cleaning goroot (post-build).")
437 if err := client.RemoveAll(addPrefix(goDir, postBuildCleanFiles)...); err != nil {
438 return err
439 }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000440 // Users don't need the api checker binary pre-built. It's
441 // used by tests, but all.bash builds it first.
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000442 if err := client.RemoveAll(b.toolDir() + "/api"); err != nil {
443 return err
444 }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000445 // Remove go/pkg/${GOOS}_${GOARCH}/cmd. This saves a bunch of
446 // space, and users don't typically rebuild cmd/compile,
447 // cmd/link, etc. If they want to, they still can, but they'll
448 // have to pay the cost of rebuilding dependent libaries. No
449 // need to ship them just in case.
450 if err := client.RemoveAll(b.pkgDir() + "/cmd"); err != nil {
451 return err
452 }
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000453
Andrew Gerrand78810b02015-07-07 11:00:09 -0600454 b.logf("Pushing and running releaselet.")
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100455 f, err := os.Open(releaselet)
456 if err != nil {
457 return err
458 }
Andrew Gerrandce7e7fd2015-08-06 04:28:33 +0000459 err = client.Put(f, "releaselet.go", 0666)
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100460 f.Close()
461 if err != nil {
462 return err
463 }
Andrew Gerrandce7e7fd2015-08-06 04:28:33 +0000464 if err := runGo("run", "releaselet.go"); err != nil {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000465 log.Printf("releaselet failed: %v", err)
466 client.ListDir(".", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
467 log.Printf("remote: %v", ent)
468 })
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100469 return err
470 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000471
Andrew Gerrandce7e7fd2015-08-06 04:28:33 +0000472 cleanFiles := []string{"releaselet.go", goPath, go14}
Andrew Gerrand78810b02015-07-07 11:00:09 -0600473
474 switch b.OS {
475 case "darwin":
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600476 filename := *version + "." + b.String() + ".pkg"
477 if err := b.fetchFile(client, filename, "pkg"); err != nil {
478 return err
479 }
480 cleanFiles = append(cleanFiles, "pkg")
Andrew Gerrand78810b02015-07-07 11:00:09 -0600481 case "windows":
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000482 filename := *version + "." + b.String() + ".msi"
483 if err := b.fetchFile(client, filename, "msi"); err != nil {
484 return err
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600485 }
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000486 cleanFiles = append(cleanFiles, "msi")
Andrew Gerrand78810b02015-07-07 11:00:09 -0600487 }
488
Andrew Gerrand319667f2015-02-04 16:04:07 +0000489 // Need to delete everything except the final "go" directory,
490 // as we make the tarball relative to workdir.
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000491 b.logf("Cleaning workdir.")
Andrew Gerrand319667f2015-02-04 16:04:07 +0000492 if err := client.RemoveAll(cleanFiles...); err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000493 return err
494 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000495
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000496 if b.OS == "windows" {
497 return b.fetchZip(client)
498 }
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600499 return b.fetchTarball(client)
500}
501
502func (b *Build) fetchTarball(client *buildlet.Client) error {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600503 b.logf("Downloading tarball.")
Kevin Burke392d3a92017-02-12 01:08:39 -0800504 tgz, err := client.GetTar(context.Background(), ".")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000505 if err != nil {
506 return err
507 }
Andrew Gerrand78810b02015-07-07 11:00:09 -0600508 filename := *version + "." + b.String() + ".tar.gz"
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600509 return b.writeFile(filename, tgz)
510}
511
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000512func (b *Build) fetchZip(client *buildlet.Client) error {
513 b.logf("Downloading tarball and re-compressing as zip.")
514
Kevin Burke392d3a92017-02-12 01:08:39 -0800515 tgz, err := client.GetTar(context.Background(), ".")
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000516 if err != nil {
517 return err
518 }
519 defer tgz.Close()
520
521 filename := *version + "." + b.String() + ".zip"
522 f, err := os.Create(filename)
523 if err != nil {
524 return err
525 }
526 if err := tgzToZip(f, tgz); err != nil {
527 f.Close()
528 return err
529 }
530 if err := f.Close(); err != nil {
531 return err
532 }
533
534 b.logf("Wrote %q.", filename)
535 return nil
536}
537
538func tgzToZip(w io.Writer, r io.Reader) error {
539 zr, err := gzip.NewReader(r)
540 if err != nil {
541 return err
542 }
543 tr := tar.NewReader(zr)
544
545 zw := zip.NewWriter(w)
546 for {
547 th, err := tr.Next()
548 if err == io.EOF {
549 break
550 }
551 if err != nil {
552 return err
553 }
554 fi := th.FileInfo()
555 zh, err := zip.FileInfoHeader(fi)
556 if err != nil {
557 return err
558 }
559 zh.Name = th.Name // for the full path
560 switch strings.ToLower(path.Ext(zh.Name)) {
561 case ".jpg", ".jpeg", ".png", ".gif":
562 // Don't re-compress already compressed files.
563 zh.Method = zip.Store
564 default:
565 zh.Method = zip.Deflate
566 }
567 if fi.IsDir() {
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000568 zh.Method = zip.Store
569 }
570 w, err := zw.CreateHeader(zh)
571 if err != nil {
572 return err
573 }
574 if fi.IsDir() {
575 continue
576 }
577 if _, err := io.Copy(w, tr); err != nil {
578 return err
579 }
580 }
581 return zw.Close()
582}
583
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600584// fetchFile fetches the specified directory from the given buildlet, and
585// writes the first file it finds in that directory to dest.
586func (b *Build) fetchFile(client *buildlet.Client, dest, dir string) error {
587 b.logf("Downloading file from %q.", dir)
Kevin Burke392d3a92017-02-12 01:08:39 -0800588 tgz, err := client.GetTar(context.Background(), dir)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000589 if err != nil {
590 return err
591 }
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600592 defer tgz.Close()
593 zr, err := gzip.NewReader(tgz)
594 if err != nil {
595 return err
596 }
597 tr := tar.NewReader(zr)
598 for {
599 h, err := tr.Next()
600 if err == io.EOF {
601 return io.ErrUnexpectedEOF
602 }
603 if err != nil {
604 return err
605 }
606 if !h.FileInfo().IsDir() {
607 break
608 }
609 }
610 return b.writeFile(dest, tr)
611}
612
613func (b *Build) writeFile(name string, r io.Reader) error {
614 f, err := os.Create(name)
615 if err != nil {
616 return err
617 }
618 if _, err := io.Copy(f, r); err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000619 f.Close()
620 return err
621 }
622 if err := f.Close(); err != nil {
623 return err
624 }
Brad Fitzpatrickb5038352017-02-13 18:15:23 +0000625 if strings.HasSuffix(name, ".gz") {
626 if err := verifyGzipSingleStream(name); err != nil {
627 return fmt.Errorf("error verifying that %s is a single-stream gzip: %v", name, err)
628 }
629 }
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600630 b.logf("Wrote %q.", name)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000631 return nil
632}
633
Brad Fitzpatrickb5038352017-02-13 18:15:23 +0000634// verifyGzipSingleStream verifies that the named gzip file is not
635// a multi-stream file. See golang.org/issue/19052
636func verifyGzipSingleStream(name string) error {
637 f, err := os.Open(name)
638 if err != nil {
639 return err
640 }
641 defer f.Close()
642 br := bufio.NewReader(f)
643 zr, err := gzip.NewReader(br)
644 if err != nil {
645 return err
646 }
647 zr.Multistream(false)
648 if _, err := io.Copy(ioutil.Discard, zr); err != nil {
649 return fmt.Errorf("reading first stream: %v", err)
650 }
651 peek, err := br.Peek(1)
652 if len(peek) > 0 || err != io.EOF {
653 return fmt.Errorf("unexpected peek of %d, %v after first gzip stream", len(peek), err)
654 }
655 return nil
656}
657
Andrew Gerrand319667f2015-02-04 16:04:07 +0000658func addPrefix(prefix string, in []string) []string {
659 var out []string
660 for _, s := range in {
661 out = append(out, path.Join(prefix, s))
662 }
663 return out
664}
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700665
666func coordinatorClient() *buildlet.CoordinatorClient {
667 return &buildlet.CoordinatorClient{
668 Auth: buildlet.UserPass{
669 Username: "user-" + *user,
670 Password: userToken(),
671 },
Andrew Gerrand8e28dc92016-03-22 09:05:52 +1100672 Instance: build.ProdCoordinator,
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700673 }
674}
675
676func homeDir() string {
677 if runtime.GOOS == "windows" {
678 return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
679 }
680 return os.Getenv("HOME")
681}
682
683func configDir() string {
684 if runtime.GOOS == "windows" {
685 return filepath.Join(os.Getenv("APPDATA"), "Gomote")
686 }
687 if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" {
688 return filepath.Join(xdg, "gomote")
689 }
690 return filepath.Join(homeDir(), ".config", "gomote")
691}
692
693func username() string {
694 if runtime.GOOS == "windows" {
695 return os.Getenv("USERNAME")
696 }
697 return os.Getenv("USER")
698}
699
700func userToken() string {
701 if *user == "" {
702 panic("userToken called with user flag empty")
703 }
704 keyDir := configDir()
705 baseFile := "user-" + *user + ".token"
706 tokenFile := filepath.Join(keyDir, baseFile)
707 slurp, err := ioutil.ReadFile(tokenFile)
708 if os.IsNotExist(err) {
709 log.Printf("Missing file %s for user %q. Change --user or obtain a token and place it there.",
710 tokenFile, *user)
711 }
712 if err != nil {
713 log.Fatal(err)
714 }
715 return strings.TrimSpace(string(slurp))
716}
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000717
718func setGOARCH(env []string, goarch string) []string {
719 wantKV := "GOARCH=" + goarch
720 existing := false
721 for i, kv := range env {
722 if strings.HasPrefix(kv, "GOARCH=") && kv != wantKV {
723 env[i] = wantKV
724 existing = true
725 }
726 }
727 if existing {
728 return env
729 }
730 return append(env, wantKV)
731}