Skip to content

Commit d1518ba

Browse files
author
Bryan C. Mills
committed
cmd/racebuild: simplify debugging
Print output directly to the racebuild log instead of separate log files per builder. Cancel all builders at the first error: if there is something wrong with the Go or compiler-rt commit, it's probably wrong globally. Add a --platforms flag to attempt only a subset of builds: that way, we can update only a subset (e.g., to work around OS-specific bugs) or iterate on a single failing platform without attempting all the other platforms at the same time. Sanity-check the platforms table at init to ensure that there are no duplicates for the same OS/arch combination. Updates golang/go#24354. Change-Id: Ic4d4ab32ca6cc13a150c9bbfcc2e5fbd3742d704 Reviewed-on: https://go-review.googlesource.com/112876 Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 7bb4e0b commit d1518ba

File tree

1 file changed

+110
-69
lines changed

1 file changed

+110
-69
lines changed

cmd/racebuild/racebuild.go

Lines changed: 110 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"archive/tar"
1212
"bytes"
1313
"compress/gzip"
14+
"context"
1415
"flag"
1516
"fmt"
1617
"io"
@@ -21,12 +22,14 @@ import (
2122
"path/filepath"
2223
"regexp"
2324
"strings"
24-
"sync"
25+
26+
"golang.org/x/sync/errgroup"
2527
)
2628

2729
var (
28-
flagGoroot = flag.String("goroot", "", "path to Go repository to update (required)")
29-
flagRev = flag.String("rev", "", "llvm compiler-rt git revision from http://llvm.org/git/compiler-rt.git (required)")
30+
flagGoroot = flag.String("goroot", "", "path to Go repository to update (required)")
31+
flagRev = flag.String("rev", "", "llvm compiler-rt git revision from http://llvm.org/git/compiler-rt.git (required)")
32+
flagPlatforms = flag.String("platforms", "all", `comma-separated platforms (such as "linux/amd64") to rebuild, or "all"`)
3033
)
3134

3235
// TODO: use buildlet package instead of calling out to gomote.
@@ -101,12 +104,57 @@ if %errorlevel% neq 0 exit /b %errorlevel%
101104
},
102105
}
103106

