github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/go/not-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 "encoding/json" 12 "io" 13 "os" 14 "sort" 15 "strings" 16 "text/template" 17 18 "github.com/gagliardetto/golang-go/cmd/go/not-internal/base" 19 "github.com/gagliardetto/golang-go/cmd/go/not-internal/cache" 20 "github.com/gagliardetto/golang-go/cmd/go/not-internal/cfg" 21 "github.com/gagliardetto/golang-go/cmd/go/not-internal/load" 22 "github.com/gagliardetto/golang-go/cmd/go/not-internal/modload" 23 "github.com/gagliardetto/golang-go/cmd/go/not-internal/str" 24 "github.com/gagliardetto/golang-go/cmd/go/not-internal/work" 25 ) 26 27 var CmdList = &base.Command{ 28 // Note: -f -json -m are listed explicitly because they are the most common list flags. 29 // Do not send CLs removing them because they're covered by [list flags]. 30 UsageLine: "go list [-f format] [-json] [-m] [list flags] [build flags] [packages]", 31 Short: "list packages or modules", 32 Long: ` 33 List lists the named packages, one per line. 34 The most commonly-used flags are -f and -json, which control the form 35 of the output printed for each package. Other list flags, documented below, 36 control more specific details. 37 38 The default output shows the package import path: 39 40 bytes 41 encoding/json 42 github.com/gorilla/mux 43 golang.org/x/net/html 44 45 The -f flag specifies an alternate format for the list, using the 46 syntax of package template. The default output is equivalent 47 to -f '{{.ImportPath}}'. The struct being passed to the template is: 48 49 type Package struct { 50 Dir string // directory containing package sources 51 ImportPath string // import path of package in dir 52 ImportComment string // path in import comment on package statement 53 Name string // package name 54 Doc string // package documentation string 55 Target string // install path 56 Shlib string // the shared library that contains this package (only set when -linkshared) 57 Goroot bool // is this package in the Go root? 58 Standard bool // is this package part of the standard Go library? 59 Stale bool // would 'go install' do anything for this package? 60 StaleReason string // explanation for Stale==true 61 Root string // Go root or Go path dir containing this package 62 ConflictDir string // this directory shadows Dir in $GOPATH 63 BinaryOnly bool // binary-only package (no longer supported) 64 ForTest string // package is only for use in named test 65 Export string // file containing export data (when using -export) 66 Module *Module // info about package's containing module, if any (can be nil) 67 Match []string // command-line patterns matching this package 68 DepOnly bool // package is only a dependency, not explicitly listed 69 70 // Source files 71 GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles) 72 CgoFiles []string // .go source files that import "C" 73 CompiledGoFiles []string // .go files presented to compiler (when using -compiled) 74 IgnoredGoFiles []string // .go source files ignored due to build constraints 75 CFiles []string // .c source files 76 CXXFiles []string // .cc, .cxx and .cpp source files 77 MFiles []string // .m source files 78 HFiles []string // .h, .hh, .hpp and .hxx source files 79 FFiles []string // .f, .F, .for and .f90 Fortran source files 80 SFiles []string // .s source files 81 SwigFiles []string // .swig files 82 SwigCXXFiles []string // .swigcxx files 83 SysoFiles []string // .syso object files to add to archive 84 TestGoFiles []string // _test.go files in package 85 XTestGoFiles []string // _test.go files outside package 86 87 // Cgo directives 88 CgoCFLAGS []string // cgo: flags for C compiler 89 CgoCPPFLAGS []string // cgo: flags for C preprocessor 90 CgoCXXFLAGS []string // cgo: flags for C++ compiler 91 CgoFFLAGS []string // cgo: flags for Fortran compiler 92 CgoLDFLAGS []string // cgo: flags for linker 93 CgoPkgConfig []string // cgo: pkg-config names 94 95 // Dependency information 96 Imports []string // import paths used by this package 97 ImportMap map[string]string // map from source import to ImportPath (identity entries omitted) 98 Deps []string // all (recursively) imported dependencies 99 TestImports []string // imports from TestGoFiles 100 XTestImports []string // imports from XTestGoFiles 101 102 // Error information 103 Incomplete bool // this package or a dependency has an error 104 Error *PackageError // error loading package 105 DepsErrors []*PackageError // errors loading dependencies 106 } 107 108 Packages stored in vendor directories report an ImportPath that includes the 109 path to the vendor directory (for example, "d/vendor/p" instead of "p"), 110 so that the ImportPath uniquely identifies a given copy of a package. 111 The Imports, Deps, TestImports, and XTestImports lists also contain these 112 expanded import paths. See golang.org/s/go15vendor for more about vendoring. 113 114 The error information, if any, is 115 116 type PackageError struct { 117 ImportStack []string // shortest path from package named on command line to this one 118 Pos string // position of error (if present, file:line:col) 119 Err string // the error itself 120 } 121 122 The module information is a Module struct, defined in the discussion 123 of list -m below. 124 125 The template function "join" calls strings.Join. 126 127 The template function "context" returns the build context, defined as: 128 129 type Context struct { 130 GOARCH string // target architecture 131 GOOS string // target operating system 132 GOROOT string // Go root 133 GOPATH string // Go path 134 CgoEnabled bool // whether cgo can be used 135 UseAllFiles bool // use files regardless of +build lines, file names 136 Compiler string // compiler to assume when computing target paths 137 BuildTags []string // build constraints to match in +build lines 138 ReleaseTags []string // releases the current release is compatible with 139 InstallSuffix string // suffix to use in the name of the install dir 140 } 141 142 For more information about the meaning of these fields see the documentation 143 for the go/build package's Context type. 144 145 The -json flag causes the package data to be printed in JSON format 146 instead of using the template format. 147 148 The -compiled flag causes list to set CompiledGoFiles to the Go source 149 files presented to the compiler. Typically this means that it repeats 150 the files listed in GoFiles and then also adds the Go code generated 151 by processing CgoFiles and SwigFiles. The Imports list contains the 152 union of all imports from both GoFiles and CompiledGoFiles. 153 154 The -deps flag causes list to iterate over not just the named packages 155 but also all their dependencies. It visits them in a depth-first post-order 156 traversal, so that a package is listed only after all its dependencies. 157 Packages not explicitly listed on the command line will have the DepOnly 158 field set to true. 159 160 The -e flag changes the handling of erroneous packages, those that 161 cannot be found or are malformed. By default, the list command 162 prints an error to standard error for each erroneous package and 163 omits the packages from consideration during the usual printing. 164 With the -e flag, the list command never prints errors to standard 165 error and instead processes the erroneous packages with the usual 166 printing. Erroneous packages will have a non-empty ImportPath and 167 a non-nil Error field; other information may or may not be missing 168 (zeroed). 169 170 The -export flag causes list to set the Export field to the name of a 171 file containing up-to-date export information for the given package. 172 173 The -find flag causes list to identify the named packages but not 174 resolve their dependencies: the Imports and Deps lists will be empty. 175 176 The -test flag causes list to report not only the named packages 177 but also their test binaries (for packages with tests), to convey to 178 source code analysis tools exactly how test binaries are constructed. 179 The reported import path for a test binary is the import path of 180 the package followed by a ".test" suffix, as in "math/rand.test". 181 When building a test, it is sometimes necessary to rebuild certain 182 dependencies specially for that test (most commonly the tested 183 package itself). The reported import path of a package recompiled 184 for a particular test binary is followed by a space and the name of 185 the test binary in brackets, as in "math/rand [math/rand.test]" 186 or "regexp [sort.test]". The ForTest field is also set to the name 187 of the package being tested ("math/rand" or "sort" in the previous 188 examples). 189 190 The Dir, Target, Shlib, Root, ConflictDir, and Export file paths 191 are all absolute paths. 192 193 By default, the lists GoFiles, CgoFiles, and so on hold names of files in Dir 194 (that is, paths relative to Dir, not absolute paths). 195 The generated files added when using the -compiled and -test flags 196 are absolute paths referring to cached copies of generated Go source files. 197 Although they are Go source files, the paths may not end in ".go". 198 199 The -m flag causes list to list modules instead of packages. 200 201 When listing modules, the -f flag still specifies a format template 202 applied to a Go struct, but now a Module struct: 203 204 type Module struct { 205 Path string // module path 206 Version string // module version 207 Versions []string // available module versions (with -versions) 208 Replace *Module // replaced by this module 209 Time *time.Time // time version was created 210 Update *Module // available update, if any (with -u) 211 Main bool // is this the main module? 212 Indirect bool // is this module only an indirect dependency of main module? 213 Dir string // directory holding files for this module, if any 214 GoMod string // path to go.mod file used when loading this module, if any 215 GoVersion string // go version used in module 216 Error *ModuleError // error loading module 217 } 218 219 type ModuleError struct { 220 Err string // the error itself 221 } 222 223 The file GoMod refers to may be outside the module directory if the 224 module is in the module cache or if the -modfile flag is used. 225 226 The default output is to print the module path and then 227 information about the version and replacement if any. 228 For example, 'go list -m all' might print: 229 230 my/main/module 231 golang.org/x/text v0.3.0 => /tmp/text 232 rsc.io/pdf v0.1.1 233 234 The Module struct has a String method that formats this 235 line of output, so that the default format is equivalent 236 to -f '{{.String}}'. 237 238 Note that when a module has been replaced, its Replace field 239 describes the replacement module, and its Dir field is set to 240 the replacement's source code, if present. (That is, if Replace 241 is non-nil, then Dir is set to Replace.Dir, with no access to 242 the replaced source code.) 243 244 The -u flag adds information about available upgrades. 245 When the latest version of a given module is newer than 246 the current one, list -u sets the Module's Update field 247 to information about the newer module. 248 The Module's String method indicates an available upgrade by 249 formatting the newer version in brackets after the current version. 250 For example, 'go list -m -u all' might print: 251 252 my/main/module 253 golang.org/x/text v0.3.0 [v0.4.0] => /tmp/text 254 rsc.io/pdf v0.1.1 [v0.1.2] 255 256 (For tools, 'go list -m -u -json all' may be more convenient to parse.) 257 258 The -versions flag causes list to set the Module's Versions field 259 to a list of all known versions of that module, ordered according 260 to semantic versioning, earliest to latest. The flag also changes 261 the default output format to display the module path followed by the 262 space-separated version list. 263 264 The arguments to list -m are interpreted as a list of modules, not packages. 265 The main module is the module containing the current directory. 266 The active modules are the main module and its dependencies. 267 With no arguments, list -m shows the main module. 268 With arguments, list -m shows the modules specified by the arguments. 269 Any of the active modules can be specified by its module path. 270 The special pattern "all" specifies all the active modules, first the main 271 module and then dependencies sorted by module path. 272 A pattern containing "..." specifies the active modules whose 273 module paths match the pattern. 274 A query of the form path@version specifies the result of that query, 275 which is not limited to active modules. 276 See 'go help modules' for more about module queries. 277 278 The template function "module" takes a single string argument 279 that must be a module path or query and returns the specified 280 module as a Module struct. If an error occurs, the result will 281 be a Module struct with a non-nil Error field. 282 283 For more about build flags, see 'go help build'. 284 285 For more about specifying packages, see 'go help packages'. 286 287 For more about modules, see 'go help modules'. 288 `, 289 } 290 291 func init() { 292 CmdList.Run = runList // break init cycle 293 work.AddBuildFlags(CmdList, work.DefaultBuildFlags) 294 } 295 296 var ( 297 listCompiled = CmdList.Flag.Bool("compiled", false, "") 298 listDeps = CmdList.Flag.Bool("deps", false, "") 299 listE = CmdList.Flag.Bool("e", false, "") 300 listExport = CmdList.Flag.Bool("export", false, "") 301 listFmt = CmdList.Flag.String("f", "", "") 302 listFind = CmdList.Flag.Bool("find", false, "") 303 listJson = CmdList.Flag.Bool("json", false, "") 304 listM = CmdList.Flag.Bool("m", false, "") 305 listU = CmdList.Flag.Bool("u", false, "") 306 listTest = CmdList.Flag.Bool("test", false, "") 307 listVersions = CmdList.Flag.Bool("versions", false, "") 308 ) 309 310 var nl = []byte{'\n'} 311 312 func runList(cmd *base.Command, args []string) { 313 modload.LoadTests = *listTest 314 work.BuildInit() 315 out := newTrackingWriter(os.Stdout) 316 defer out.w.Flush() 317 318 if *listFmt == "" { 319 if *listM { 320 *listFmt = "{{.String}}" 321 if *listVersions { 322 *listFmt = `{{.Path}}{{range .Versions}} {{.}}{{end}}` 323 } 324 } else { 325 *listFmt = "{{.ImportPath}}" 326 } 327 } 328 329 var do func(interface{}) 330 if *listJson { 331 do = func(x interface{}) { 332 b, err := json.MarshalIndent(x, "", "\t") 333 if err != nil { 334 out.Flush() 335 base.Fatalf("%s", err) 336 } 337 out.Write(b) 338 out.Write(nl) 339 } 340 } else { 341 var cachedCtxt *Context 342 context := func() *Context { 343 if cachedCtxt == nil { 344 cachedCtxt = newContext(&cfg.BuildContext) 345 } 346 return cachedCtxt 347 } 348 fm := template.FuncMap{ 349 "join": strings.Join, 350 "context": context, 351 "module": modload.ModuleInfo, 352 } 353 tmpl, err := template.New("main").Funcs(fm).Parse(*listFmt) 354 if err != nil { 355 base.Fatalf("%s", err) 356 } 357 do = func(x interface{}) { 358 if err := tmpl.Execute(out, x); err != nil { 359 out.Flush() 360 base.Fatalf("%s", err) 361 } 362 if out.NeedNL() { 363 out.Write(nl) 364 } 365 } 366 } 367 368 if *listM { 369 // Module mode. 370 if *listCompiled { 371 base.Fatalf("go list -compiled cannot be used with -m") 372 } 373 if *listDeps { 374 // TODO(rsc): Could make this mean something with -m. 375 base.Fatalf("go list -deps cannot be used with -m") 376 } 377 if *listExport { 378 base.Fatalf("go list -export cannot be used with -m") 379 } 380 if *listFind { 381 base.Fatalf("go list -find cannot be used with -m") 382 } 383 if *listTest { 384 base.Fatalf("go list -test cannot be used with -m") 385 } 386 387 if modload.Init(); !modload.Enabled() { 388 base.Fatalf("go list -m: not using modules") 389 } 390 391 modload.InitMod() // Parses go.mod and sets cfg.BuildMod. 392 if cfg.BuildMod == "vendor" { 393 const actionDisabledFormat = "go list -m: can't %s using the vendor directory\n\t(Use -mod=mod or -mod=readonly to bypass.)" 394 395 if *listVersions { 396 base.Fatalf(actionDisabledFormat, "determine available versions") 397 } 398 if *listU { 399 base.Fatalf(actionDisabledFormat, "determine available upgrades") 400 } 401 402 for _, arg := range args { 403 // In vendor mode, the module graph is incomplete: it contains only the 404 // explicit module dependencies and the modules that supply packages in 405 // the import graph. Reject queries that imply more information than that. 406 if arg == "all" { 407 base.Fatalf(actionDisabledFormat, "compute 'all'") 408 } 409 if strings.Contains(arg, "...") { 410 base.Fatalf(actionDisabledFormat, "match module patterns") 411 } 412 } 413 } 414 415 modload.LoadBuildList() 416 417 mods := modload.ListModules(args, *listU, *listVersions) 418 if !*listE { 419 for _, m := range mods { 420 if m.Error != nil { 421 base.Errorf("go list -m: %v", m.Error.Err) 422 } 423 } 424 base.ExitIfErrors() 425 } 426 for _, m := range mods { 427 do(m) 428 } 429 return 430 } 431 432 // Package mode (not -m). 433 if *listU { 434 base.Fatalf("go list -u can only be used with -m") 435 } 436 if *listVersions { 437 base.Fatalf("go list -versions can only be used with -m") 438 } 439 440 // These pairings make no sense. 441 if *listFind && *listDeps { 442 base.Fatalf("go list -deps cannot be used with -find") 443 } 444 if *listFind && *listTest { 445 base.Fatalf("go list -test cannot be used with -find") 446 } 447 448 load.IgnoreImports = *listFind 449 var pkgs []*load.Package 450 if *listE { 451 pkgs = load.PackagesAndErrors(args) 452 } else { 453 pkgs = load.Packages(args) 454 } 455 456 if cache.Default() == nil { 457 // These flags return file names pointing into the build cache, 458 // so the build cache must exist. 459 if *listCompiled { 460 base.Fatalf("go list -compiled requires build cache") 461 } 462 if *listExport { 463 base.Fatalf("go list -export requires build cache") 464 } 465 if *listTest { 466 base.Fatalf("go list -test requires build cache") 467 } 468 } 469 470 if *listTest { 471 c := cache.Default() 472 // Add test binaries to packages to be listed. 473 for _, p := range pkgs { 474 if p.Error != nil { 475 continue 476 } 477 if len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 { 478 var pmain, ptest, pxtest *load.Package 479 var err error 480 if *listE { 481 pmain, ptest, pxtest = load.TestPackagesAndErrors(p, nil) 482 } else { 483 pmain, ptest, pxtest, err = load.TestPackagesFor(p, nil) 484 if err != nil { 485 base.Errorf("can't load test package: %s", err) 486 } 487 } 488 if pmain != nil { 489 pkgs = append(pkgs, pmain) 490 data := *pmain.Internal.TestmainGo 491 h := cache.NewHash("testmain") 492 h.Write([]byte("testmain\n")) 493 h.Write(data) 494 out, _, err := c.Put(h.Sum(), bytes.NewReader(data)) 495 if err != nil { 496 base.Fatalf("%s", err) 497 } 498 pmain.GoFiles[0] = c.OutputFile(out) 499 } 500 if ptest != nil && ptest != p { 501 pkgs = append(pkgs, ptest) 502 } 503 if pxtest != nil { 504 pkgs = append(pkgs, pxtest) 505 } 506 } 507 } 508 } 509 510 // Remember which packages are named on the command line. 511 cmdline := make(map[*load.Package]bool) 512 for _, p := range pkgs { 513 cmdline[p] = true 514 } 515 516 if *listDeps { 517 // Note: This changes the order of the listed packages 518 // from "as written on the command line" to 519 // "a depth-first post-order traversal". 520 // (The dependency exploration order for a given node 521 // is alphabetical, same as listed in .Deps.) 522 // Note that -deps is applied after -test, 523 // so that you only get descriptions of tests for the things named 524 // explicitly on the command line, not for all dependencies. 525 pkgs = load.PackageList(pkgs) 526 } 527 528 // Do we need to run a build to gather information? 529 needStale := *listJson || strings.Contains(*listFmt, ".Stale") 530 if needStale || *listExport || *listCompiled { 531 var b work.Builder 532 b.Init() 533 b.IsCmdList = true 534 b.NeedExport = *listExport 535 b.NeedCompiledGoFiles = *listCompiled 536 a := &work.Action{} 537 // TODO: Use pkgsFilter? 538 for _, p := range pkgs { 539 if len(p.GoFiles)+len(p.CgoFiles) > 0 { 540 a.Deps = append(a.Deps, b.AutoAction(work.ModeInstall, work.ModeInstall, p)) 541 } 542 } 543 b.Do(a) 544 } 545 546 for _, p := range pkgs { 547 // Show vendor-expanded paths in listing 548 p.TestImports = p.Resolve(p.TestImports) 549 p.XTestImports = p.Resolve(p.XTestImports) 550 p.DepOnly = !cmdline[p] 551 552 if *listCompiled { 553 p.Imports = str.StringList(p.Imports, p.Internal.CompiledImports) 554 } 555 } 556 557 if *listTest { 558 all := pkgs 559 if !*listDeps { 560 all = load.PackageList(pkgs) 561 } 562 // Update import paths to distinguish the real package p 563 // from p recompiled for q.test. 564 // This must happen only once the build code is done 565 // looking at import paths, because it will get very confused 566 // if it sees these. 567 old := make(map[string]string) 568 for _, p := range all { 569 if p.ForTest != "" { 570 new := p.ImportPath + " [" + p.ForTest + ".test]" 571 old[new] = p.ImportPath 572 p.ImportPath = new 573 } 574 p.DepOnly = !cmdline[p] 575 } 576 // Update import path lists to use new strings. 577 m := make(map[string]string) 578 for _, p := range all { 579 for _, p1 := range p.Internal.Imports { 580 if p1.ForTest != "" { 581 m[old[p1.ImportPath]] = p1.ImportPath 582 } 583 } 584 for i, old := range p.Imports { 585 if new := m[old]; new != "" { 586 p.Imports[i] = new 587 } 588 } 589 for old := range m { 590 delete(m, old) 591 } 592 } 593 // Recompute deps lists using new strings, from the leaves up. 594 for _, p := range all { 595 deps := make(map[string]bool) 596 for _, p1 := range p.Internal.Imports { 597 deps[p1.ImportPath] = true 598 for _, d := range p1.Deps { 599 deps[d] = true 600 } 601 } 602 p.Deps = make([]string, 0, len(deps)) 603 for d := range deps { 604 p.Deps = append(p.Deps, d) 605 } 606 sort.Strings(p.Deps) 607 } 608 } 609 610 // Record non-identity import mappings in p.ImportMap. 611 for _, p := range pkgs { 612 for i, srcPath := range p.Internal.RawImports { 613 path := p.Imports[i] 614 if path != srcPath { 615 if p.ImportMap == nil { 616 p.ImportMap = make(map[string]string) 617 } 618 p.ImportMap[srcPath] = path 619 } 620 } 621 } 622 623 for _, p := range pkgs { 624 do(&p.PackagePublic) 625 } 626 } 627 628 // TrackingWriter tracks the last byte written on every write so 629 // we can avoid printing a newline if one was already written or 630 // if there is no output at all. 631 type TrackingWriter struct { 632 w *bufio.Writer 633 last byte 634 } 635 636 func newTrackingWriter(w io.Writer) *TrackingWriter { 637 return &TrackingWriter{ 638 w: bufio.NewWriter(w), 639 last: '\n', 640 } 641 } 642 643 func (t *TrackingWriter) Write(p []byte) (n int, err error) { 644 n, err = t.w.Write(p) 645 if n > 0 { 646 t.last = p[n-1] 647 } 648 return 649 } 650 651 func (t *TrackingWriter) Flush() { 652 t.w.Flush() 653 } 654 655 func (t *TrackingWriter) NeedNL() bool { 656 return t.last != '\n' 657 }