blob: 09e0c7f950bee22868112e7b9a5555c99830e488 [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 toolsRev = flag.String("tools", "", "Tools revision to build")
46 tourRev = flag.String("tour", "master", "Tour revision to include")
Andrew Gerrandde0661e2015-07-13 11:18:56 -060047 netRev = flag.String("net", "master", "Net revision to include")
48 version = flag.String("version", "", "Version string (go1.5.2)")
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100049 user = flag.String("user", username(), "coordinator username, appended to 'user-'")
Brad Fitzpatrickba6d1092015-12-17 14:21:30 -080050 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 +000051
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100052 uploadMode = flag.Bool("upload", false, "Upload files (exclusive to all other flags)")
Chris Broadfoot71359ad2017-10-24 12:52:01 -070053 uploadKick = flag.String("edge_kick_command", "", "Command to run to kick off an edge cache update")
Andrew Gerrand15af43e2015-02-11 11:47:03 +110054)
Andrew Gerrand319667f2015-02-04 16:04:07 +000055
Andrew Gerrand8e28dc92016-03-22 09:05:52 +110056var (
57 coordClient *buildlet.CoordinatorClient
58 buildEnv *buildenv.Environment
59)
Brad Fitzpatrick4b956612015-07-07 09:57:08 -070060
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100061func main() {
62 flag.Parse()
Andrew Bonventre82242412017-09-11 14:22:38 -040063 rand.Seed(time.Now().UnixNano())
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100064
65 if *uploadMode {
Brad Fitzpatrickf7da0f82018-08-20 22:49:40 +000066 buildenv.CheckUserCredentials()
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100067 if err := upload(flag.Args()); err != nil {
68 log.Fatal(err)
69 }
70 return
71 }
72
Filippo Valsorda702928c2018-12-12 14:37:02 -050073 if (*rev == "" && *tarball == "") || (*rev != "" && *tarball != "") {
Brad Fitzpatrick5bd98932019-04-29 17:28:21 +000074 log.Fatal("must specify one of -rev or -tarball")
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100075 }
76 if *version == "" {
Brad Fitzpatrick5bd98932019-04-29 17:28:21 +000077 log.Fatal(`must specify -version flag (such as "go1.12" or "go1.13beta1")`)
78 }
79 if *toolsRev == "" && (versionIncludesGodoc(*version) || versionIncludesTour(*version)) {
80 log.Fatal("must specify -tools flag")
Andrew Gerrand063dc2f2015-07-22 17:21:16 +100081 }
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 Gerrand319667f2015-02-04 16:04:07 +0000111type Build struct {
112 OS, Arch string
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600113 Source bool
Andrew Gerrand319667f2015-02-04 16:04:07 +0000114
Chris Broadfootc13f7d22015-12-17 14:02:46 -0800115 Race bool // Build race detector.
Andrew Gerrand319667f2015-02-04 16:04:07 +0000116
117 Builder string // Key for dashboard.Builders.
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100118
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000119 Goarm int // GOARM value if set.
120 MakeOnly bool // don't run tests; needed by cross-compile builders (s390x)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000121}
122
Andrew Gerrand319667f2015-02-04 16:04:07 +0000123func (b *Build) String() string {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600124 if b.Source {
125 return "src"
126 }
Chris Broadfootf84ad522015-12-17 16:18:20 -0800127 if b.Goarm != 0 {
Shenghou Ma558ac4f2015-12-20 02:04:40 -0500128 return fmt.Sprintf("%v-%vv%vl", b.OS, b.Arch, b.Goarm)
Chris Broadfootf84ad522015-12-17 16:18:20 -0800129 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000130 return fmt.Sprintf("%v-%v", b.OS, b.Arch)
131}
132
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000133func (b *Build) toolDir() string { return "go/pkg/tool/" + b.OS + "_" + b.Arch }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000134func (b *Build) pkgDir() string { return "go/pkg/" + b.OS + "_" + b.Arch }
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000135
Andrew Gerrand78810b02015-07-07 11:00:09 -0600136func (b *Build) logf(format string, args ...interface{}) {
137 format = fmt.Sprintf("%v: %s", b, format)
138 log.Printf(format, args...)
139}
140
Andrew Gerrand319667f2015-02-04 16:04:07 +0000141var builds = []*Build{
142 {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600143 Source: true,
Brad Fitzpatrick1fe20772019-04-09 01:48:33 +0000144 Builder: "linux-amd64",
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600145 },
146 {
Andrew Gerrand319667f2015-02-04 16:04:07 +0000147 OS: "linux",
148 Arch: "386",
Andrew Gerrand9fb312f2015-07-07 21:46:45 -0600149 Builder: "linux-386",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000150 },
151 {
152 OS: "linux",
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100153 Arch: "arm",
154 Builder: "linux-arm",
155 Goarm: 6, // for compatibility with all Raspberry Pi models.
Russ Cox7b0d8a82017-10-25 16:03:51 -0400156 // The tests take too long for the release packaging.
157 // Much of the time the whole buildlet times out.
158 MakeOnly: true,
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100159 },
160 {
161 OS: "linux",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000162 Arch: "amd64",
163 Race: true,
Brad Fitzpatrick1fe20772019-04-09 01:48:33 +0000164 Builder: "linux-amd64-jessie", // using Jessie for at least [Go 1.11, Go 1.13] due to golang.org/issue/31336
Andrew Gerrand319667f2015-02-04 16:04:07 +0000165 },
166 {
Brad Fitzpatrick07714b02017-06-15 19:46:22 +0000167 OS: "linux",
168 Arch: "arm64",
169 Builder: "linux-arm64-packet",
170 },
171 {
Andrew Gerrand319667f2015-02-04 16:04:07 +0000172 OS: "freebsd",
173 Arch: "386",
Brad Fitzpatrick873c4122017-11-28 21:51:29 +0000174 Builder: "freebsd-386-11_1",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000175 },
176 {
177 OS: "freebsd",
178 Arch: "amd64",
179 Race: true,
Brad Fitzpatrick873c4122017-11-28 21:51:29 +0000180 Builder: "freebsd-amd64-11_1",
Andrew Gerrand319667f2015-02-04 16:04:07 +0000181 },
Andrew Gerrand78810b02015-07-07 11:00:09 -0600182 {
183 OS: "windows",
184 Arch: "386",
Chris Broadfootffc9f6c2017-08-07 13:50:52 -0700185 Builder: "windows-386-2008",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600186 },
187 {
188 OS: "windows",
189 Arch: "amd64",
190 Race: true,
Brad Fitzpatrick97a4f812017-04-24 20:32:02 +0000191 Builder: "windows-amd64-2008",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600192 },
193 {
194 OS: "darwin",
195 Arch: "amd64",
196 Race: true,
Chris Broadfoot51046002016-09-07 12:41:11 -0700197 Builder: "darwin-amd64-10_11",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600198 },
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000199 {
200 OS: "linux",
201 Arch: "s390x",
202 MakeOnly: true,
203 Builder: "linux-s390x-crosscompile",
204 },
Brad Fitzpatricka6cb7e42016-11-15 21:16:56 -0500205 // TODO(bradfitz): switch this ppc64 builder to a Kubernetes
206 // container cross-compiling ppc64 like the s390x one? For
207 // now, the ppc64le builders (5) are back, so let's see if we
208 // can just depend on them not going away.
209 {
210 OS: "linux",
211 Arch: "ppc64le",
212 MakeOnly: true,
213 Builder: "linux-ppc64le-buildlet",
214 },
Andrew Gerrand319667f2015-02-04 16:04:07 +0000215}
216
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000217var preBuildCleanFiles = []string{
218 ".gitattributes",
Andrew Gerrand82423c12016-07-05 09:22:29 +1000219 ".github",
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000220 ".gitignore",
221 ".hgignore",
222 ".hgtags",
223 "misc/dashboard",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600224 "misc/makerelease",
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000225}
226
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700227func (b *Build) buildlet() (*buildlet.Client, error) {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600228 b.logf("Creating buildlet.")
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700229 bc, err := coordClient.CreateBuildlet(b.Builder)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000230 if err != nil {
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700231 return nil, err
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000232 }
Brad Fitzpatrick1e7c6912017-02-13 17:38:27 +0000233 bc.SetReleaseMode(true) // disable pargzip; golang.org/issue/19052
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700234 return bc, nil
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700235}
236
Andrew Gerrand78810b02015-07-07 11:00:09 -0600237func (b *Build) make() error {
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700238 bc, ok := dashboard.Builders[b.Builder]
239 if !ok {
240 return fmt.Errorf("unknown builder: %v", bc)
241 }
242
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000243 var hostArch string // non-empty if we're cross-compiling (s390x)
Brad Fitzpatrick14d99732018-05-05 16:36:05 +0000244 if b.MakeOnly && bc.IsContainer() && (bc.GOARCH() != "amd64" && bc.GOARCH() != "386") {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000245 hostArch = "amd64"
246 }
247
Brad Fitzpatrick2742bc32015-07-03 16:20:37 -0700248 client, err := b.buildlet()
249 if err != nil {
250 return err
251 }
252 defer client.Close()
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000253
Andrew Gerrand319667f2015-02-04 16:04:07 +0000254 work, err := client.WorkDir()
255 if err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000256 return err
257 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000258
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400259 // Push source to buildlet.
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000260 b.logf("Pushing source to buildlet.")
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100261 const (
262 goDir = "go"
263 goPath = "gopath"
Andrew Gerrand78810b02015-07-07 11:00:09 -0600264 go14 = "go1.4"
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100265 )
Filippo Valsorda702928c2018-12-12 14:37:02 -0500266 if *tarball != "" {
267 tarFile, err := os.Open(*tarball)
268 if err != nil {
269 b.logf("failed to open tarball %q: %v", *tarball, err)
270 return err
271 }
272 if err := client.PutTar(tarFile, goDir); err != nil {
273 b.logf("failed to put tarball %q into dir %q: %v", *tarball, goDir, err)
274 return err
275 }
276 tarFile.Close()
277 } else {
278 tar := "https://go.googlesource.com/go/+archive/" + *rev + ".tar.gz"
279 if err := client.PutTarFromURL(tar, goDir); err != nil {
280 b.logf("failed to put tarball %q into dir %q: %v", tar, goDir, err)
281 return err
282 }
283 }
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100284 for _, r := range []struct {
285 repo, rev string
286 }{
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100287 {"tools", *toolsRev},
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100288 {"tour", *tourRev},
289 {"net", *netRev},
290 } {
Filippo Valsorda702928c2018-12-12 14:37:02 -0500291 if b.Source {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600292 continue
293 }
Brad Fitzpatrick790500f2018-10-19 15:15:16 -0700294 if r.repo == "tour" && !versionIncludesTour(*version) {
295 continue
296 }
Brad Fitzpatrick5bd98932019-04-29 17:28:21 +0000297 if (r.repo == "net" || r.repo == "tools") && !versionIncludesGodoc(*version) {
298 continue
299 }
Filippo Valsorda702928c2018-12-12 14:37:02 -0500300 dir := goPath + "/src/golang.org/x/" + r.repo
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100301 tar := "https://go.googlesource.com/" + r.repo + "/+archive/" + r.rev + ".tar.gz"
302 if err := client.PutTarFromURL(tar, dir); err != nil {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000303 b.logf("failed to put tarball %q into dir %q: %v", tar, dir, err)
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100304 return err
305 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000306 }
307
Andrew Gerrand8e28dc92016-03-22 09:05:52 +1100308 if u := bc.GoBootstrapURL(buildEnv); u != "" && !b.Source {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600309 b.logf("Installing go1.4.")
Andrew Gerrand8e28dc92016-03-22 09:05:52 +1100310 if err := client.PutTarFromURL(u, go14); err != nil {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600311 return err
312 }
313 }
314
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000315 // Write out version file.
316 b.logf("Writing VERSION file.")
317 if err := client.Put(strings.NewReader(*version), "go/VERSION", 0644); err != nil {
318 return err
319 }
320
Andrew Gerrand78810b02015-07-07 11:00:09 -0600321 b.logf("Cleaning goroot (pre-build).")
Andrew Gerrand319667f2015-02-04 16:04:07 +0000322 if err := client.RemoveAll(addPrefix(goDir, preBuildCleanFiles)...); err != nil {
323 return err
324 }
325
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600326 if b.Source {
327 b.logf("Skipping build.")
Brad Fitzpatricke6f00552019-02-12 00:47:55 +0000328
329 // Remove unwanted top-level directories and verify only "go" remains:
330 if err := client.RemoveAll("tmp", "gocache"); err != nil {
331 return err
332 }
333 if err := b.checkTopLevelDirs(client); err != nil {
334 return fmt.Errorf("verifying no unwanted top-level directories: %v", err)
335 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400336 if err := b.checkPerm(client); err != nil {
337 return fmt.Errorf("verifying file permissions: %v", err)
338 }
Brad Fitzpatricke6f00552019-02-12 00:47:55 +0000339
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400340 finalFilename := *version + "." + b.String() + ".tar.gz"
341 return b.fetchTarball(client, finalFilename)
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600342 }
343
Andrew Gerrand319667f2015-02-04 16:04:07 +0000344 // Set up build environment.
345 sep := "/"
346 if b.OS == "windows" {
347 sep = "\\"
348 }
Andrew Gerrand78810b02015-07-07 11:00:09 -0600349 env := append(bc.Env(),
350 "GOROOT_FINAL="+bc.GorootFinal(),
351 "GOROOT="+work+sep+goDir,
Andrew Gerrand78810b02015-07-07 11:00:09 -0600352 "GOPATH="+work+sep+goPath,
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600353 "GOBIN=",
Andrew Gerrand78810b02015-07-07 11:00:09 -0600354 )
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100355
356 if b.Goarm > 0 {
357 env = append(env, fmt.Sprintf("GOARM=%d", b.Goarm))
Cherry Zhang297480d2017-01-22 19:01:43 -0500358 env = append(env, fmt.Sprintf("CGO_CFLAGS=-march=armv%d", b.Goarm))
359 env = append(env, fmt.Sprintf("CGO_LDFLAGS=-march=armv%d", b.Goarm))
Dave Cheney25a7b0c2015-12-11 14:00:21 +1100360 }
361
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400362 // Execute build (make.bash only first).
363 b.logf("Building (make.bash only).")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000364 out := new(bytes.Buffer)
Brad Fitzpatrickdcc7bc32015-12-17 14:53:55 -0800365 var execOut io.Writer = out
366 if *watch && *target != "" {
367 execOut = io.MultiWriter(out, os.Stdout)
368 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400369 remoteErr, err := client.Exec(filepath.Join(goDir, bc.MakeScript()), buildlet.ExecOpts{
Brad Fitzpatrickdcc7bc32015-12-17 14:53:55 -0800370 Output: execOut,
Andrew Gerrand319667f2015-02-04 16:04:07 +0000371 ExtraEnv: env,
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400372 Args: bc.MakeScriptArgs(),
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000373 })
374 if err != nil {
375 return err
376 }
377 if remoteErr != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000378 return fmt.Errorf("Build failed: %v\nOutput:\n%v", remoteErr, out)
379 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000380
Brad Fitzpatrick0cea2062019-04-10 14:13:33 +0000381 if err := b.checkRelocations(client); err != nil {
382 return err
383 }
384
Andrew Gerrand319667f2015-02-04 16:04:07 +0000385 goCmd := path.Join(goDir, "bin/go")
386 if b.OS == "windows" {
387 goCmd += ".exe"
388 }
389 runGo := func(args ...string) error {
390 out := new(bytes.Buffer)
Chris Broadfoote296e7e2015-12-17 15:18:14 -0800391 var execOut io.Writer = out
392 if *watch && *target != "" {
393 execOut = io.MultiWriter(out, os.Stdout)
394 }
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000395 cmdEnv := append([]string(nil), env...)
396 if len(args) > 0 && args[0] == "run" && hostArch != "" {
397 cmdEnv = setGOARCH(cmdEnv, hostArch)
398 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000399 remoteErr, err := client.Exec(goCmd, buildlet.ExecOpts{
Chris Broadfoote296e7e2015-12-17 15:18:14 -0800400 Output: execOut,
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100401 Dir: ".", // root of buildlet work directory
Andrew Gerrand319667f2015-02-04 16:04:07 +0000402 Args: args,
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000403 ExtraEnv: cmdEnv,
Andrew Gerrand319667f2015-02-04 16:04:07 +0000404 })
405 if err != nil {
406 return err
407 }
408 if remoteErr != nil {
409 return fmt.Errorf("go %v: %v\n%s", strings.Join(args, " "), remoteErr, out)
410 }
411 return nil
412 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000413
Andrew Gerrand319667f2015-02-04 16:04:07 +0000414 if b.Race {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600415 b.logf("Building race detector.")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000416
Andrew Gerrand319667f2015-02-04 16:04:07 +0000417 if err := runGo("install", "-race", "std"); err != nil {
418 return err
419 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000420 }
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000421
Brad Fitzpatrick5bd98932019-04-29 17:28:21 +0000422 var toolPaths []string
423 if versionIncludesGodoc(*version) {
424 toolPaths = append(toolPaths, "golang.org/x/tools/cmd/godoc")
Brad Fitzpatrick790500f2018-10-19 15:15:16 -0700425 }
426 if versionIncludesTour(*version) {
427 toolPaths = append(toolPaths, "golang.org/x/tour")
428 }
Brad Fitzpatrick5bd98932019-04-29 17:28:21 +0000429 if len(toolPaths) > 0 {
430 b.logf("Building %v.", strings.Join(toolPaths, ", "))
431 if err := runGo(append([]string{"install"}, toolPaths...)...); err != nil {
432 return err
433 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000434 }
435
Brad Fitzpatrickbbe91e82018-10-24 19:05:40 +0000436 // postBuildCleanFiles are the list of files to remove in the go/ directory
437 // after things have been built.
438 postBuildCleanFiles := []string{
439 "VERSION.cache",
440 "pkg/bootstrap",
441 }
442
443 // Remove race detector *.syso files for other GOOS/GOARCHes (except for the source release).
444 if !b.Source {
445 okayRace := fmt.Sprintf("race_%s_%s.syso", b.OS, b.Arch)
446 err := client.ListDir(".", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
447 name := strings.TrimPrefix(ent.Name(), "go/")
448 if strings.HasPrefix(name, "src/runtime/race/race_") &&
449 strings.HasSuffix(name, ".syso") &&
450 path.Base(name) != okayRace {
451 postBuildCleanFiles = append(postBuildCleanFiles, name)
452 }
453 })
454 if err != nil {
455 return fmt.Errorf("enumerating files to clean race syso files: %v", err)
456 }
457 }
458
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000459 b.logf("Cleaning goroot (post-build).")
460 if err := client.RemoveAll(addPrefix(goDir, postBuildCleanFiles)...); err != nil {
461 return err
462 }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000463 // Users don't need the api checker binary pre-built. It's
464 // used by tests, but all.bash builds it first.
Brad Fitzpatricka2a69082015-11-11 17:34:48 +0000465 if err := client.RemoveAll(b.toolDir() + "/api"); err != nil {
466 return err
467 }
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000468 // Remove go/pkg/${GOOS}_${GOARCH}/cmd. This saves a bunch of
469 // space, and users don't typically rebuild cmd/compile,
470 // cmd/link, etc. If they want to, they still can, but they'll
471 // have to pay the cost of rebuilding dependent libaries. No
472 // need to ship them just in case.
Brad Fitzpatrickc3605022019-01-31 23:54:08 +0000473 //
474 // Also remove go/pkg/${GOOS}_${GOARCH}_{dynlink,shared,testcshared_shared}
475 // per Issue 20038.
476 if err := client.RemoveAll(
477 b.pkgDir()+"/cmd",
478 b.pkgDir()+"_dynlink",
479 b.pkgDir()+"_shared",
480 b.pkgDir()+"_testcshared_shared",
481 ); err != nil {
Brad Fitzpatrick5e1479f2018-08-20 17:17:18 +0000482 return err
483 }
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000484
Andrew Gerrand78810b02015-07-07 11:00:09 -0600485 b.logf("Pushing and running releaselet.")
Dmitri Shuralyovded33d32019-08-10 15:16:18 -0400486 err = client.Put(strings.NewReader(releaselet), "releaselet.go", 0666)
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100487 if err != nil {
488 return err
489 }
Andrew Gerrandce7e7fd2015-08-06 04:28:33 +0000490 if err := runGo("run", "releaselet.go"); err != nil {
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000491 log.Printf("releaselet failed: %v", err)
492 client.ListDir(".", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
493 log.Printf("remote: %v", ent)
494 })
Andrew Gerrand15af43e2015-02-11 11:47:03 +1100495 return err
496 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000497
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000498 cleanFiles := []string{"releaselet.go", goPath, go14, "tmp", "gocache"}
Andrew Gerrand78810b02015-07-07 11:00:09 -0600499
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400500 // So far, we've run make.bash. We want to create the release archive next.
501 // Since the release archive hasn't been tested yet, place it in a temporary
502 // location. After all.bash runs successfully (or gets explicitly skipped),
503 // we'll move the release archive to its final location.
504 type releaseFile struct {
505 Untested string // Temporary location of the file before the release has been tested.
506 Final string // Final location where to move the file after the release has been tested.
507 }
508 var releases []releaseFile
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400509 stagingDir := *stagingDir
510 if stagingDir == "" {
511 var err error
512 stagingDir, err = ioutil.TempDir("", "")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400513 if err != nil {
514 log.Fatal(err)
515 }
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400516 }
517 stagingFile := func(ext string) string {
518 return filepath.Join(stagingDir, *version+"."+b.String()+ext+".untested")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400519 }
520
Andrew Gerrand78810b02015-07-07 11:00:09 -0600521 switch b.OS {
522 case "darwin":
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400523 untested := stagingFile(".pkg")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400524 if err := b.fetchFile(client, untested, "pkg"); err != nil {
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600525 return err
526 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400527 releases = append(releases, releaseFile{
528 Untested: untested,
529 Final: *version + "." + b.String() + ".pkg",
530 })
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600531 cleanFiles = append(cleanFiles, "pkg")
Andrew Gerrand78810b02015-07-07 11:00:09 -0600532 case "windows":
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400533 untested := stagingFile(".msi")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400534 if err := b.fetchFile(client, untested, "msi"); err != nil {
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000535 return err
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600536 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400537 releases = append(releases, releaseFile{
538 Untested: untested,
539 Final: *version + "." + b.String() + ".msi",
540 })
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000541 cleanFiles = append(cleanFiles, "msi")
Andrew Gerrand78810b02015-07-07 11:00:09 -0600542 }
543
Andrew Gerrand319667f2015-02-04 16:04:07 +0000544 // Need to delete everything except the final "go" directory,
545 // as we make the tarball relative to workdir.
Andrew Gerrandba1664c2015-07-16 11:51:19 +1000546 b.logf("Cleaning workdir.")
Andrew Gerrand319667f2015-02-04 16:04:07 +0000547 if err := client.RemoveAll(cleanFiles...); err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000548 return err
549 }
Andrew Gerrand319667f2015-02-04 16:04:07 +0000550
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000551 // And verify there's no other top-level stuff besides the "go" directory:
Brad Fitzpatrick9fd15fa2019-01-24 05:41:21 +0000552 if err := b.checkTopLevelDirs(client); err != nil {
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000553 return fmt.Errorf("verifying no unwanted top-level directories: %v", err)
554 }
555
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400556 if err := b.checkPerm(client); err != nil {
557 return fmt.Errorf("verifying file permissions: %v", err)
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000558 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400559
560 switch b.OS {
561 default:
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400562 untested := stagingFile(".tar.gz")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400563 if err := b.fetchTarball(client, untested); err != nil {
564 return fmt.Errorf("fetching and writing tarball: %v", err)
565 }
566 releases = append(releases, releaseFile{
567 Untested: untested,
568 Final: *version + "." + b.String() + ".tar.gz",
569 })
570 case "windows":
Dmitri Shuralyov673ce342019-08-21 14:11:59 -0400571 untested := stagingFile(".zip")
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400572 if err := b.fetchZip(client, untested); err != nil {
573 return fmt.Errorf("fetching and writing zip: %v", err)
574 }
575 releases = append(releases, releaseFile{
576 Untested: untested,
577 Final: *version + "." + b.String() + ".zip",
578 })
579 }
580
581 // Execute build (all.bash) if running tests.
582 if *skipTests || b.MakeOnly {
583 b.logf("Skipping all.bash tests.")
584 } else {
585 if u := bc.GoBootstrapURL(buildEnv); u != "" {
586 b.logf("Installing go1.4 (second time, for all.bash).")
587 if err := client.PutTarFromURL(u, go14); err != nil {
588 return err
589 }
590 }
591
592 b.logf("Building (all.bash to ensure tests pass).")
593 out := new(bytes.Buffer)
594 var execOut io.Writer = out
595 if *watch && *target != "" {
596 execOut = io.MultiWriter(out, os.Stdout)
597 }
598 remoteErr, err := client.Exec(filepath.Join(goDir, bc.AllScript()), buildlet.ExecOpts{
599 Output: execOut,
600 ExtraEnv: env,
601 Args: bc.AllScriptArgs(),
602 })
603 if err != nil {
604 return err
605 }
606 if remoteErr != nil {
607 return fmt.Errorf("Build failed: %v\nOutput:\n%v", remoteErr, out)
608 }
609 }
610
611 // If we get this far, the all.bash tests have passed (or been skipped).
612 // Move untested release files to their final locations.
613 for _, r := range releases {
614 b.logf("Moving %q to %q.", r.Untested, r.Final)
615 if err := os.Rename(r.Untested, r.Final); err != nil {
616 return err
617 }
618 }
619 return nil
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600620}
621
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000622// checkTopLevelDirs checks that all files under client's "."
623// ($WORKDIR) are are under "go/".
Brad Fitzpatrick9fd15fa2019-01-24 05:41:21 +0000624func (b *Build) checkTopLevelDirs(client *buildlet.Client) error {
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000625 var badFileErr error // non-nil once an unexpected file/dir is found
626 if err := client.ListDir(".", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000627 name := ent.Name()
628 if !(strings.HasPrefix(name, "go/") || strings.HasPrefix(name, `go\`)) {
Brad Fitzpatrick9fd15fa2019-01-24 05:41:21 +0000629 b.logf("unexpected file: %q", name)
630 if badFileErr == nil {
631 badFileErr = fmt.Errorf("unexpected filename %q found after cleaning", name)
632 }
Brad Fitzpatrick36bd60d2019-01-23 22:57:20 +0000633 }
634 }); err != nil {
635 return err
636 }
637 return badFileErr
638}
639
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400640// checkPerm checks that files in client's $WORKDIR/go directory
641// have expected permissions.
642func (b *Build) checkPerm(client *buildlet.Client) error {
643 var badPermErr error // non-nil once an unexpected perm is found
644 checkPerm := func(ent buildlet.DirEntry, allowed ...string) {
645 for _, p := range allowed {
646 if ent.Perm() == p {
647 return
648 }
649 }
650 b.logf("unexpected file %q perm: %q", ent.Name(), ent.Perm())
651 if badPermErr == nil {
652 badPermErr = fmt.Errorf("unexpected file %q perm %q found", ent.Name(), ent.Perm())
653 }
654 }
655 if err := client.ListDir("go", buildlet.ListDirOpts{Recursive: true}, func(ent buildlet.DirEntry) {
656 switch b.OS {
657 default:
658 checkPerm(ent, "drwxr-xr-x", "-rw-r--r--", "-rwxr-xr-x")
659 case "windows":
660 checkPerm(ent, "drwxrwxrwx", "-rw-rw-rw-")
661 }
662 }); err != nil {
663 return err
664 }
665 if !b.Source {
666 if err := client.ListDir("go/bin", buildlet.ListDirOpts{}, func(ent buildlet.DirEntry) {
667 switch b.OS {
668 default:
669 checkPerm(ent, "-rwxr-xr-x")
670 case "windows":
671 checkPerm(ent, "-rw-rw-rw-")
672 }
673 }); err != nil {
674 return err
675 }
676 }
677 return badPermErr
678}
679
680func (b *Build) fetchTarball(client *buildlet.Client, dest string) error {
Andrew Gerrand78810b02015-07-07 11:00:09 -0600681 b.logf("Downloading tarball.")
Kevin Burke392d3a92017-02-12 01:08:39 -0800682 tgz, err := client.GetTar(context.Background(), ".")
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000683 if err != nil {
684 return err
685 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400686 return b.writeFile(dest, tgz)
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600687}
688
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400689func (b *Build) fetchZip(client *buildlet.Client, dest string) error {
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000690 b.logf("Downloading tarball and re-compressing as zip.")
691
Kevin Burke392d3a92017-02-12 01:08:39 -0800692 tgz, err := client.GetTar(context.Background(), ".")
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000693 if err != nil {
694 return err
695 }
696 defer tgz.Close()
697
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400698 f, err := os.Create(dest)
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000699 if err != nil {
700 return err
701 }
702 if err := tgzToZip(f, tgz); err != nil {
703 f.Close()
704 return err
705 }
706 if err := f.Close(); err != nil {
707 return err
708 }
Dmitri Shuralyov6225d662019-08-09 19:11:39 -0400709 b.logf("Wrote %q.", dest)
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000710 return nil
711}
712
713func tgzToZip(w io.Writer, r io.Reader) error {
714 zr, err := gzip.NewReader(r)
715 if err != nil {
716 return err
717 }
718 tr := tar.NewReader(zr)
719
720 zw := zip.NewWriter(w)
721 for {
722 th, err := tr.Next()
723 if err == io.EOF {
724 break
725 }
726 if err != nil {
727 return err
728 }
729 fi := th.FileInfo()
730 zh, err := zip.FileInfoHeader(fi)
731 if err != nil {
732 return err
733 }
734 zh.Name = th.Name // for the full path
735 switch strings.ToLower(path.Ext(zh.Name)) {
736 case ".jpg", ".jpeg", ".png", ".gif":
737 // Don't re-compress already compressed files.
738 zh.Method = zip.Store
739 default:
740 zh.Method = zip.Deflate
741 }
742 if fi.IsDir() {
Andrew Gerrandca5899f2015-07-23 12:30:44 +1000743 zh.Method = zip.Store
744 }
745 w, err := zw.CreateHeader(zh)
746 if err != nil {
747 return err
748 }
749 if fi.IsDir() {
750 continue
751 }
752 if _, err := io.Copy(w, tr); err != nil {
753 return err
754 }
755 }
756 return zw.Close()
757}
758
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600759// fetchFile fetches the specified directory from the given buildlet, and
760// writes the first file it finds in that directory to dest.
761func (b *Build) fetchFile(client *buildlet.Client, dest, dir string) error {
762 b.logf("Downloading file from %q.", dir)
Kevin Burke392d3a92017-02-12 01:08:39 -0800763 tgz, err := client.GetTar(context.Background(), dir)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000764 if err != nil {
765 return err
766 }
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600767 defer tgz.Close()
768 zr, err := gzip.NewReader(tgz)
769 if err != nil {
770 return err
771 }
772 tr := tar.NewReader(zr)
773 for {
774 h, err := tr.Next()
775 if err == io.EOF {
776 return io.ErrUnexpectedEOF
777 }
778 if err != nil {
779 return err
780 }
781 if !h.FileInfo().IsDir() {
782 break
783 }
784 }
785 return b.writeFile(dest, tr)
786}
787
788func (b *Build) writeFile(name string, r io.Reader) error {
789 f, err := os.Create(name)
790 if err != nil {
791 return err
792 }
793 if _, err := io.Copy(f, r); err != nil {
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000794 f.Close()
795 return err
796 }
797 if err := f.Close(); err != nil {
798 return err
799 }
Brad Fitzpatrickb5038352017-02-13 18:15:23 +0000800 if strings.HasSuffix(name, ".gz") {
801 if err := verifyGzipSingleStream(name); err != nil {
802 return fmt.Errorf("error verifying that %s is a single-stream gzip: %v", name, err)
803 }
804 }
Andrew Gerrandde0661e2015-07-13 11:18:56 -0600805 b.logf("Wrote %q.", name)
Andrew Gerrandf83f3e42015-02-02 12:05:01 +0000806 return nil
807}
808
Brad Fitzpatrick0cea2062019-04-10 14:13:33 +0000809// checkRelocations runs readelf on pkg/linux_amd64/runtime/cgo.a and makes sure
810// we don't see R_X86_64_REX_GOTPCRELX. See issue 31293.
811func (b *Build) checkRelocations(client *buildlet.Client) error {
812 if b.OS != "linux" || b.Arch != "amd64" {
813 return nil
814 }
815 var out bytes.Buffer
816 file := fmt.Sprintf("go/pkg/linux_%s/runtime/cgo.a", b.Arch)
817 remoteErr, err := client.Exec("readelf", buildlet.ExecOpts{
818 Output: &out,
819 Args: []string{"-r", "--wide", file},
820 SystemLevel: true, // look for readelf in system's PATH
821 })
822 if err != nil {
823 return fmt.Errorf("failed to run readelf: %v", err)
824 }
825 got := out.String()
826 if strings.Contains(got, "R_X86_64_REX_GOTPCRELX") {
827 return fmt.Errorf("%s contained a R_X86_64_REX_GOTPCRELX relocation", file)
828 }
829 if !strings.Contains(got, "R_X86_64_GOTPCREL") {
830 return fmt.Errorf("%s did not contain a R_X86_64_GOTPCREL relocation; remoteErr=%v, %s", file, remoteErr, got)
831 }
832 return nil
833}
834
Brad Fitzpatrickb5038352017-02-13 18:15:23 +0000835// verifyGzipSingleStream verifies that the named gzip file is not
836// a multi-stream file. See golang.org/issue/19052
837func verifyGzipSingleStream(name string) error {
838 f, err := os.Open(name)
839 if err != nil {
840 return err
841 }
842 defer f.Close()
843 br := bufio.NewReader(f)
844 zr, err := gzip.NewReader(br)
845 if err != nil {
846 return err
847 }
848 zr.Multistream(false)
849 if _, err := io.Copy(ioutil.Discard, zr); err != nil {
850 return fmt.Errorf("reading first stream: %v", err)
851 }
852 peek, err := br.Peek(1)
853 if len(peek) > 0 || err != io.EOF {
854 return fmt.Errorf("unexpected peek of %d, %v after first gzip stream", len(peek), err)
855 }
856 return nil
857}
858
Andrew Gerrand319667f2015-02-04 16:04:07 +0000859func addPrefix(prefix string, in []string) []string {
860 var out []string
861 for _, s := range in {
862 out = append(out, path.Join(prefix, s))
863 }
864 return out
865}
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700866
867func coordinatorClient() *buildlet.CoordinatorClient {
868 return &buildlet.CoordinatorClient{
869 Auth: buildlet.UserPass{
870 Username: "user-" + *user,
871 Password: userToken(),
872 },
Andrew Gerrand8e28dc92016-03-22 09:05:52 +1100873 Instance: build.ProdCoordinator,
Brad Fitzpatrick4b956612015-07-07 09:57:08 -0700874 }
875}
876
877func homeDir() string {
878 if runtime.GOOS == "windows" {
879 return os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
880 }
881 return os.Getenv("HOME")
882}
883
884func configDir() string {
885 if runtime.GOOS == "windows" {
886 return filepath.Join(os.Getenv("APPDATA"), "Gomote")
887 }
888 if xdg := os.Getenv("XDG_CONFIG_HOME"); xdg != "" {
889 return filepath.Join(xdg, "gomote")
890 }
891 return filepath.Join(homeDir(), ".config", "gomote")
892}
893
894func username() string {
895 if runtime.GOOS == "windows" {
896 return os.Getenv("USERNAME")
897 }
898 return os.Getenv("USER")
899}
900
901func userToken() string {
902 if *user == "" {
903 panic("userToken called with user flag empty")
904 }
905 keyDir := configDir()
906 baseFile := "user-" + *user + ".token"
907 tokenFile := filepath.Join(keyDir, baseFile)
908 slurp, err := ioutil.ReadFile(tokenFile)
909 if os.IsNotExist(err) {
910 log.Printf("Missing file %s for user %q. Change --user or obtain a token and place it there.",
911 tokenFile, *user)
912 }
913 if err != nil {
914 log.Fatal(err)
915 }
916 return strings.TrimSpace(string(slurp))
917}
Brad Fitzpatrick9702f6a2016-08-30 20:32:33 +0000918
919func setGOARCH(env []string, goarch string) []string {
920 wantKV := "GOARCH=" + goarch
921 existing := false
922 for i, kv := range env {
923 if strings.HasPrefix(kv, "GOARCH=") && kv != wantKV {
924 env[i] = wantKV
925 existing = true
926 }
927 }
928 if existing {
929 return env
930 }
931 return append(env, wantKV)
932}
Brad Fitzpatrick790500f2018-10-19 15:15:16 -0700933
934// versionIncludesTour reports whether the provided Go version (of the
935// form "go1.N" or "go1.N.M" includes the Go tour binary.
936func versionIncludesTour(goVer string) bool {
937 // We don't do releases of Go 1.9 and earlier, so this only
938 // needs to recognize the two current past releases. From Go
939 // 1.12 and on, we won't ship the tour binary (see CL 131156).
940 return strings.HasPrefix(goVer, "go1.10.") ||
941 strings.HasPrefix(goVer, "go1.11.")
942}
Brad Fitzpatrick5bd98932019-04-29 17:28:21 +0000943
944// versionIncludesGodoc reports whether the provided Go version (of the
945// form "go1.N" or "go1.N.M" includes the godoc binary.
946func versionIncludesGodoc(goVer string) bool {
947 // We don't do releases of Go 1.10 and earlier, so this only
948 // needs to recognize the two current past releases. From Go
949 // 1.13 and on, we won't ship the godoc binary (see Issue 30029).
950 return strings.HasPrefix(goVer, "go1.11.") ||
951 strings.HasPrefix(goVer, "go1.12.")
952}