107+
func init() {
108+
// Ensure that there are no duplicate platform entries.
109+
seen := make(map[string]bool)
110+
for _, p := range platforms {
111+
if seen[p.Name()] {
112+
log.Fatal("Duplicate platforms entry for %s.", p.Name())
113+
}
114+
seen[p.Name()] = true
115+
}
116+
}
117+
118+
var platformEnabled = make(map[string]bool)
119+
120+
func parsePlatformsFlag() {
121+
if *flagPlatforms == "all" {
122+
for _, p := range platforms {
123+
platformEnabled[p.Name()] = true
124+
}
125+
return
126+
}
127+
128+
var invalid []string
129+
for _, name := range strings.Split(*flagPlatforms, ",") {
130+
for _, p := range platforms {
131+
if name == p.Name() {
132+
platformEnabled[name] = true
133+
break
134+
}
135+
}
136+
if !platformEnabled[name] {
137+
invalid = append(invalid, name)
138+
}
139+
}
140+
141+
if len(invalid) > 0 {
142+
var msg bytes.Buffer
143+
fmt.Fprintf(&msg, "Unrecognized platforms: %q. Supported platforms are:\n", invalid)
144+
for _, p := range platforms {
145+
fmt.Fprintf(&msg, "\t%s/%s\n", p.OS, p.Arch)
146+
}
147+
log.Fatal(&msg)
148+
}
149+
}
150+
104151
func main() {
105152
flag.Parse()
106153
if *flagRev == "" || *flagGoroot == "" {
107154
flag.PrintDefaults()
108155
os.Exit(1)
109156
}
157+
parsePlatformsFlag()
110158

111159
// Update revision in the README file.
112160
// Do this early to check goroot correctness.
@@ -125,84 +173,69 @@ func main() {
125173
}
126174

127175
// Start build on all platforms in parallel.
128-
var wg sync.WaitGroup
129-
wg.Add(len(platforms))
176+
g, ctx := errgroup.WithContext(context.Background())
130177
for _, p := range platforms {
178+
if !platformEnabled[p.Name()] {
179+
continue
180+
}
181+
131182
p := p
132-
go func() {
133-
defer wg.Done()
134-
p.Err = p.Build()
135-
if p.Err != nil {
136-
p.Err = fmt.Errorf("failed: %v", p.Err)
137-
log.Printf("%v: %v", p.Name, p.Err)
183+
g.Go(func() error {
184+
if err := p.Build(ctx); err != nil {
185+
return fmt.Errorf("%v failed: %v", p.Name(), err)
138186
}
139-
}()
187+
return nil
188+
})
140189
}
141-
wg.Wait()
142190

143-
// Duplicate results, they can get lost in the log.
144-
ok := true
145-
log.Printf("---")
146-
for _, p := range platforms {
147-
if p.Err == nil {
148-
log.Printf("%v: ok", p.Name)
149-
continue
150-
}
151-
ok = false
152-
log.Printf("%v: %v", p.Name, p.Err)
153-
}
154-
if !ok {
191+
if err := g.Wait(); err != nil {
192+
log.Println(err)
155193
os.Exit(1)
156194
}
157195
}
158196

159197
type Platform struct {
160198
OS string
161199
Arch string
162-
Name string // something for logging
163200
Type string // gomote instance type
164201
Inst string // actual gomote instance name
165-
Err error
166-
Log *os.File
167202
Script string
168203
}
169204

170-
func (p *Platform) Build() error {
171-
p.Name = fmt.Sprintf("%v-%v", p.OS, p.Arch)
172-
173-
// Open log file.
174-
var err error
175-
p.Log, err = ioutil.TempFile("", p.Name)
176-
if err != nil {
177-
return fmt.Errorf("failed to create log file: %v", err)
178-
}
179-
defer p.Log.Close()
180-
log.Printf("%v: logging to %v", p.Name, p.Log.Name())
205+
func (p *Platform) Name() string {
206+
return fmt.Sprintf("%v/%v", p.OS, p.Arch)
207+
}
181208

209+
func (p *Platform) Build(ctx context.Context) error {
182210
// Create gomote instance (or reuse an existing instance for debugging).
183-
if p.Inst == "" {
184-
// Creation sometimes fails with transient errors like:
185-
// "buildlet didn't come up at http://10.240.0.13 in 3m0s".
186-
var createErr error
187-
for i := 0; i < 10; i++ {
188-
inst, err := p.Gomote("create", p.Type)
189-
if err != nil {
211+
var lastErr error
212+
for i := 0; p.Inst == "" && i < 10; i++ {
213+
inst, err := p.Gomote(ctx, "create", p.Type)
214+
if err != nil {
215+
select {
216+
case <-ctx.Done():
217+
if lastErr != nil {
218+
return lastErr
219+
}
220+
return err
221+
default:
222+
// Creation sometimes fails with transient errors like:
223+
// "buildlet didn't come up at http://10.240.0.13 in 3m0s".
190224
log.Printf("%v: instance creation failed, retrying", p.Name)
191-
createErr = err
225+
lastErr = err
192226
continue
193227
}
194-
p.Inst = strings.Trim(string(inst), " \t\n")
195-
break
196-
}
197-
if p.Inst == "" {
198-
return createErr
199228
}
229+
p.Inst = strings.Trim(string(inst), " \t\n")
230+
defer p.Gomote(context.Background(), "destroy", p.Inst)
200231
}
201-
defer p.Gomote("destroy", p.Inst)
202-
log.Printf("%s: using instance %v", p.Name, p.Inst)
232+
if p.Inst == "" {
233+
return lastErr
234+
}
235+
log.Printf("%s: using instance %v", p.Name(), p.Inst)
203236

204237
// put14
205-
if _, err := p.Gomote("put14", p.Inst); err != nil {
238+
if _, err := p.Gomote(ctx, "put14", p.Inst); err != nil {
206239
return err
207240
}
208241

@@ -223,16 +256,16 @@ func (p *Platform) Build() error {
223256
if p.OS == "windows" {
224257
targetName = "script.bat"
225258
}
226-
if _, err := p.Gomote("put", "-mode=0700", p.Inst, script.Name(), targetName); err != nil {
259+
if _, err := p.Gomote(ctx, "put", "-mode=0700", p.Inst, script.Name(), targetName); err != nil {
227260
return err
228261
}
229-
if _, err := p.Gomote("run", "-e=REV="+*flagRev, p.Inst, targetName); err != nil {
262+
if _, err := p.Gomote(ctx, "run", "-e=REV="+*flagRev, p.Inst, targetName); err != nil {
230263
return err
231264
}
232265

233266
// The script is supposed to leave updated runtime at that path. Copy it out.
234267
syso := fmt.Sprintf("race_%v_%s.syso", p.OS, p.Arch)
235-
targz, err := p.Gomote("gettar", "-dir=go/src/runtime/race/"+syso, p.Inst)
268+
targz, err := p.Gomote(ctx, "gettar", "-dir=go/src/runtime/race/"+syso, p.Inst)
236269
if err != nil {
237270
return err
238271
}
@@ -242,7 +275,7 @@ func (p *Platform) Build() error {
242275
return fmt.Errorf("%v", err)
243276
}
244277

245-
log.Printf("%v: build completed", p.Name)
278+
log.Printf("%v: build completed", p.Name())
246279
return nil
247280
}
248281

@@ -270,16 +303,24 @@ func (p *Platform) WriteSyso(sysof string, targz []byte) error {
270303
return nil
271304
}
272305

273-
func (p *Platform) Gomote(args ...string) ([]byte, error) {
274-
log.Printf("%v: gomote %v", p.Name, args)
275-
fmt.Fprintf(p.Log, "$ gomote %v\n", args)
276-
output, err := exec.Command("gomote", args...).CombinedOutput()
277-
if err != nil || args[0] != "gettar" {
278-
p.Log.Write(output)
279-
}
280-
fmt.Fprintf(p.Log, "\n\n")
306+
func (p *Platform) Gomote(ctx context.Context, args ...string) ([]byte, error) {
307+
log.Printf("%v: gomote %v", p.Name(), args)
308+
output, err := exec.CommandContext(ctx, "gomote", args...).CombinedOutput()
309+
281310
if err != nil {
282-
err = fmt.Errorf("gomote %v failed: %v", args, err)
311+
select {
312+
case <-ctx.Done():
313+
return nil, ctx.Err()
314+
default:
315+
}
316+
log.Printf("%v: gomote %v failed:\n%s", p.Name(), args, output)
317+
return nil, err
318+
}
319+
320+
logData := output
321+
if args[0] == "gettar" {
322+
logData = []byte("<output elided>")
283323
}
284-
return output, err
324+
log.Printf("%v: gomote %v succeeded:\n%s", p.Name(), args, logData)
325+
return output, nil
285326
}

0 commit comments

Comments
 (0)