blob: 3a4194d9b45d4264a1a3d51f202fbd957a0b9af6 [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"
17 "io"
Brad Fitzpatrick4b956612015-07-07 09:57:08 -070018 "io/ioutil"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000019 "log"
Andrew Bonventre82242412017-09-11 14:22:38 -040020 "math/rand"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000021 "os"
Andrew Gerrand319667f2015-02-04 16:04:07 +000022 "path"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000023 "path/filepath"
Brad Fitzpatrick4b956612015-07-07 09:57:08 -070024 "runtime"
Andrew Gerrand319667f2015-02-04 16:04:07 +000025 "strings"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000026 "sync"
Andrew Bonventre82242412017-09-11 14:22:38 -040027 "time"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000028
Brad Fitzpatrick4b956612015-07-07 09:57:08 -070029 "golang.org/x/build"
Andrew Gerrand8e28dc92016-03-22 09:05:52 +110030 "golang.org/x/build/buildenv"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000031 "golang.org/x/build/buildlet"
32 "golang.org/x/build/dashboard"
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000033)
34
Dmitri Shuralyovded33d32019-08-10 15:16:18 -040035//go:generate go run makestatic.go
36
Andrew Gerrandf83f3e42015-02-02 12:05:01 +000037var (
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +000038 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 -080039 watch = flag.Bool("watch", false, "Watch the build. Only compatible with -target")
Andrew Gerrand15af43e2015-02-11 11:47:03 +110040
Dmitri Shuralyov673ce342019-08-21 14:11:59 -040041 stagingDir = flag.String("staging_dir", "", "If specified, use this as the staging directory for untested release artifacts. Default is the system temporary directory.")
42
Filippo Valsorda702928c2018-12-12 14:37:02 -050043 rev = flag.String("rev", "", "Go revision to build, alternative to -tarball")
44 tarball = flag.String("tarball", "", "Go tree tarball to build, alternative to -rev")
Andrew Gerrandde0661e2015-07-13 11:18:56 -060045 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-'")
Dmitri Shuralyove566a702020-05-18 19:06:44 -040047 skipTests = flag.Bool("skip_tests", false, "skip tests; run make.bash but not all.bash (only use if sufficient testing was done elsewhere)")
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 {
Brad Fitzpatrickf7da0f82018-08-20 22:49:40 +000063 buildenv.CheckUserCredentials()
Dmitri Shuralyovce4d62a2021-04-30 19:02:55 -040064 userToken() // Call userToken for the side-effect of exiting if a gomote token doesn't exist.
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100065 if err := upload(flag.Args()); err != nil {
66 log.Fatal(err)
67 }
68 return
69 }
70
Filippo Valsorda702928c2018-12-12 14:37:02 -050071 if (*rev == "" && *tarball == "") || (*rev != "" && *tarball != "") {
Brad Fitzpatrick5bd98932019-04-29 17:28:21 +000072 log.Fatal("must specify one of -rev or -tarball")
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100073 }
74 if *version == "" {
Brad Fitzpatrick5bd98932019-04-29 17:28:21 +000075 log.Fatal(`must specify -version flag (such as "go1.12" or "go1.13beta1")`)
76 }
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100077
78 coordClient = coordinatorClient()
Andrew Gerrand8e28dc92016-03-22 09:05:52 +110079 buildEnv = buildenv.Production
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100080
81 var wg sync.WaitGroup
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +000082 matches := 0
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100083 for _, b := range builds {
84 b := b
85 if *target != "" && b.String() != *target {
86 continue
87 }
Dmitri Shuralyov56b7eea2020-08-03 23:22:08 -040088 if !match(b.GoQuery, *version) {
89 continue
90 }
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +000091 matches++
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100092 b.logf("Start.")
93 wg.Add(1)
94 go func() {
95 defer wg.Done()
96 if err := b.make(); err != nil {
97 b.logf("Error: %v", err)
98 } else {
99 b.logf("Done.")
100 }
101 }()
102 }
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000103 if *target != "" && matches == 0 {
104 log.Fatalf("no targets matched %q", *target)
105 }
Andrew Gerrand063dc2f2015-07-22 17:21:16 +1000106 wg.Wait()
107}
108
Andrew Gerrand319667f2015-02-04 16:04:07 +0000109type Build struct {
Dmitri Shuralyov56b7eea2020-08-03 23:22:08 -0400110 // GoQuery is a Go version query specifying the Go versions
111 // the build applies to. Empty string means all Go versions.
112 GoQuery string
113
Andrew Gerrand319667f2015-02-04 16:04:07 +0000114 OS, Arch string
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600115 Source bool
Andrew Gerrand319667f2015-02-04 16:04:07 +0000116
Chris Broadfootc13f7d22015-12-17 14:02:46 -0800117 Race bool // Build race detector.
Andrew Gerrand319667f2015-02-04 16:04:07 +0000118
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400119 Builder string // Key for dashboard.Builders.
120 TestOnly bool // Run tests only; don't produce a release artifact.
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100121
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400122 Goarm int // GOARM value if set.
123 SkipTests bool // skip tests (run make.bash but not all.bash); needed by cross-compile builders (s390x)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000124}
125
Andrew Gerrand319667f2015-02-04 16:04:07 +0000126func (b *Build) String() string {
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400127 switch {
128 case b.Source:
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600129 return "src"
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400130 case b.TestOnly:
131 // Test-only builds are named after the builder used to
132 // perform them. For example, "linux-amd64-longtest".
133 return b.Builder
134 case b.Goarm != 0:
Shenghou Ma558ac4f2015-12-20 02:04:40 -0500135 return fmt.Sprintf("%v-%vv%vl", b.OS, b.Arch, b.Goarm)
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400136 default:
137 return fmt.Sprintf("%v-%v", b.OS, b.Arch)
Chris Broadfootf84ad522015-12-17 16:18:20 -0800138 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000139}
140
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000141func (b *Build) toolDir() string { return "go/pkg/tool/" + b.OS + "_" + b.Arch }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000142func (b *Build) pkgDir() string { return "go/pkg/" + b.OS + "_" + b.Arch }
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000143
Andrew Gerrand78810b02015-07-07 11:00:09 -0600144func (b *Build) logf(format string, args ...interface{}) {
145 format = fmt.Sprintf("%v: %s", b, format)
146 log.Printf(format, args...)
147}
148
Andrew Gerrand319667f2015-02-04 16:04:07 +0000149var builds = []*Build{
150 {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600151 Source: true,
Brad Fitzpatrick1fe20772019-04-09 01:48:33 +0000152 Builder: "linux-amd64",
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600153 },
154 {
Andrew Gerrand319667f2015-02-04 16:04:07 +0000155 OS: "linux",
156 Arch: "386",
Dmitri Shuralyov90d5e7c2020-12-07 22:31:50 -0500157 Builder: "linux-386-stretch",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000158 },
159 {
160 OS: "linux",
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100161 Arch: "arm",
Dmitri Shuralyov90d5e7c2020-12-07 22:31:50 -0500162 Builder: "linux-arm-aws",
163 Goarm: 6, // For compatibility with all Raspberry Pi models.
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100164 },
165 {
166 OS: "linux",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000167 Arch: "amd64",
168 Race: true,
Dmitri Shuralyov90d5e7c2020-12-07 22:31:50 -0500169 Builder: "linux-amd64-stretch", // Using Stretch as of Go 1.16 because Jessie LTS has ended (golang.org/issue/40561#issuecomment-731482962).
Andrew Gerrand319667f2015-02-04 16:04:07 +0000170 },
171 {
Brad Fitzpatrick07714b02017-06-15 19:46:22 +0000172 OS: "linux",
173 Arch: "arm64",
Dmitri Shuralyov90d5e7c2020-12-07 22:31:50 -0500174 Builder: "linux-arm64-aws",
Brad Fitzpatrick07714b02017-06-15 19:46:22 +0000175 },
176 {
Carlos Amedee6883e812021-11-19 10:03:57 -0500177 GoQuery: ">= go1.18beta1", // See #40561.
178 OS: "freebsd",
179 Arch: "386",
Heschi Kreinick14466342022-01-10 15:09:53 -0500180 Builder: "freebsd-386-12_3",
Carlos Amedee6883e812021-11-19 10:03:57 -0500181 },
182 {
183 GoQuery: ">= go1.18beta1", // See #40561.
184 OS: "freebsd",
185 Arch: "amd64",
186 Race: true,
Heschi Kreinick14466342022-01-10 15:09:53 -0500187 Builder: "freebsd-amd64-12_3",
Carlos Amedee6883e812021-11-19 10:03:57 -0500188 },
189 {
190 GoQuery: ">= go1.17beta1 && < go1.18beta1", // See #45727.
Andrew Gerrand319667f2015-02-04 16:04:07 +0000191 OS: "freebsd",
192 Arch: "386",
Carlos Amedee63087352021-04-30 17:38:39 -0400193 Builder: "freebsd-386-11_4",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000194 },
195 {
Carlos Amedee6883e812021-11-19 10:03:57 -0500196 GoQuery: ">= go1.17beta1 && < go1.18beta1", // See #45727.
Andrew Gerrand319667f2015-02-04 16:04:07 +0000197 OS: "freebsd",
198 Arch: "amd64",
199 Race: true,
Carlos Amedee63087352021-04-30 17:38:39 -0400200 Builder: "freebsd-amd64-11_4",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000201 },
Andrew Gerrand78810b02015-07-07 11:00:09 -0600202 {
203 OS: "windows",
204 Arch: "386",
Chris Broadfootffc9f6c2017-08-07 13:50:52 -0700205 Builder: "windows-386-2008",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600206 },
207 {
208 OS: "windows",
209 Arch: "amd64",
210 Race: true,
Brad Fitzpatrick97a4f812017-04-24 20:32:02 +0000211 Builder: "windows-amd64-2008",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600212 },
213 {
Dmitri Shuralyov0f4c55b2021-06-01 17:58:34 -0400214 GoQuery: ">= go1.17beta1", // Go 1.17 Beta 1 is the first Go (pre-)release with the windows/arm64 port.
215 OS: "windows",
216 Arch: "arm64",
217 Race: false, // Not supported as of 2021-06-01.
Alexander Rakoczy76eb6412021-06-29 11:40:03 -0400218 Builder: "windows-arm64-10",
Dmitri Shuralyov0f4c55b2021-06-01 17:58:34 -0400219 },
220 {
Dmitri Shuralyovc37e51d2021-12-07 17:41:13 -0500221 GoQuery: ">= go1.18beta1", // Start exercising a macOS 12 releaselet as of Go 1.18 Beta 1; see issue 40561.
Andrew Gerrand78810b02015-07-07 11:00:09 -0600222 OS: "darwin",
223 Arch: "amd64",
224 Race: true,
Dmitri Shuralyovc37e51d2021-12-07 17:41:13 -0500225 Builder: "darwin-amd64-12_0",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600226 },
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000227 {
Dmitri Shuralyovc37e51d2021-12-07 17:41:13 -0500228 GoQuery: ">= go1.18beta1", // Start exercising a macOS 12 releaselet as of Go 1.18 Beta 1; see issue 40561.
Dmitri Shuralyov4682f4a2020-12-15 19:06:56 -0500229 OS: "darwin",
230 Arch: "arm64",
231 Race: true,
Alexander Rakoczy6f3ca612021-11-18 11:31:07 -0500232 Builder: "darwin-arm64-12_0-toothrot",
Dmitri Shuralyov4682f4a2020-12-15 19:06:56 -0500233 },
234 {
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400235 OS: "linux",
236 Arch: "s390x",
237 SkipTests: true,
238 Builder: "linux-s390x-crosscompile",
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000239 },
Brad Fitzpatricka6cb7e42016-11-15 21:16:56 -0500240 // TODO(bradfitz): switch this ppc64 builder to a Kubernetes
241 // container cross-compiling ppc64 like the s390x one? For
242 // now, the ppc64le builders (5) are back, so let's see if we
243 // can just depend on them not going away.
244 {
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400245 OS: "linux",
246 Arch: "ppc64le",
247 SkipTests: true,
248 Builder: "linux-ppc64le-buildlet",
249 },
250
Dmitri Shuralyov56b7eea2020-08-03 23:22:08 -0400251 // Older builds.
252 {
Carlos Amedee63087352021-04-30 17:38:39 -0400253 GoQuery: "< go1.17beta1", // See #40563.
254 OS: "freebsd",
255 Arch: "386",
256 Builder: "freebsd-386-11_2",
257 },
258 {
259 GoQuery: "< go1.17beta1", // See #40563.
260 OS: "freebsd",
261 Arch: "amd64",
262 Race: true,
263 Builder: "freebsd-amd64-11_2",
264 },
Heschi Kreinickd0819ed2021-05-18 17:15:24 -0400265 {
Dmitri Shuralyovc37e51d2021-12-07 17:41:13 -0500266 GoQuery: ">= go1.17beta1 && < go1.18beta1",
267 OS: "darwin",
268 Arch: "amd64",
269 Race: true,
270 Builder: "darwin-amd64-11_0",
271 },
272 {
Heschi Kreinickd0819ed2021-05-18 17:15:24 -0400273 GoQuery: "< go1.17beta1", // See golang/go#46161.
274 OS: "darwin",
275 Arch: "amd64",
276 Race: true,
277 Builder: "darwin-amd64-10_15",
278 },
Dmitri Shuralyov233166b2021-12-01 14:35:11 -0500279 {
280 GoQuery: "< go1.18beta1", // Go 1.17 and 1.16 still use macOS 11. See issue 49889.
281 OS: "darwin",
282 Arch: "arm64",
283 Race: true,
284 Builder: "darwin-arm64-11_0-toothrot",
285 },
Dmitri Shuralyov56b7eea2020-08-03 23:22:08 -0400286
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400287 // Test-only builds.
288 {
Dmitri Shuralyov305e1e32021-03-25 17:40:02 -0400289 Builder: "linux-386-longtest",
290 OS: "linux", Arch: "386",
291 TestOnly: true,
292 },
293 {
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400294 Builder: "linux-amd64-longtest",
295 OS: "linux", Arch: "amd64",
296 TestOnly: true,
297 },
298 {
299 Builder: "windows-amd64-longtest",
300 OS: "windows", Arch: "amd64",
301 TestOnly: true,
Brad Fitzpatricka6cb7e42016-11-15 21:16:56 -0500302 },
Andrew Gerrand319667f2015-02-04 16:04:07 +0000303}
304
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000305var preBuildCleanFiles = []string{
306 ".gitattributes",
Andrew Gerrand82423c12016-07-05 09:22:29 +1000307 ".github",
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000308 ".gitignore",
309 ".hgignore",
310 ".hgtags",
311 "misc/dashboard",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600312 "misc/makerelease",
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000313}
314
Carlos Amedeef8a16ea2021-12-14 18:17:24 -0500315func (b *Build) buildlet() (buildlet.Client, error) {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600316 b.logf("Creating buildlet.")
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700317 bc, err := coordClient.CreateBuildlet(b.Builder)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000318 if err != nil {
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700319 return nil, err
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000320 }
Brad Fitzpatrick1e7c6912017-02-13 17:38:27 +0000321 bc.SetReleaseMode(true) // disable pargzip; golang.org/issue/19052
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700322 return bc, nil
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700323}
324
Andrew Gerrand78810b02015-07-07 11:00:09 -0600325func (b *Build) make() error {
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000326 ctx := context.TODO()
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700327 bc, ok := dashboard.Builders[b.Builder]
328 if !ok {
329 return fmt.Errorf("unknown builder: %v", bc)
330 }
331
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000332 var hostArch string // non-empty if we're cross-compiling (s390x)
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400333 if b.SkipTests && bc.IsContainer() && (bc.GOARCH() != "amd64" && bc.GOARCH() != "386") {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000334 hostArch = "amd64"
335 }
336
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700337 client, err := b.buildlet()
338 if err != nil {
339 return err
340 }
341 defer client.Close()
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000342
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000343 work, err := client.WorkDir(ctx)
Andrew Gerrand319667f2015-02-04 16:04:07 +0000344 if err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000345 return err
346 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000347
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400348 // Push source to buildlet.
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000349 b.logf("Pushing source to buildlet.")
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100350 const (
351 goDir = "go"
352 goPath = "gopath"
Andrew Gerrand78810b02015-07-07 11:00:09 -0600353 go14 = "go1.4"
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100354 )
Filippo Valsorda702928c2018-12-12 14:37:02 -0500355 if *tarball != "" {
356 tarFile, err := os.Open(*tarball)
357 if err != nil {
358 b.logf("failed to open tarball %q: %v", *tarball, err)
359 return err
360 }
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000361 if err := client.PutTar(ctx, tarFile, goDir); err != nil {
Filippo Valsorda702928c2018-12-12 14:37:02 -0500362 b.logf("failed to put tarball %q into dir %q: %v", *tarball, goDir, err)
363 return err
364 }
365 tarFile.Close()
366 } else {
367 tar := "https://go.googlesource.com/go/+archive/" + *rev + ".tar.gz"
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000368 if err := client.PutTarFromURL(ctx, tar, goDir); err != nil {
Filippo Valsorda702928c2018-12-12 14:37:02 -0500369 b.logf("failed to put tarball %q into dir %q: %v", tar, goDir, err)
370 return err
371 }
372 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000373
Andrew Gerrand8e28dc92016-03-22 09:05:52 +1100374 if u := bc.GoBootstrapURL(buildEnv); u != "" && !b.Source {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600375 b.logf("Installing go1.4.")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000376 if err := client.PutTarFromURL(ctx, u, go14); err != nil {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600377 return err
378 }
379 }
380
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000381 // Write out version file.
382 b.logf("Writing VERSION file.")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000383 if err := client.Put(ctx, strings.NewReader(*version), "go/VERSION", 0644); err != nil {
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000384 return err
385 }
386
Andrew Gerrand78810b02015-07-07 11:00:09 -0600387 b.logf("Cleaning goroot (pre-build).")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000388 if err := client.RemoveAll(ctx, addPrefix(goDir, preBuildCleanFiles)...); err != nil {
Andrew Gerrand319667f2015-02-04 16:04:07 +0000389 return err
390 }
391
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600392 if b.Source {
393 b.logf("Skipping build.")
Brad Fitzpatricke6f00552019-02-12 00:47:55 +0000394
395 // Remove unwanted top-level directories and verify only "go" remains:
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000396 if err := client.RemoveAll(ctx, "tmp", "gocache"); err != nil {
Brad Fitzpatricke6f00552019-02-12 00:47:55 +0000397 return err
398 }
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000399 if err := b.checkTopLevelDirs(ctx, client); err != nil {
Brad Fitzpatricke6f00552019-02-12 00:47:55 +0000400 return fmt.Errorf("verifying no unwanted top-level directories: %v", err)
401 }
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000402 if err := b.checkPerm(ctx, client); err != nil {
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400403 return fmt.Errorf("verifying file permissions: %v", err)
404 }
Brad Fitzpatricke6f00552019-02-12 00:47:55 +0000405
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400406 finalFilename := *version + "." + b.String() + ".tar.gz"
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000407 return b.fetchTarball(ctx, client, finalFilename)
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600408 }
409
Andrew Gerrand319667f2015-02-04 16:04:07 +0000410 // Set up build environment.
411 sep := "/"
412 if b.OS == "windows" {
413 sep = "\\"
414 }
Andrew Gerrand78810b02015-07-07 11:00:09 -0600415 env := append(bc.Env(),
416 "GOROOT_FINAL="+bc.GorootFinal(),
417 "GOROOT="+work+sep+goDir,
Andrew Gerrand78810b02015-07-07 11:00:09 -0600418 "GOPATH="+work+sep+goPath,
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600419 "GOBIN=",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600420 )
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100421
422 if b.Goarm > 0 {
423 env = append(env, fmt.Sprintf("GOARM=%d", b.Goarm))
Cherry Zhang297480d2017-01-22 19:01:43 -0500424 env = append(env, fmt.Sprintf("CGO_CFLAGS=-march=armv%d", b.Goarm))
425 env = append(env, fmt.Sprintf("CGO_LDFLAGS=-march=armv%d", b.Goarm))
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100426 }
427
Carlos Amedee5bb938e2020-01-24 16:07:47 -0500428 // Issues #36025 #35459
Carlos Amedee7ece5da2020-02-26 11:10:56 -0500429 if b.OS == "darwin" && b.Arch == "amd64" {
Carlos Amedee5bb938e2020-01-24 16:07:47 -0500430 minMacVersion := minSupportedMacOSVersion(*version)
431 env = append(env, fmt.Sprintf("CGO_CFLAGS=-mmacosx-version-min=%s", minMacVersion))
432 }
433
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400434 // Execute build (make.bash only first).
435 b.logf("Building (make.bash only).")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000436 out := new(bytes.Buffer)
Brad Fitzpatrickdcc7bc32015-12-17 14:53:55 -0800437 var execOut io.Writer = out
438 if *watch && *target != "" {
439 execOut = io.MultiWriter(out, os.Stdout)
440 }
Brad Fitzpatrick5a368652019-11-20 03:30:26 +0000441 remoteErr, err := client.Exec(context.Background(), filepath.Join(goDir, bc.MakeScript()), buildlet.ExecOpts{
Brad Fitzpatrickdcc7bc32015-12-17 14:53:55 -0800442 Output: execOut,
Andrew Gerrand319667f2015-02-04 16:04:07 +0000443 ExtraEnv: env,
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400444 Args: bc.MakeScriptArgs(),
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000445 })
446 if err != nil {
447 return err
448 }
449 if remoteErr != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000450 return fmt.Errorf("Build failed: %v\nOutput:\n%v", remoteErr, out)
451 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000452
Brad Fitzpatrick0cea2062019-04-10 14:13:33 +0000453 if err := b.checkRelocations(client); err != nil {
454 return err
455 }
456
Andrew Gerrand319667f2015-02-04 16:04:07 +0000457 goCmd := path.Join(goDir, "bin/go")
458 if b.OS == "windows" {
459 goCmd += ".exe"
460 }
461 runGo := func(args ...string) error {
462 out := new(bytes.Buffer)
Chris Broadfoote296e7e2015-12-17 15:18:14 -0800463 var execOut io.Writer = out
464 if *watch && *target != "" {
465 execOut = io.MultiWriter(out, os.Stdout)
466 }
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000467 cmdEnv := append([]string(nil), env...)
468 if len(args) > 0 && args[0] == "run" && hostArch != "" {
469 cmdEnv = setGOARCH(cmdEnv, hostArch)
470 }
Brad Fitzpatrick5a368652019-11-20 03:30:26 +0000471 remoteErr, err := client.Exec(context.Background(), goCmd, buildlet.ExecOpts{
Chris Broadfoote296e7e2015-12-17 15:18:14 -0800472 Output: execOut,
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100473 Dir: ".", // root of buildlet work directory
Andrew Gerrand319667f2015-02-04 16:04:07 +0000474 Args: args,
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000475 ExtraEnv: cmdEnv,
Andrew Gerrand319667f2015-02-04 16:04:07 +0000476 })
477 if err != nil {
478 return err
479 }
480 if remoteErr != nil {
481 return fmt.Errorf("go %v: %v\n%s", strings.Join(args, " "), remoteErr, out)
482 }
483 return nil
484 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000485
Andrew Gerrand319667f2015-02-04 16:04:07 +0000486 if b.Race {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600487 b.logf("Building race detector.")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000488
Andrew Gerrand319667f2015-02-04 16:04:07 +0000489 if err := runGo("install", "-race", "std"); err != nil {
490 return err
491 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000492 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000493
Brad Fitzpatrickbbe91e82018-10-24 19:05:40 +0000494 // postBuildCleanFiles are the list of files to remove in the go/ directory
495 // after things have been built.
496 postBuildCleanFiles := []string{
497 "VERSION.cache",
498 "pkg/bootstrap",
499 }
500
501 // Remove race detector *.syso files for other GOOS/GOARCHes (except for the source release).
502 if !b.Source {
503 okayRace := fmt.Sprintf("race_%s_%s.syso", b.OS, b.Arch)
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000504 err := client.ListDir(ctx, ".", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
Brad Fitzpatrickbbe91e82018-10-24 19:05:40 +0000505 name := strings.TrimPrefix(ent.Name(), "go/")
506 if strings.HasPrefix(name, "src/runtime/race/race_") &&
507 strings.HasSuffix(name, ".syso") &&
508 path.Base(name) != okayRace {
509 postBuildCleanFiles = append(postBuildCleanFiles, name)
510 }
511 })
512 if err != nil {
513 return fmt.Errorf("enumerating files to clean race syso files: %v", err)
514 }
515 }
516
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000517 b.logf("Cleaning goroot (post-build).")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000518 if err := client.RemoveAll(ctx, addPrefix(goDir, postBuildCleanFiles)...); err != nil {
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000519 return err
520 }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000521 // Users don't need the api checker binary pre-built. It's
522 // used by tests, but all.bash builds it first.
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000523 if err := client.RemoveAll(ctx, b.toolDir()+"/api"); err != nil {
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000524 return err
525 }
Alexander Rakoczy6a30d042020-07-14 17:08:04 -0400526 // The oldlink tool is used for debugging differences during
527 // testing of the linker rewrite, and can be built by users
528 // if necessary. See issue 39509.
529 // This can be removed when oldlink is gone, likely once Go 1.16
530 // is no longer supported.
531 if err := client.RemoveAll(ctx, b.toolDir()+"/oldlink"); err != nil {
532 return err
533 }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000534 // Remove go/pkg/${GOOS}_${GOARCH}/cmd. This saves a bunch of
535 // space, and users don't typically rebuild cmd/compile,
536 // cmd/link, etc. If they want to, they still can, but they'll
537 // have to pay the cost of rebuilding dependent libaries. No
538 // need to ship them just in case.
Brad Fitzpatrickc3605022019-01-31 23:54:08 +0000539 //
540 // Also remove go/pkg/${GOOS}_${GOARCH}_{dynlink,shared,testcshared_shared}
541 // per Issue 20038.
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000542 if err := client.RemoveAll(ctx,
Brad Fitzpatrickc3605022019-01-31 23:54:08 +0000543 b.pkgDir()+"/cmd",
544 b.pkgDir()+"_dynlink",
545 b.pkgDir()+"_shared",
546 b.pkgDir()+"_testcshared_shared",
547 ); err != nil {
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000548 return err
549 }
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000550
Andrew Gerrand78810b02015-07-07 11:00:09 -0600551 b.logf("Pushing and running releaselet.")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000552 err = client.Put(ctx, strings.NewReader(releaselet), "releaselet.go", 0666)
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100553 if err != nil {
554 return err
555 }
Andrew Gerrandce7e7fd2015-08-06 04:28:33 +0000556 if err := runGo("run", "releaselet.go"); err != nil {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000557 log.Printf("releaselet failed: %v", err)
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000558 client.ListDir(ctx, ".", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000559 log.Printf("remote: %v", ent)
560 })
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100561 return err
562 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000563
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000564 cleanFiles := []string{"releaselet.go", goPath, go14, "tmp", "gocache"}
Andrew Gerrand78810b02015-07-07 11:00:09 -0600565
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400566 // So far, we've run make.bash. We want to create the release archive next.
567 // Since the release archive hasn't been tested yet, place it in a temporary
568 // location. After all.bash runs successfully (or gets explicitly skipped),
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400569 // we'll move the release archive to its final location. For TestOnly builds,
570 // we only care whether tests passed and do not produce release artifacts.
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400571 type releaseFile struct {
572 Untested string // Temporary location of the file before the release has been tested.
573 Final string // Final location where to move the file after the release has been tested.
574 }
575 var releases []releaseFile
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400576 stagingDir := *stagingDir
577 if stagingDir == "" {
578 var err error
Dmitri Shuralyov83da5c52019-08-22 10:30:51 -0400579 stagingDir, err = ioutil.TempDir("", "go-release-staging_")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400580 if err != nil {
581 log.Fatal(err)
582 }
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400583 }
584 stagingFile := func(ext string) string {
585 return filepath.Join(stagingDir, *version+"."+b.String()+ext+".untested")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400586 }
587
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400588 if !b.TestOnly && b.OS == "windows" {
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400589 untested := stagingFile(".msi")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400590 if err := b.fetchFile(client, untested, "msi"); err != nil {
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000591 return err
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600592 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400593 releases = append(releases, releaseFile{
594 Untested: untested,
595 Final: *version + "." + b.String() + ".msi",
596 })
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400597 }
598
599 if b.OS == "windows" {
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000600 cleanFiles = append(cleanFiles, "msi")
Andrew Gerrand78810b02015-07-07 11:00:09 -0600601 }
Dmitri Shuralyov0f4c55b2021-06-01 17:58:34 -0400602 if b.OS == "windows" && b.Arch == "arm64" {
603 // At least on windows-arm64, 'wix/winterop.dll' gets created.
604 // Delete the entire wix directory since it's unrelated to Go.
605 cleanFiles = append(cleanFiles, "wix")
606 }
Andrew Gerrand78810b02015-07-07 11:00:09 -0600607
Andrew Gerrand319667f2015-02-04 16:04:07 +0000608 // Need to delete everything except the final "go" directory,
609 // as we make the tarball relative to workdir.
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000610 b.logf("Cleaning workdir.")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000611 if err := client.RemoveAll(ctx, cleanFiles...); err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000612 return err
613 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000614
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000615 // And verify there's no other top-level stuff besides the "go" directory:
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000616 if err := b.checkTopLevelDirs(ctx, client); err != nil {
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000617 return fmt.Errorf("verifying no unwanted top-level directories: %v", err)
618 }
619
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000620 if err := b.checkPerm(ctx, client); err != nil {
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400621 return fmt.Errorf("verifying file permissions: %v", err)
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000622 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400623
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400624 switch {
625 case !b.TestOnly && b.OS != "windows":
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400626 untested := stagingFile(".tar.gz")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000627 if err := b.fetchTarball(ctx, client, untested); err != nil {
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400628 return fmt.Errorf("fetching and writing tarball: %v", err)
629 }
630 releases = append(releases, releaseFile{
631 Untested: untested,
632 Final: *version + "." + b.String() + ".tar.gz",
633 })
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400634 case !b.TestOnly && b.OS == "windows":
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400635 untested := stagingFile(".zip")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400636 if err := b.fetchZip(client, untested); err != nil {
637 return fmt.Errorf("fetching and writing zip: %v", err)
638 }
639 releases = append(releases, releaseFile{
640 Untested: untested,
641 Final: *version + "." + b.String() + ".zip",
642 })
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400643 case b.TestOnly:
644 // Use an empty .test-only file to indicate the test outcome.
645 // This file gets moved from its initial location in the
646 // release-staging directory to the final release directory
647 // when the test-only build passes tests successfully.
648 untested := stagingFile(".test-only")
649 if err := ioutil.WriteFile(untested, nil, 0600); err != nil {
650 return fmt.Errorf("writing empty test-only file: %v", err)
651 }
652 releases = append(releases, releaseFile{
653 Untested: untested,
654 Final: *version + "." + b.String() + ".test-only",
655 })
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400656 }
657
658 // Execute build (all.bash) if running tests.
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400659 if *skipTests || b.SkipTests {
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400660 b.logf("Skipping all.bash tests.")
661 } else {
662 if u := bc.GoBootstrapURL(buildEnv); u != "" {
663 b.logf("Installing go1.4 (second time, for all.bash).")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000664 if err := client.PutTarFromURL(ctx, u, go14); err != nil {
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400665 return err
666 }
667 }
668
669 b.logf("Building (all.bash to ensure tests pass).")
670 out := new(bytes.Buffer)
671 var execOut io.Writer = out
672 if *watch && *target != "" {
673 execOut = io.MultiWriter(out, os.Stdout)
674 }
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000675 remoteErr, err := client.Exec(ctx, filepath.Join(goDir, bc.AllScript()), buildlet.ExecOpts{
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400676 Output: execOut,
677 ExtraEnv: env,
678 Args: bc.AllScriptArgs(),
679 })
680 if err != nil {
681 return err
682 }
683 if remoteErr != nil {
684 return fmt.Errorf("Build failed: %v\nOutput:\n%v", remoteErr, out)
685 }
686 }
687
688 // If we get this far, the all.bash tests have passed (or been skipped).
689 // Move untested release files to their final locations.
690 for _, r := range releases {
691 b.logf("Moving %q to %q.", r.Untested, r.Final)
692 if err := os.Rename(r.Untested, r.Final); err != nil {
693 return err
694 }
695 }
696 return nil
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600697}
698
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000699// checkTopLevelDirs checks that all files under client's "."
700// ($WORKDIR) are are under "go/".
Carlos Amedeef8a16ea2021-12-14 18:17:24 -0500701func (b *Build) checkTopLevelDirs(ctx context.Context, client buildlet.Client) error {
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000702 var badFileErr error // non-nil once an unexpected file/dir is found
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000703 if err := client.ListDir(ctx, ".", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000704 name := ent.Name()
705 if !(strings.HasPrefix(name, "go/") || strings.HasPrefix(name, `go\`)) {
Brad Fitzpatrick9fd15fa2019-01-24 05:41:21 +0000706 b.logf("unexpected file: %q", name)
707 if badFileErr == nil {
708 badFileErr = fmt.Errorf("unexpected filename %q found after cleaning", name)
709 }
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000710 }
711 }); err != nil {
712 return err
713 }
714 return badFileErr
715}
716
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400717// checkPerm checks that files in client's $WORKDIR/go directory
718// have expected permissions.
Carlos Amedeef8a16ea2021-12-14 18:17:24 -0500719func (b *Build) checkPerm(ctx context.Context, client buildlet.Client) error {
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400720 var badPermErr error // non-nil once an unexpected perm is found
721 checkPerm := func(ent buildlet.DirEntry, allowed ...string) {
722 for _, p := range allowed {
723 if ent.Perm() == p {
724 return
725 }
726 }
727 b.logf("unexpected file %q perm: %q", ent.Name(), ent.Perm())
728 if badPermErr == nil {
729 badPermErr = fmt.Errorf("unexpected file %q perm %q found", ent.Name(), ent.Perm())
730 }
731 }
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000732 if err := client.ListDir(ctx, "go", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400733 switch b.OS {
734 default:
735 checkPerm(ent, "drwxr-xr-x", "-rw-r--r--", "-rwxr-xr-x")
736 case "windows":
737 checkPerm(ent, "drwxrwxrwx", "-rw-rw-rw-")
738 }
739 }); err != nil {
740 return err
741 }
742 if !b.Source {
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000743 if err := client.ListDir(ctx, "go/bin", buildlet.ListDirOpts{}, func(ent buildlet.DirEntry) {
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400744 switch b.OS {
745 default:
746 checkPerm(ent, "-rwxr-xr-x")
747 case "windows":
748 checkPerm(ent, "-rw-rw-rw-")
749 }
750 }); err != nil {
751 return err
752 }
753 }
754 return badPermErr
755}
756
Carlos Amedeef8a16ea2021-12-14 18:17:24 -0500757func (b *Build) fetchTarball(ctx context.Context, client buildlet.Client, dest string) error {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600758 b.logf("Downloading tarball.")
Brad Fitzpatrickd4e4f4e2019-11-20 16:34:11 +0000759 tgz, err := client.GetTar(ctx, ".")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000760 if err != nil {
761 return err
762 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400763 return b.writeFile(dest, tgz)
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600764}
765
Carlos Amedeef8a16ea2021-12-14 18:17:24 -0500766func (b *Build) fetchZip(client buildlet.Client, dest string) error {
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000767 b.logf("Downloading tarball and re-compressing as zip.")
768
Kevin Burke392d3a92017-02-12 01:08:39 -0800769 tgz, err := client.GetTar(context.Background(), ".")
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000770 if err != nil {
771 return err
772 }
773 defer tgz.Close()
774
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400775 f, err := os.Create(dest)
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000776 if err != nil {
777 return err
778 }
779 if err := tgzToZip(f, tgz); err != nil {
780 f.Close()
781 return err
782 }
783 if err := f.Close(); err != nil {
784 return err
785 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400786 b.logf("Wrote %q.", dest)
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000787 return nil
788}
789
790func tgzToZip(w io.Writer, r io.Reader) error {
791 zr, err := gzip.NewReader(r)
792 if err != nil {
793 return err
794 }
795 tr := tar.NewReader(zr)
796
797 zw := zip.NewWriter(w)
798 for {
799 th, err := tr.Next()
800 if err == io.EOF {
801 break
802 }
803 if err != nil {
804 return err
805 }
806 fi := th.FileInfo()
807 zh, err := zip.FileInfoHeader(fi)
808 if err != nil {
809 return err
810 }
811 zh.Name = th.Name // for the full path
812 switch strings.ToLower(path.Ext(zh.Name)) {
813 case ".jpg", ".jpeg", ".png", ".gif":
814 // Don't re-compress already compressed files.
815 zh.Method = zip.Store
816 default:
817 zh.Method = zip.Deflate
818 }
819 if fi.IsDir() {
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000820 zh.Method = zip.Store
821 }
822 w, err := zw.CreateHeader(zh)
823 if err != nil {
824 return err
825 }
826 if fi.IsDir() {
827 continue
828 }
829 if _, err := io.Copy(w, tr); err != nil {
830 return err
831 }
832 }
833 return zw.Close()
834}
835
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600836// fetchFile fetches the specified directory from the given buildlet, and
837// writes the first file it finds in that directory to dest.
Carlos Amedeef8a16ea2021-12-14 18:17:24 -0500838func (b *Build) fetchFile(client buildlet.Client, dest, dir string) error {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600839 b.logf("Downloading file from %q.", dir)
Kevin Burke392d3a92017-02-12 01:08:39 -0800840 tgz, err := client.GetTar(context.Background(), dir)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000841 if err != nil {
842 return err
843 }
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600844 defer tgz.Close()
845 zr, err := gzip.NewReader(tgz)
846 if err != nil {
847 return err
848 }
849 tr := tar.NewReader(zr)
850 for {
851 h, err := tr.Next()
852 if err == io.EOF {
853 return io.ErrUnexpectedEOF
854 }
855 if err != nil {
856 return err
857 }
858 if !h.FileInfo().IsDir() {
859 break
860 }
861 }
862 return b.writeFile(dest, tr)
863}
864
865func (b *Build) writeFile(name string, r io.Reader) error {
866 f, err := os.Create(name)
867 if err != nil {
868 return err
869 }
870 if _, err := io.Copy(f, r); err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000871 f.Close()
872 return err
873 }
874 if err := f.Close(); err != nil {
875 return err
876 }
Brad Fitzpatrickb5038352017-02-13 18:15:23 +0000877 if strings.HasSuffix(name, ".gz") {
878 if err := verifyGzipSingleStream(name); err != nil {
879 return fmt.Errorf("error verifying that %s is a single-stream gzip: %v", name, err)
880 }
881 }
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600882 b.logf("Wrote %q.", name)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000883 return nil
884}
885
Brad Fitzpatrick0cea2062019-04-10 14:13:33 +0000886// checkRelocations runs readelf on pkg/linux_amd64/runtime/cgo.a and makes sure
Dmitri Shuralyov43ea6942021-02-19 12:17:28 -0500887// we don't see R_X86_64_REX_GOTPCRELX in new Go 1.15 minor releases.
Dmitri Shuralyovb0441a62020-12-15 12:11:20 -0500888// See golang.org/issue/31293 and golang.org/issue/40561#issuecomment-731482962.
Carlos Amedeef8a16ea2021-12-14 18:17:24 -0500889func (b *Build) checkRelocations(client buildlet.Client) error {
Dmitri Shuralyove566a702020-05-18 19:06:44 -0400890 if b.OS != "linux" || b.Arch != "amd64" || b.TestOnly {
891 // This check is only applicable to linux/amd64 builds.
892 // However, skip it on test-only builds because they
893 // don't produce binaries that are shipped to users.
Brad Fitzpatrick0cea2062019-04-10 14:13:33 +0000894 return nil
895 }
896 var out bytes.Buffer
897 file := fmt.Sprintf("go/pkg/linux_%s/runtime/cgo.a", b.Arch)
Brad Fitzpatrick5a368652019-11-20 03:30:26 +0000898 remoteErr, err := client.Exec(context.Background(), "readelf", buildlet.ExecOpts{
Brad Fitzpatrick0cea2062019-04-10 14:13:33 +0000899 Output: &out,
900 Args: []string{"-r", "--wide", file},
901 SystemLevel: true, // look for readelf in system's PATH
902 })
903 if err != nil {
904 return fmt.Errorf("failed to run readelf: %v", err)
905 }
906 got := out.String()
Dmitri Shuralyovb0441a62020-12-15 12:11:20 -0500907 switch {
908 default: // Go 1.16 and newer.
909 // Note: This check was kept and updated for Go 1.16, since it wasn't hard.
910 // Remove it at some point in the future if it becomes no longer useful or
911 // overly expensive to maintain.
912 if strings.Contains(got, "R_X86_64_GOTPCREL") {
913 return fmt.Errorf("%s contained a R_X86_64_GOTPCREL relocation", file)
914 }
915 if !strings.Contains(got, "R_X86_64_REX_GOTPCRELX") {
916 return fmt.Errorf("%s did not contain a R_X86_64_REX_GOTPCRELX relocation; remoteErr=%v, %s", file, remoteErr, got)
917 }
Dmitri Shuralyov43ea6942021-02-19 12:17:28 -0500918 case strings.HasPrefix(*version, "go1.15"):
Dmitri Shuralyovb0441a62020-12-15 12:11:20 -0500919 if strings.Contains(got, "R_X86_64_REX_GOTPCRELX") {
920 return fmt.Errorf("%s contained a R_X86_64_REX_GOTPCRELX relocation", file)
921 }
922 if !strings.Contains(got, "R_X86_64_GOTPCREL") {
923 return fmt.Errorf("%s did not contain a R_X86_64_GOTPCREL relocation; remoteErr=%v, %s", file, remoteErr, got)
924 }
Brad Fitzpatrick0cea2062019-04-10 14:13:33 +0000925 }
926 return nil
927}
928
Brad Fitzpatrickb5038352017-02-13 18:15:23 +0000929// verifyGzipSingleStream verifies that the named gzip file is not
930// a multi-stream file. See golang.org/issue/19052
931func verifyGzipSingleStream(name string) error {
932 f, err := os.Open(name)
933 if err != nil {
934 return err
935 }
936 defer f.Close()
937 br := bufio.NewReader(f)
938 zr, err := gzip.NewReader(br)
939 if err != nil {
940 return err
941 }
942 zr.Multistream(false)
943 if _, err := io.Copy(ioutil.Discard, zr); err != nil {
944 return fmt.Errorf("reading first stream: %v", err)
945 }
946 peek, err := br.Peek(1)
947 if len(peek) > 0 || err != io.EOF {
948 return fmt.Errorf("unexpected peek of %d, %v after first gzip stream", len(peek), err)
949 }
950 return nil
951}
952
Andrew Gerrand319667f2015-02-04 16:04:07 +0000953func addPrefix(prefix string, in []string) []string {
954 var out []string
955 for _, s := range in {
956 out = append(out, path.Join(prefix, s))
957 }
958 return out
959}
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700960
961func coordinatorClient() *buildlet.CoordinatorClient {
962 return &buildlet.CoordinatorClient{
963 Auth: buildlet.UserPass{
964 Username: "user-" + *user,
965 Password: userToken(),
966 },
Andrew Gerrand8e28dc92016-03-22 09:05:52 +1100967 Instance: build.ProdCoordinator,
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700968 }
969}
970
971func homeDir() string {
972 if runtime.GOOS == "windows" {
973 return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
974 }
975 return os.Getenv("HOME")
976}
977
978func configDir() string {
979 if runtime.GOOS == "windows" {
980 return filepath.Join(os.Getenv("APPDATA"), "Gomote")
981 }
982 if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" {
983 return filepath.Join(xdg, "gomote")
984 }
985 return filepath.Join(homeDir(), ".config", "gomote")
986}
987
988func username() string {
989 if runtime.GOOS == "windows" {
990 return os.Getenv("USERNAME")
991 }
992 return os.Getenv("USER")
993}
994
995func userToken() string {
996 if *user == "" {
997 panic("userToken called with user flag empty")
998 }
999 keyDir := configDir()
1000 baseFile := "user-" + *user + ".token"
1001 tokenFile := filepath.Join(keyDir, baseFile)
1002 slurp, err := ioutil.ReadFile(tokenFile)
1003 if os.IsNotExist(err) {
1004 log.Printf("Missing file %s for user %q. Change --user or obtain a token and place it there.",
1005 tokenFile, *user)
1006 }
1007 if err != nil {
1008 log.Fatal(err)
1009 }
1010 return strings.TrimSpace(string(slurp))
1011}
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +00001012
1013func setGOARCH(env []string, goarch string) []string {
1014 wantKV := "GOARCH=" + goarch
1015 existing := false
1016 for i, kv := range env {
1017 if strings.HasPrefix(kv, "GOARCH=") && kv != wantKV {
1018 env[i] = wantKV
1019 existing = true
1020 }
1021 }
1022 if existing {
1023 return env
1024 }
1025 return append(env, wantKV)
1026}
Brad Fitzpatrick790500f2018-10-19 15:15:16 -07001027
Carlos Amedee5bb938e2020-01-24 16:07:47 -05001028// minSupportedMacOSVersion provides the minimum supported macOS
Carlos Amedee7ece5da2020-02-26 11:10:56 -05001029// version (of the form N.M) for supported Go versions.
Carlos Amedee5bb938e2020-01-24 16:07:47 -05001030func minSupportedMacOSVersion(goVer string) string {
Dmitri Shuralyov56b7eea2020-08-03 23:22:08 -04001031 // TODO(amedee,dmitshur,golang.org/issue/40558): Use a version package to compare versions of Go.
Carlos Amedee5bb938e2020-01-24 16:07:47 -05001032
1033 // The minimum supported version of macOS with each version of go:
Dmitri Shuralyov90d5e7c2020-12-07 22:31:50 -05001034 // go1.16 - macOS 10.12
Dmitri Shuralyov43ea6942021-02-19 12:17:28 -05001035 // go1.17 - macOS 10.13
Carlos Amedee6883e812021-11-19 10:03:57 -05001036 // go1.18 - macOS 10.13
Dmitri Shuralyov43ea6942021-02-19 12:17:28 -05001037 minMacVersion := "10.13"
1038 if match("< go1.17beta1", goVer) {
1039 minMacVersion = "10.12"
Carlos Amedee5bb938e2020-01-24 16:07:47 -05001040 return minMacVersion
1041 }
1042 return minMacVersion
1043}
Dmitri Shuralyov56b7eea2020-08-03 23:22:08 -04001044
1045// match reports whether the Go version goVer matches the provided version query.
1046// The empty query matches all Go versions.
1047// match panics if given a query that it doesn't support.
1048func match(query, goVer string) bool {
1049 // TODO(golang.org/issue/40558): This should help inform the API for a Go version parser.
1050 switch query {
1051 case "": // A special case to make the zero Build.GoQuery value useful.
1052 return true
Carlos Amedee6883e812021-11-19 10:03:57 -05001053 case ">= go1.18beta1":
1054 return !strings.HasPrefix(goVer, "go1.17") && !strings.HasPrefix(goVer, "go1.16")
1055 case "< go1.18beta1":
1056 return strings.HasPrefix(goVer, "go1.17") || strings.HasPrefix(goVer, "go1.16")
Carlos Amedee63087352021-04-30 17:38:39 -04001057 case ">= go1.17beta1":
Carlos Amedee6883e812021-11-19 10:03:57 -05001058 return !strings.HasPrefix(goVer, "go1.16")
Dmitri Shuralyov43ea6942021-02-19 12:17:28 -05001059 case "< go1.17beta1":
Carlos Amedee6883e812021-11-19 10:03:57 -05001060 return strings.HasPrefix(goVer, "go1.16")
1061 case ">= go1.17beta1 && < go1.18beta1":
1062 return strings.HasPrefix(goVer, "go1.17")
Dmitri Shuralyov56b7eea2020-08-03 23:22:08 -04001063 default:
1064 panic(fmt.Errorf("match: query %q is not supported", query))
1065 }
1066}