1
1
package task
2
2
3
3
import (
4
- "bytes"
4
+ "archive/tar"
5
+ "compress/gzip"
5
6
"context"
6
7
"encoding/json"
7
8
"errors"
8
9
"fmt"
10
+ "io"
9
11
"net/http"
10
12
"net/url"
13
+ "path"
11
14
"reflect"
12
15
"regexp"
13
16
"strconv"
@@ -47,6 +50,7 @@ type TagRepo struct {
47
50
Name string // Gerrit project name, e.g. "tools".
48
51
ModPath string // Module path, e.g. "golang.org/x/tools".
49
52
Deps []string // Dependency module paths.
53
+ Compat string // The version to pass to go mod tidy -compat for this repository.
50
54
Version string // After a tagging decision has been made, the version dependencies should upgrade to.
51
55
}
52
56
@@ -127,6 +131,14 @@ func (x *TagXReposTasks) readRepo(ctx *wf.TaskContext, project string) (*TagRepo
127
131
ModPath : mf .Module .Mod .Path ,
128
132
}
129
133
134
+ compatRe := regexp .MustCompile (`tagx:compat\s+([\d.]+)` )
135
+ if mf .Go != nil {
136
+ for _ , c := range mf .Go .Syntax .Comments .Suffix {
137
+ if matches := compatRe .FindStringSubmatch (c .Token ); matches != nil {
138
+ result .Compat = matches [1 ]
139
+ }
140
+ }
141
+ }
130
142
require:
131
143
for _ , req := range mf .Require {
132
144
if ! isX (req .Mod .Path ) {
@@ -266,88 +278,126 @@ func (x *TagXReposTasks) planRepo(wd *wf.Definition, repo TagRepo, updated map[s
266
278
return tagged , true
267
279
}
268
280
269
- type UpdatedModSum struct {
270
- Mod , Sum string
271
- }
272
-
273
- func (x * TagXReposTasks ) UpdateGoMod (ctx * wf.TaskContext , repo TagRepo , deps []TagRepo , branch string ) (UpdatedModSum , error ) {
281
+ func (x * TagXReposTasks ) UpdateGoMod (ctx * wf.TaskContext , repo TagRepo , deps []TagRepo , branch string ) (files map [string ]string , _ error ) {
274
282
commit , err := x .Gerrit .ReadBranchHead (ctx , repo .Name , branch )
275
283
if err != nil {
276
- return UpdatedModSum {} , err
284
+ return nil , err
277
285
}
278
286
279
287
binaries , err := x .LatestGoBinaries (ctx )
280
288
if err != nil {
281
- return UpdatedModSum {} , err
289
+ return nil , err
282
290
}
283
291
bc , err := x .CreateBuildlet (ctx , "linux-amd64-longtest" ) // longtest to allow network access. A little yucky.
284
292
if err != nil {
285
- return UpdatedModSum {} , err
293
+ return nil , err
286
294
}
287
295
defer bc .Close ()
288
296
289
297
if err := bc .PutTarFromURL (ctx , binaries , "" ); err != nil {
290
- return UpdatedModSum {} , err
298
+ return nil , err
291
299
}
292
300
tarURL := fmt .Sprintf ("%s/%s/+archive/%s.tar.gz" , x .GerritURL , repo .Name , commit )
293
301
if err := bc .PutTarFromURL (ctx , tarURL , "repo" ); err != nil {
294
- return UpdatedModSum {} , err
302
+ return nil , err
295
303
}
296
304
297
305
writer := & LogWriter {Logger : ctx }
298
306
go writer .Run (ctx )
299
307
300
- args := []string {"get" }
308
+ // Update the root module to the selected versions.
309
+ getCmd := []string {"get" }
301
310
for _ , dep := range deps {
302
- args = append (args , dep .ModPath + "@" + dep .Version )
311
+ getCmd = append (getCmd , dep .ModPath + "@" + dep .Version )
303
312
}
304
313
remoteErr , execErr := bc .Exec (ctx , "go/bin/go" , buildlet.ExecOpts {
305
314
Dir : "repo" ,
306
- Args : args ,
315
+ Args : getCmd ,
307
316
Output : writer ,
308
317
})
309
318
if execErr != nil {
310
- return UpdatedModSum {} , execErr
319
+ return nil , execErr
311
320
}
312
321
if remoteErr != nil {
313
- return UpdatedModSum {} , fmt .Errorf ("Command failed: %v" , remoteErr )
322
+ return nil , fmt .Errorf ("Command failed: %v" , remoteErr )
314
323
}
315
324
316
- remoteErr , execErr = bc .Exec (ctx , "go/bin/go" , buildlet.ExecOpts {
317
- Dir : "repo" ,
318
- Args : []string {"mod" , "tidy" },
319
- Output : writer ,
320
- })
321
- if execErr != nil {
322
- return UpdatedModSum {}, execErr
325
+ // Tidy the root module. For tools, also tidy gopls so that its replaced
326
+ // version still works.
327
+ dirs := []string {"" }
328
+ if repo .Name == "tools" {
329
+ dirs = append (dirs , "gopls" )
323
330
}
324
- if remoteErr != nil {
325
- return UpdatedModSum {}, fmt .Errorf ("Command failed: %v" , remoteErr )
331
+ var fetchCmd []string
332
+ for _ , dir := range dirs {
333
+ var tidyFlags []string
334
+ if repo .Compat != "" {
335
+ tidyFlags = append (tidyFlags , "-compat" , repo .Compat )
336
+ }
337
+ remoteErr , execErr = bc .Exec (ctx , "go/bin/go" , buildlet.ExecOpts {
338
+ Dir : path .Join ("repo" , dir ),
339
+ Args : append ([]string {"mod" , "tidy" }, tidyFlags ... ),
340
+ Output : writer ,
341
+ })
342
+ if execErr != nil {
343
+ return nil , execErr
344
+ }
345
+ if remoteErr != nil {
346
+ return nil , fmt .Errorf ("Command failed: %v" , remoteErr )
347
+ }
348
+
349
+ repoDir , fetchDir := path .Join ("repo" , dir ), path .Join ("fetch" , dir )
350
+ fetchCmd = append (fetchCmd , fmt .Sprintf ("mkdir -p %[2]v && cp %[1]v/go.mod %[2]v && touch %[1]v/go.sum && cp %[1]v/go.sum %[2]v" , repoDir , fetchDir ))
326
351
}
327
352
328
353
remoteErr , execErr = bc .Exec (ctx , "bash" , buildlet.ExecOpts {
329
354
Dir : "." ,
330
- Args : []string {"-c" , "mkdir fetchgomod && cp repo/go.mod fetchgomod && touch repo/go.sum && mkdir fetchgosum && cp repo/go.sum fetchgosum" },
355
+ Args : []string {"-c" , strings . Join ( fetchCmd , " && " ) },
331
356
Output : writer ,
332
357
SystemLevel : true ,
333
358
})
334
359
if execErr != nil {
335
- return UpdatedModSum {} , execErr
360
+ return nil , execErr
336
361
}
337
362
if remoteErr != nil {
338
- return UpdatedModSum {} , fmt .Errorf ("Command failed: %v" , remoteErr )
363
+ return nil , fmt .Errorf ("Command failed: %v" , remoteErr )
339
364
}
340
365
341
- mod := & bytes. Buffer {}
342
- if err := fetchFile ( ctx , bc , mod , "fetchgomod" ); err != nil {
343
- return UpdatedModSum {} , err
366
+ tgz , err := bc . GetTar ( ctx , "fetch" )
367
+ if err != nil {
368
+ return nil , err
344
369
}
345
- sum := & bytes.Buffer {}
346
- if err := fetchFile (ctx , bc , sum , "fetchgosum" ); err != nil {
347
- return UpdatedModSum {}, err
370
+ defer tgz .Close ()
371
+ return tgzToMap (tgz )
372
+ }
373
+
374
+ func tgzToMap (r io.Reader ) (map [string ]string , error ) {
375
+ gzr , err := gzip .NewReader (r )
376
+ if err != nil {
377
+ return nil , err
348
378
}
379
+ defer gzr .Close ()
349
380
350
- return UpdatedModSum {mod .String (), sum .String ()}, nil
381
+ result := map [string ]string {}
382
+ tr := tar .NewReader (gzr )
383
+ for {
384
+ h , err := tr .Next ()
385
+ if err == io .EOF {
386
+ break
387
+ }
388
+ if err != nil {
389
+ return nil , err
390
+ }
391
+ if h .Typeflag != tar .TypeReg {
392
+ continue
393
+ }
394
+ b , err := io .ReadAll (tr )
395
+ if err != nil {
396
+ return nil , err
397
+ }
398
+ result [h .Name ] = string (b )
399
+ }
400
+ return result , nil
351
401
}
352
402
353
403
func LatestGoBinaries (ctx context.Context ) (string , error ) {
@@ -374,7 +424,7 @@ func LatestGoBinaries(ctx context.Context) (string, error) {
374
424
return "" , fmt .Errorf ("no linux-amd64??" )
375
425
}
376
426
377
- func (x * TagXReposTasks ) MailGoMod (ctx * wf.TaskContext , repo string , gomod UpdatedModSum ) (string , error ) {
427
+ func (x * TagXReposTasks ) MailGoMod (ctx * wf.TaskContext , repo string , files map [ string ] string ) (string , error ) {
378
428
const subject = `go.mod: update golang.org/x dependencies
379
429
380
430
Update golang.org/x dependencies to their latest tagged versions.
@@ -386,10 +436,7 @@ will be tagged with its next minor version.
386
436
Project : repo ,
387
437
Branch : "master" ,
388
438
Subject : subject ,
389
- }, nil , map [string ]string {
390
- "go.mod" : gomod .Mod ,
391
- "go.sum" : gomod .Sum ,
392
- })
439
+ }, nil , files )
393
440
}
394
441
395
442
func (x * TagXReposTasks ) AwaitGoMod (ctx * wf.TaskContext , changeID , repo , branch string ) (string , error ) {
0 commit comments