@@ -11,6 +11,7 @@ import (
11
11
"archive/tar"
12
12
"bytes"
13
13
"compress/gzip"
14
+ "context"
14
15
"flag"
15
16
"fmt"
16
17
"io"
@@ -21,12 +22,14 @@ import (
21
22
"path/filepath"
22
23
"regexp"
23
24
"strings"
24
- "sync"
25
+
26
+ "golang.org/x/sync/errgroup"
25
27
)
26
28
27
29
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"` )
30
33
)
31
34
32
35
// TODO: use buildlet package instead of calling out to gomote.
@@ -101,12 +104,57 @@ if %errorlevel% neq 0 exit /b %errorlevel%
101
104
},
102
105
}
103
106
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
+
104
151
func main () {
105
152
flag .Parse ()
106
153
if * flagRev == "" || * flagGoroot == "" {
107
154
flag .PrintDefaults ()
108
155
os .Exit (1 )
109
156
}
157
+ parsePlatformsFlag ()
110
158
111
159
// Update revision in the README file.
112
160
// Do this early to check goroot correctness.
@@ -125,84 +173,69 @@ func main() {
125
173
}
126
174
127
175
// Start build on all platforms in parallel.
128
- var wg sync.WaitGroup
129
- wg .Add (len (platforms ))
176
+ g , ctx := errgroup .WithContext (context .Background ())
130
177
for _ , p := range platforms {
178
+ if ! platformEnabled [p .Name ()] {
179
+ continue
180
+ }
181
+
131
182
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 )
138
186
}
139
- }()
187
+ return nil
188
+ })
140
189
}
141
- wg .Wait ()
142
190
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 )
155
193
os .Exit (1 )
156
194
}
157
195
}
158
196
159
197
type Platform struct {
160
198
OS string
161
199
Arch string
162
- Name string // something for logging
163
200
Type string // gomote instance type
164
201
Inst string // actual gomote instance name
165
- Err error
166
- Log * os.File
167
202
Script string
168
203
}
169
204
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
+ }
181
208
209
+ func (p * Platform ) Build (ctx context.Context ) error {
182
210
// 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".
190
224
log .Printf ("%v: instance creation failed, retrying" , p .Name )
191
- createErr = err
225
+ lastErr = err
192
226
continue
193
227
}
194
- p .Inst = strings .Trim (string (inst ), " \t \n " )
195
- break
196
- }
197
- if p .Inst == "" {
198
- return createErr
199
228
}
229
+ p .Inst = strings .Trim (string (inst ), " \t \n " )
230
+ defer p .Gomote (context .Background (), "destroy" , p .Inst )
200
231
}
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 )
203
236
204
237
// put14
205
- if _ , err := p .Gomote ("put14" , p .Inst ); err != nil {
238
+ if _ , err := p .Gomote (ctx , "put14" , p .Inst ); err != nil {
206
239
return err
207
240
}
208
241
@@ -223,16 +256,16 @@ func (p *Platform) Build() error {
223
256
if p .OS == "windows" {
224
257
targetName = "script.bat"
225
258
}
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 {
227
260
return err
228
261
}
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 {
230
263
return err
231
264
}
232
265
233
266
// The script is supposed to leave updated runtime at that path. Copy it out.
234
267
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 )
236
269
if err != nil {
237
270
return err
238
271
}
@@ -242,7 +275,7 @@ func (p *Platform) Build() error {
242
275
return fmt .Errorf ("%v" , err )
243
276
}
244
277
245
- log .Printf ("%v: build completed" , p .Name )
278
+ log .Printf ("%v: build completed" , p .Name () )
246
279
return nil
247
280
}
248
281
@@ -270,16 +303,24 @@ func (p *Platform) WriteSyso(sysof string, targz []byte) error {
270
303
return nil
271
304
}
272
305
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
+
281
310
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>" )
283
323
}
284
- return output , err
324
+ log .Printf ("%v: gomote %v succeeded:\n %s" , p .Name (), args , logData )
325
+ return output , nil
285
326
}
0 commit comments