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