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