github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/go/list/list.go (about) 1 // Copyright 2011 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 // Package list implements the “go list” command. 6 package list 7 8 import ( 9 "bufio" 10 "bytes" 11 "context" 12 "encoding/json" 13 "errors" 14 "fmt" 15 "io" 16 "os" 17 "reflect" 18 "runtime" 19 "sort" 20 "strconv" 21 "strings" 22 "sync" 23 "text/template" 24 25 "golang.org/x/sync/semaphore" 26 27 "github.com/go-asm/go/cmd/go/base" 28 "github.com/go-asm/go/cmd/go/cache" 29 "github.com/go-asm/go/cmd/go/cfg" 30 "github.com/go-asm/go/cmd/go/load" 31 "github.com/go-asm/go/cmd/go/modinfo" 32 "github.com/go-asm/go/cmd/go/modload" 33 "github.com/go-asm/go/cmd/go/str" 34 "github.com/go-asm/go/cmd/go/work" 35 ) 36 37 var CmdList = &base.Command{ 38 // Note: -f -json -m are listed explicitly because they are the most common list flags. 39 // Do not send CLs removing them because they're covered by [list flags]. 40 UsageLine: "go list [-f format] [-json] [-m] [list flags] [build flags] [packages]", 41 Short: "list packages or modules", 42 Long: ` 43 List lists the named packages, one per line. 44 The most commonly-used flags are -f and -json, which control the form 45 of the output printed for each package. Other list flags, documented below, 46 control more specific details. 47 48 The default output shows the package import path: 49 50 bytes 51 encoding/json 52 github.com/gorilla/mux 53 golang.org/x/net/html 54 55 The -f flag specifies an alternate format for the list, using the 56 syntax of package template. The default output is equivalent 57 to -f '{{.ImportPath}}'. The struct being passed to the template is: 58 59 type Package struct { 60 Dir string // directory containing package sources 61 ImportPath string // import path of package in dir 62 ImportComment string // path in import comment on package statement 63 Name string // package name 64 Doc string // package documentation string 65 Target string // install path 66 Shlib string // the shared library that contains this package (only set when -linkshared) 67 Goroot bool // is this package in the Go root? 68 Standard bool // is this package part of the standard Go library? 69 Stale bool // would 'go install' do anything for this package? 70 StaleReason string // explanation for Stale==true 71 Root string // Go root or Go path dir containing this package 72 ConflictDir string // this directory shadows Dir in $GOPATH 73 BinaryOnly bool // binary-only package (no longer supported) 74 ForTest string // package is only for use in named test 75 Export string // file containing export data (when using -export) 76 BuildID string // build ID of the compiled package (when using -export) 77 Module *Module // info about package's containing module, if any (can be nil) 78 Match []string // command-line patterns matching this package 79 DepOnly bool // package is only a dependency, not explicitly listed 80 DefaultGODEBUG string // default GODEBUG setting, for main packages 81 82 // Source files 83 GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) 84 CgoFiles []string // .go source files that import "C" 85 CompiledGoFiles []string // .go files presented to compiler (when using -compiled) 86 IgnoredGoFiles []string // .go source files ignored due to build constraints 87 IgnoredOtherFiles []string // non-.go source files ignored due to build constraints 88 CFiles []string // .c source files 89 CXXFiles []string // .cc, .cxx and .cpp source files 90 MFiles []string // .m source files 91 HFiles []string // .h, .hh, .hpp and .hxx source files 92 FFiles []string // .f, .F, .for and .f90 Fortran source files 93 SFiles []string // .s source files 94 SwigFiles []string // .swig files 95 SwigCXXFiles []string // .swigcxx files 96 SysoFiles []string // .syso object files to add to archive 97 TestGoFiles []string // _test.go files in package 98 XTestGoFiles []string // _test.go files outside package 99 100 // Embedded files 101 EmbedPatterns []string // //go:embed patterns 102 EmbedFiles []string // files matched by EmbedPatterns 103 TestEmbedPatterns []string // //go:embed patterns in TestGoFiles 104 TestEmbedFiles []string // files matched by TestEmbedPatterns 105 XTestEmbedPatterns []string // //go:embed patterns in XTestGoFiles 106 XTestEmbedFiles []string // files matched by XTestEmbedPatterns 107 108 // Cgo directives 109 CgoCFLAGS []string // cgo: flags for C compiler 110 CgoCPPFLAGS []string // cgo: flags for C preprocessor 111 CgoCXXFLAGS []string // cgo: flags for C++ compiler 112 CgoFFLAGS []string // cgo: flags for Fortran compiler 113 CgoLDFLAGS []string // cgo: flags for linker 114 CgoPkgConfig []string // cgo: pkg-config names 115 116 // Dependency information 117 Imports []string // import paths used by this package 118 ImportMap map[string]string // map from source import to ImportPath (identity entries omitted) 119 Deps []string // all (recursively) imported dependencies 120 TestImports []string // imports from TestGoFiles 121 XTestImports []string // imports from XTestGoFiles 122 123 // Error information 124 Incomplete bool // this package or a dependency has an error 125 Error *PackageError // error loading package 126 DepsErrors []*PackageError // errors loading dependencies 127 } 128 129 Packages stored in vendor directories report an ImportPath that includes the 130 path to the vendor directory (for example, "d/vendor/p" instead of "p"), 131 so that the ImportPath uniquely identifies a given copy of a package. 132 The Imports, Deps, TestImports, and XTestImports lists also contain these 133 expanded import paths. See golang.org/s/go15vendor for more about vendoring. 134 135 The error information, if any, is 136 137 type PackageError struct { 138 ImportStack []string // shortest path from package named on command line to this one 139 Pos string // position of error (if present, file:line:col) 140 Err string // the error itself 141 } 142 143 The module information is a Module struct, defined in the discussion 144 of list -m below. 145 146 The template function "join" calls strings.Join. 147 148 The template function "context" returns the build context, defined as: 149 150 type Context struct { 151 GOARCH string // target architecture 152 GOOS string // target operating system 153 GOROOT string // Go root 154 GOPATH string // Go path 155 CgoEnabled bool // whether cgo can be used 156 UseAllFiles bool // use files regardless of //go:build lines, file names 157 Compiler string // compiler to assume when computing target paths 158 BuildTags []string // build constraints to match in //go:build lines 159 ToolTags []string // toolchain-specific build constraints 160 ReleaseTags []string // releases the current release is compatible with 161 InstallSuffix string // suffix to use in the name of the install dir 162 } 163 164 For more information about the meaning of these fields see the documentation 165 for the go/build package's Context type. 166 167 The -json flag causes the package data to be printed in JSON format 168 instead of using the template format. The JSON flag can optionally be 169 provided with a set of comma-separated required field names to be output. 170 If so, those required fields will always appear in JSON output, but 171 others may be omitted to save work in computing the JSON struct. 172 173 The -compiled flag causes list to set CompiledGoFiles to the Go source 174 files presented to the compiler. Typically this means that it repeats 175 the files listed in GoFiles and then also adds the Go code generated 176 by processing CgoFiles and SwigFiles. The Imports list contains the 177 union of all imports from both GoFiles and CompiledGoFiles. 178 179 The -deps flag causes list to iterate over not just the named packages 180 but also all their dependencies. It visits them in a depth-first post-order 181 traversal, so that a package is listed only after all its dependencies. 182 Packages not explicitly listed on the command line will have the DepOnly 183 field set to true. 184 185 The -e flag changes the handling of erroneous packages, those that 186 cannot be found or are malformed. By default, the list command 187 prints an error to standard error for each erroneous package and 188 omits the packages from consideration during the usual printing. 189 With the -e flag, the list command never prints errors to standard 190 error and instead processes the erroneous packages with the usual 191 printing. Erroneous packages will have a non-empty ImportPath and 192 a non-nil Error field; other information may or may not be missing 193 (zeroed). 194 195 The -export flag causes list to set the Export field to the name of a 196 file containing up-to-date export information for the given package, 197 and the BuildID field to the build ID of the compiled package. 198 199 The -find flag causes list to identify the named packages but not 200 resolve their dependencies: the Imports and Deps lists will be empty. 201 With the -find flag, the -deps, -test and -export commands cannot be 202 used. 203 204 The -test flag causes list to report not only the named packages 205 but also their test binaries (for packages with tests), to convey to 206 source code analysis tools exactly how test binaries are constructed. 207 The reported import path for a test binary is the import path of 208 the package followed by a ".test" suffix, as in "math/rand.test". 209 When building a test, it is sometimes necessary to rebuild certain 210 dependencies specially for that test (most commonly the tested 211 package itself). The reported import path of a package recompiled 212 for a particular test binary is followed by a space and the name of 213 the test binary in brackets, as in "math/rand [math/rand.test]" 214 or "regexp [sort.test]". The ForTest field is also set to the name 215 of the package being tested ("math/rand" or "sort" in the previous 216 examples). 217 218 The Dir, Target, Shlib, Root, ConflictDir, and Export file paths 219 are all absolute paths. 220 221 By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir 222 (that is, paths relative to Dir, not absolute paths). 223 The generated files added when using the -compiled and -test flags 224 are absolute paths referring to cached copies of generated Go source files. 225 Although they are Go source files, the paths may not end in ".go". 226 227 The -m flag causes list to list modules instead of packages. 228 229 When listing modules, the -f flag still specifies a format template 230 applied to a Go struct, but now a Module struct: 231 232 type Module struct { 233 Path string // module path 234 Query string // version query corresponding to this version 235 Version string // module version 236 Versions []string // available module versions 237 Replace *Module // replaced by this module 238 Time *time.Time // time version was created 239 Update *Module // available update (with -u) 240 Main bool // is this the main module? 241 Indirect bool // module is only indirectly needed by main module 242 Dir string // directory holding local copy of files, if any 243 GoMod string // path to go.mod file describing module, if any 244 GoVersion string // go version used in module 245 Retracted []string // retraction information, if any (with -retracted or -u) 246 Deprecated string // deprecation message, if any (with -u) 247 Error *ModuleError // error loading module 248 Origin any // provenance of module 249 Reuse bool // reuse of old module info is safe 250 } 251 252 type ModuleError struct { 253 Err string // the error itself 254 } 255 256 The file GoMod refers to may be outside the module directory if the 257 module is in the module cache or if the -modfile flag is used. 258 259 The default output is to print the module path and then 260 information about the version and replacement if any. 261 For example, 'go list -m all' might print: 262 263 my/main/module 264 golang.org/x/text v0.3.0 => /tmp/text 265 rsc.io/pdf v0.1.1 266 267 The Module struct has a String method that formats this 268 line of output, so that the default format is equivalent 269 to -f '{{.String}}'. 270 271 Note that when a module has been replaced, its Replace field 272 describes the replacement module, and its Dir field is set to 273 the replacement's source code, if present. (That is, if Replace 274 is non-nil, then Dir is set to Replace.Dir, with no access to 275 the replaced source code.) 276 277 The -u flag adds information about available upgrades. 278 When the latest version of a given module is newer than 279 the current one, list -u sets the Module's Update field 280 to information about the newer module. list -u will also set 281 the module's Retracted field if the current version is retracted. 282 The Module's String method indicates an available upgrade by 283 formatting the newer version in brackets after the current version. 284 If a version is retracted, the string "(retracted)" will follow it. 285 For example, 'go list -m -u all' might print: 286 287 my/main/module 288 golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text 289 rsc.io/pdf v0.1.1 (retracted) [v0.1.2] 290 291 (For tools, 'go list -m -u -json all' may be more convenient to parse.) 292 293 The -versions flag causes list to set the Module's Versions field 294 to a list of all known versions of that module, ordered according 295 to semantic versioning, earliest to latest. The flag also changes 296 the default output format to display the module path followed by the 297 space-separated version list. 298 299 The -retracted flag causes list to report information about retracted 300 module versions. When -retracted is used with -f or -json, the Retracted 301 field will be set to a string explaining why the version was retracted. 302 The string is taken from comments on the retract directive in the 303 module's go.mod file. When -retracted is used with -versions, retracted 304 versions are listed together with unretracted versions. The -retracted 305 flag may be used with or without -m. 306 307 The arguments to list -m are interpreted as a list of modules, not packages. 308 The main module is the module containing the current directory. 309 The active modules are the main module and its dependencies. 310 With no arguments, list -m shows the main module. 311 With arguments, list -m shows the modules specified by the arguments. 312 Any of the active modules can be specified by its module path. 313 The special pattern "all" specifies all the active modules, first the main 314 module and then dependencies sorted by module path. 315 A pattern containing "..." specifies the active modules whose 316 module paths match the pattern. 317 A query of the form path@version specifies the result of that query, 318 which is not limited to active modules. 319 See 'go help modules' for more about module queries. 320 321 The template function "module" takes a single string argument 322 that must be a module path or query and returns the specified 323 module as a Module struct. If an error occurs, the result will 324 be a Module struct with a non-nil Error field. 325 326 When using -m, the -reuse=old.json flag accepts the name of file containing 327 the JSON output of a previous 'go list -m -json' invocation with the 328 same set of modifier flags (such as -u, -retracted, and -versions). 329 The go command may use this file to determine that a module is unchanged 330 since the previous invocation and avoid redownloading information about it. 331 Modules that are not redownloaded will be marked in the new output by 332 setting the Reuse field to true. Normally the module cache provides this 333 kind of reuse automatically; the -reuse flag can be useful on systems that 334 do not preserve the module cache. 335 336 For more about build flags, see 'go help build'. 337 338 For more about specifying packages, see 'go help packages'. 339 340 For more about modules, see https://golang.org/ref/mod. 341 `, 342 } 343 344 func init() { 345 CmdList.Run = runList // break init cycle 346 work.AddBuildFlags(CmdList, work.DefaultBuildFlags) 347 if cfg.Experiment != nil && cfg.Experiment.CoverageRedesign { 348 work.AddCoverFlags(CmdList, nil) 349 } 350 CmdList.Flag.Var(&listJsonFields, "json", "") 351 } 352 353 var ( 354 listCompiled = CmdList.Flag.Bool("compiled", false, "") 355 listDeps = CmdList.Flag.Bool("deps", false, "") 356 listE = CmdList.Flag.Bool("e", false, "") 357 listExport = CmdList.Flag.Bool("export", false, "") 358 listFmt = CmdList.Flag.String("f", "", "") 359 listFind = CmdList.Flag.Bool("find", false, "") 360 listJson bool 361 listJsonFields jsonFlag // If not empty, only output these fields. 362 listM = CmdList.Flag.Bool("m", false, "") 363 listRetracted = CmdList.Flag.Bool("retracted", false, "") 364 listReuse = CmdList.Flag.String("reuse", "", "") 365 listTest = CmdList.Flag.Bool("test", false, "") 366 listU = CmdList.Flag.Bool("u", false, "") 367 listVersions = CmdList.Flag.Bool("versions", false, "") 368 ) 369 370 // A StringsFlag is a command-line flag that interprets its argument 371 // as a space-separated list of possibly-quoted strings. 372 type jsonFlag map[string]bool 373 374 func (v *jsonFlag) Set(s string) error { 375 if v, err := strconv.ParseBool(s); err == nil { 376 listJson = v 377 return nil 378 } 379 listJson = true 380 if *v == nil { 381 *v = make(map[string]bool) 382 } 383 for _, f := range strings.Split(s, ",") { 384 (*v)[f] = true 385 } 386 return nil 387 } 388 389 func (v *jsonFlag) String() string { 390 var fields []string 391 for f := range *v { 392 fields = append(fields, f) 393 } 394 sort.Strings(fields) 395 return strings.Join(fields, ",") 396 } 397 398 func (v *jsonFlag) IsBoolFlag() bool { 399 return true 400 } 401 402 func (v *jsonFlag) needAll() bool { 403 return len(*v) == 0 404 } 405 406 func (v *jsonFlag) needAny(fields ...string) bool { 407 if v.needAll() { 408 return true 409 } 410 for _, f := range fields { 411 if (*v)[f] { 412 return true 413 } 414 } 415 return false 416 } 417 418 var nl = []byte{'\n'} 419 420 func runList(ctx context.Context, cmd *base.Command, args []string) { 421 modload.InitWorkfile() 422 423 if *listFmt != "" && listJson { 424 base.Fatalf("go list -f cannot be used with -json") 425 } 426 if *listReuse != "" && !*listM { 427 base.Fatalf("go list -reuse cannot be used without -m") 428 } 429 if *listReuse != "" && modload.HasModRoot() { 430 base.Fatalf("go list -reuse cannot be used inside a module") 431 } 432 433 work.BuildInit() 434 out := newTrackingWriter(os.Stdout) 435 defer out.w.Flush() 436 437 if *listFmt == "" { 438 if *listM { 439 *listFmt = "{{.String}}" 440 if *listVersions { 441 *listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}{{if .Deprecated}} (deprecated){{end}}` 442 } 443 } else { 444 *listFmt = "{{.ImportPath}}" 445 } 446 } 447 448 var do func(x any) 449 if listJson { 450 do = func(x any) { 451 if !listJsonFields.needAll() { 452 v := reflect.ValueOf(x).Elem() // do is always called with a non-nil pointer. 453 // Clear all non-requested fields. 454 for i := 0; i < v.NumField(); i++ { 455 if !listJsonFields.needAny(v.Type().Field(i).Name) { 456 v.Field(i).SetZero() 457 } 458 } 459 } 460 b, err := json.MarshalIndent(x, "", "\t") 461 if err != nil { 462 out.Flush() 463 base.Fatalf("%s", err) 464 } 465 out.Write(b) 466 out.Write(nl) 467 } 468 } else { 469 var cachedCtxt *Context 470 context := func() *Context { 471 if cachedCtxt == nil { 472 cachedCtxt = newContext(&cfg.BuildContext) 473 } 474 return cachedCtxt 475 } 476 fm := template.FuncMap{ 477 "join": strings.Join, 478 "context": context, 479 "module": func(path string) *modinfo.ModulePublic { return modload.ModuleInfo(ctx, path) }, 480 } 481 tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt) 482 if err != nil { 483 base.Fatalf("%s", err) 484 } 485 do = func(x any) { 486 if err := tmpl.Execute(out, x); err != nil { 487 out.Flush() 488 base.Fatalf("%s", err) 489 } 490 if out.NeedNL() { 491 out.Write(nl) 492 } 493 } 494 } 495 496 modload.Init() 497 if *listRetracted { 498 if cfg.BuildMod == "vendor" { 499 base.Fatalf("go list -retracted cannot be used when vendoring is enabled") 500 } 501 if !modload.Enabled() { 502 base.Fatalf("go list -retracted can only be used in module-aware mode") 503 } 504 } 505 506 if *listM { 507 // Module mode. 508 if *listCompiled { 509 base.Fatalf("go list -compiled cannot be used with -m") 510 } 511 if *listDeps { 512 // TODO(rsc): Could make this mean something with -m. 513 base.Fatalf("go list -deps cannot be used with -m") 514 } 515 if *listExport { 516 base.Fatalf("go list -export cannot be used with -m") 517 } 518 if *listFind { 519 base.Fatalf("go list -find cannot be used with -m") 520 } 521 if *listTest { 522 base.Fatalf("go list -test cannot be used with -m") 523 } 524 525 if modload.Init(); !modload.Enabled() { 526 base.Fatalf("go: list -m cannot be used with GO111MODULE=off") 527 } 528 529 modload.LoadModFile(ctx) // Sets cfg.BuildMod as a side-effect. 530 if cfg.BuildMod == "vendor" { 531 const actionDisabledFormat = "go: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)" 532 533 if *listVersions { 534 base.Fatalf(actionDisabledFormat, "determine available versions") 535 } 536 if *listU { 537 base.Fatalf(actionDisabledFormat, "determine available upgrades") 538 } 539 540 for _, arg := range args { 541 // In vendor mode, the module graph is incomplete: it contains only the 542 // explicit module dependencies and the modules that supply packages in 543 // the import graph. Reject queries that imply more information than that. 544 if arg == "all" { 545 base.Fatalf(actionDisabledFormat, "compute 'all'") 546 } 547 if strings.Contains(arg, "...") { 548 base.Fatalf(actionDisabledFormat, "match module patterns") 549 } 550 } 551 } 552 553 var mode modload.ListMode 554 if *listU { 555 mode |= modload.ListU | modload.ListRetracted | modload.ListDeprecated 556 } 557 if *listRetracted { 558 mode |= modload.ListRetracted 559 } 560 if *listVersions { 561 mode |= modload.ListVersions 562 if *listRetracted { 563 mode |= modload.ListRetractedVersions 564 } 565 } 566 if *listReuse != "" && len(args) == 0 { 567 base.Fatalf("go: list -m -reuse only has an effect with module@version arguments") 568 } 569 mods, err := modload.ListModules(ctx, args, mode, *listReuse) 570 if !*listE { 571 for _, m := range mods { 572 if m.Error != nil { 573 base.Error(errors.New(m.Error.Err)) 574 } 575 } 576 if err != nil { 577 base.Error(err) 578 } 579 base.ExitIfErrors() 580 } 581 for _, m := range mods { 582 do(m) 583 } 584 return 585 } 586 587 // Package mode (not -m). 588 if *listU { 589 base.Fatalf("go list -u can only be used with -m") 590 } 591 if *listVersions { 592 base.Fatalf("go list -versions can only be used with -m") 593 } 594 595 // These pairings make no sense. 596 if *listFind && *listDeps { 597 base.Fatalf("go list -deps cannot be used with -find") 598 } 599 if *listFind && *listTest { 600 base.Fatalf("go list -test cannot be used with -find") 601 } 602 if *listFind && *listExport { 603 base.Fatalf("go list -export cannot be used with -find") 604 } 605 606 pkgOpts := load.PackageOpts{ 607 IgnoreImports: *listFind, 608 ModResolveTests: *listTest, 609 AutoVCS: true, 610 SuppressBuildInfo: !*listExport && !listJsonFields.needAny("Stale", "StaleReason"), 611 SuppressEmbedFiles: !*listExport && !listJsonFields.needAny("EmbedFiles", "TestEmbedFiles", "XTestEmbedFiles"), 612 } 613 pkgs := load.PackagesAndErrors(ctx, pkgOpts, args) 614 if !*listE { 615 w := 0 616 for _, pkg := range pkgs { 617 if pkg.Error != nil { 618 base.Errorf("%v", pkg.Error) 619 continue 620 } 621 pkgs[w] = pkg 622 w++ 623 } 624 pkgs = pkgs[:w] 625 base.ExitIfErrors() 626 } 627 628 if *listTest { 629 c := cache.Default() 630 // Add test binaries to packages to be listed. 631 632 var wg sync.WaitGroup 633 sema := semaphore.NewWeighted(int64(runtime.GOMAXPROCS(0))) 634 type testPackageSet struct { 635 p, pmain, ptest, pxtest *load.Package 636 } 637 var testPackages []testPackageSet 638 for _, p := range pkgs { 639 if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 { 640 var pmain, ptest, pxtest *load.Package 641 var err error 642 if *listE { 643 sema.Acquire(ctx, 1) 644 wg.Add(1) 645 done := func() { 646 sema.Release(1) 647 wg.Done() 648 } 649 pmain, ptest, pxtest = load.TestPackagesAndErrors(ctx, done, pkgOpts, p, nil) 650 } else { 651 pmain, ptest, pxtest, err = load.TestPackagesFor(ctx, pkgOpts, p, nil) 652 if err != nil { 653 base.Fatalf("go: can't load test package: %s", err) 654 } 655 } 656 testPackages = append(testPackages, testPackageSet{p, pmain, ptest, pxtest}) 657 } 658 } 659 wg.Wait() 660 for _, pkgset := range testPackages { 661 p, pmain, ptest, pxtest := pkgset.p, pkgset.pmain, pkgset.ptest, pkgset.pxtest 662 if pmain != nil { 663 pkgs = append(pkgs, pmain) 664 data := *pmain.Internal.TestmainGo 665 sema.Acquire(ctx, 1) 666 wg.Add(1) 667 go func() { 668 h := cache.NewHash("testmain") 669 h.Write([]byte("testmain\n")) 670 h.Write(data) 671 out, _, err := c.Put(h.Sum(), bytes.NewReader(data)) 672 if err != nil { 673 base.Fatalf("%s", err) 674 } 675 pmain.GoFiles[0] = c.OutputFile(out) 676 sema.Release(1) 677 wg.Done() 678 }() 679 680 } 681 if ptest != nil && ptest != p { 682 pkgs = append(pkgs, ptest) 683 } 684 if pxtest != nil { 685 pkgs = append(pkgs, pxtest) 686 } 687 } 688 689 wg.Wait() 690 } 691 692 // Remember which packages are named on the command line. 693 cmdline := make(map[*load.Package]bool) 694 for _, p := range pkgs { 695 cmdline[p] = true 696 } 697 698 if *listDeps { 699 // Note: This changes the order of the listed packages 700 // from "as written on the command line" to 701 // "a depth-first post-order traversal". 702 // (The dependency exploration order for a given node 703 // is alphabetical, same as listed in .Deps.) 704 // Note that -deps is applied after -test, 705 // so that you only get descriptions of tests for the things named 706 // explicitly on the command line, not for all dependencies. 707 pkgs = loadPackageList(pkgs) 708 } 709 710 // Do we need to run a build to gather information? 711 needStale := (listJson && listJsonFields.needAny("Stale", "StaleReason")) || strings.Contains(*listFmt, ".Stale") 712 if needStale || *listExport || *listCompiled { 713 b := work.NewBuilder("") 714 if *listE { 715 b.AllowErrors = true 716 } 717 defer func() { 718 if err := b.Close(); err != nil { 719 base.Fatal(err) 720 } 721 }() 722 723 b.IsCmdList = true 724 b.NeedExport = *listExport 725 b.NeedCompiledGoFiles = *listCompiled 726 a := &work.Action{} 727 // TODO: Use pkgsFilter? 728 for _, p := range pkgs { 729 if len(p.GoFiles)+len(p.CgoFiles) > 0 { 730 a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p)) 731 } 732 } 733 if cfg.Experiment.CoverageRedesign && cfg.BuildCover { 734 load.PrepareForCoverageBuild(pkgs) 735 } 736 b.Do(ctx, a) 737 } 738 739 for _, p := range pkgs { 740 // Show vendor-expanded paths in listing 741 p.TestImports = p.Resolve(p.TestImports) 742 p.XTestImports = p.Resolve(p.XTestImports) 743 p.DepOnly = !cmdline[p] 744 745 if *listCompiled { 746 p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports) 747 } 748 } 749 750 if *listTest || (cfg.BuildPGO == "auto" && len(cmdline) > 1) { 751 all := pkgs 752 if !*listDeps { 753 all = loadPackageList(pkgs) 754 } 755 // Update import paths to distinguish the real package p 756 // from p recompiled for q.test, or to distinguish between 757 // p compiled with different PGO profiles. 758 // This must happen only once the build code is done 759 // looking at import paths, because it will get very confused 760 // if it sees these. 761 old := make(map[string]string) 762 for _, p := range all { 763 if p.ForTest != "" || p.Internal.ForMain != "" { 764 new := p.Desc() 765 old[new] = p.ImportPath 766 p.ImportPath = new 767 } 768 p.DepOnly = !cmdline[p] 769 } 770 // Update import path lists to use new strings. 771 m := make(map[string]string) 772 for _, p := range all { 773 for _, p1 := range p.Internal.Imports { 774 if p1.ForTest != "" || p1.Internal.ForMain != "" { 775 m[old[p1.ImportPath]] = p1.ImportPath 776 } 777 } 778 for i, old := range p.Imports { 779 if new := m[old]; new != "" { 780 p.Imports[i] = new 781 } 782 } 783 clear(m) 784 } 785 } 786 787 if listJsonFields.needAny("Deps", "DepsErrors") { 788 all := pkgs 789 // Make sure we iterate through packages in a postorder traversal, 790 // which load.PackageList guarantees. If *listDeps, then all is 791 // already in PackageList order. Otherwise, calling load.PackageList 792 // provides the guarantee. In the case of an import cycle, the last package 793 // visited in the cycle, importing the first encountered package in the cycle, 794 // is visited first. The cycle import error will be bubbled up in the traversal 795 // order up to the first package in the cycle, covering all the packages 796 // in the cycle. 797 if !*listDeps { 798 all = load.PackageList(pkgs) 799 } 800 if listJsonFields.needAny("Deps") { 801 for _, p := range all { 802 collectDeps(p) 803 } 804 } 805 if listJsonFields.needAny("DepsErrors") { 806 for _, p := range all { 807 collectDepsErrors(p) 808 } 809 } 810 } 811 812 // TODO(golang.org/issue/40676): This mechanism could be extended to support 813 // -u without -m. 814 if *listRetracted { 815 // Load retractions for modules that provide packages that will be printed. 816 // TODO(golang.org/issue/40775): Packages from the same module refer to 817 // distinct ModulePublic instance. It would be nice if they could all point 818 // to the same instance. This would require additional global state in 819 // modload.loaded, so that should be refactored first. For now, we update 820 // all instances. 821 modToArg := make(map[*modinfo.ModulePublic]string) 822 argToMods := make(map[string][]*modinfo.ModulePublic) 823 var args []string 824 addModule := func(mod *modinfo.ModulePublic) { 825 if mod.Version == "" { 826 return 827 } 828 arg := fmt.Sprintf("%s@%s", mod.Path, mod.Version) 829 if argToMods[arg] == nil { 830 args = append(args, arg) 831 } 832 argToMods[arg] = append(argToMods[arg], mod) 833 modToArg[mod] = arg 834 } 835 for _, p := range pkgs { 836 if p.Module == nil { 837 continue 838 } 839 addModule(p.Module) 840 if p.Module.Replace != nil { 841 addModule(p.Module.Replace) 842 } 843 } 844 845 if len(args) > 0 { 846 var mode modload.ListMode 847 if *listRetracted { 848 mode |= modload.ListRetracted 849 } 850 rmods, err := modload.ListModules(ctx, args, mode, *listReuse) 851 if err != nil && !*listE { 852 base.Error(err) 853 } 854 for i, arg := range args { 855 rmod := rmods[i] 856 for _, mod := range argToMods[arg] { 857 mod.Retracted = rmod.Retracted 858 if rmod.Error != nil && mod.Error == nil { 859 mod.Error = rmod.Error 860 } 861 } 862 } 863 } 864 } 865 866 // Record non-identity import mappings in p.ImportMap. 867 for _, p := range pkgs { 868 nRaw := len(p.Internal.RawImports) 869 for i, path := range p.Imports { 870 var srcPath string 871 if i < nRaw { 872 srcPath = p.Internal.RawImports[i] 873 } else { 874 // This path is not within the raw imports, so it must be an import 875 // found only within CompiledGoFiles. Those paths are found in 876 // CompiledImports. 877 srcPath = p.Internal.CompiledImports[i-nRaw] 878 } 879 880 if path != srcPath { 881 if p.ImportMap == nil { 882 p.ImportMap = make(map[string]string) 883 } 884 p.ImportMap[srcPath] = path 885 } 886 } 887 } 888 889 for _, p := range pkgs { 890 do(&p.PackagePublic) 891 } 892 } 893 894 // loadPackageList is like load.PackageList, but prints error messages and exits 895 // with nonzero status if listE is not set and any package in the expanded list 896 // has errors. 897 func loadPackageList(roots []*load.Package) []*load.Package { 898 pkgs := load.PackageList(roots) 899 900 if !*listE { 901 for _, pkg := range pkgs { 902 if pkg.Error != nil { 903 base.Errorf("%v", pkg.Error) 904 } 905 } 906 } 907 908 return pkgs 909 } 910 911 // collectDeps populates p.Deps by iterating over p.Internal.Imports. 912 // collectDeps must be called on all of p's Imports before being called on p. 913 func collectDeps(p *load.Package) { 914 deps := make(map[string]bool) 915 916 for _, p := range p.Internal.Imports { 917 deps[p.ImportPath] = true 918 for _, q := range p.Deps { 919 deps[q] = true 920 } 921 } 922 923 p.Deps = make([]string, 0, len(deps)) 924 for dep := range deps { 925 p.Deps = append(p.Deps, dep) 926 } 927 sort.Strings(p.Deps) 928 } 929 930 // collectDeps populates p.DepsErrors by iterating over p.Internal.Imports. 931 // collectDepsErrors must be called on all of p's Imports before being called on p. 932 func collectDepsErrors(p *load.Package) { 933 depsErrors := make(map[*load.PackageError]bool) 934 935 for _, p := range p.Internal.Imports { 936 if p.Error != nil { 937 depsErrors[p.Error] = true 938 } 939 for _, q := range p.DepsErrors { 940 depsErrors[q] = true 941 } 942 } 943 944 p.DepsErrors = make([]*load.PackageError, 0, len(depsErrors)) 945 for deperr := range depsErrors { 946 p.DepsErrors = append(p.DepsErrors, deperr) 947 } 948 // Sort packages by the package on the top of the stack, which should be 949 // the package the error was produced for. Each package can have at most 950 // one error set on it. 951 sort.Slice(p.DepsErrors, func(i, j int) bool { 952 stki, stkj := p.DepsErrors[i].ImportStack, p.DepsErrors[j].ImportStack 953 // Some packages are missing import stacks. To ensure deterministic 954 // sort order compare two errors that are missing import stacks by 955 // their errors' error texts. 956 if len(stki) == 0 { 957 if len(stkj) != 0 { 958 return true 959 } 960 961 return p.DepsErrors[i].Err.Error() < p.DepsErrors[j].Err.Error() 962 } else if len(stkj) == 0 { 963 return false 964 } 965 pathi, pathj := stki[len(stki)-1], stkj[len(stkj)-1] 966 return pathi < pathj 967 }) 968 } 969 970 // TrackingWriter tracks the last byte written on every write so 971 // we can avoid printing a newline if one was already written or 972 // if there is no output at all. 973 type TrackingWriter struct { 974 w *bufio.Writer 975 last byte 976 } 977 978 func newTrackingWriter(w io.Writer) *TrackingWriter { 979 return &TrackingWriter{ 980 w: bufio.NewWriter(w), 981 last: '\n', 982 } 983 } 984 985 func (t *TrackingWriter) Write(p []byte) (n int, err error) { 986 n, err = t.w.Write(p) 987 if n > 0 { 988 t.last = p[n-1] 989 } 990 return 991 } 992 993 func (t *TrackingWriter) Flush() { 994 t.w.Flush() 995 } 996 997 func (t *TrackingWriter) NeedNL() bool { 998 return t.last != '\n' 999 }