visit.go 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. // Copyright 2018 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. package packages
  5. import (
  6. "fmt"
  7. "os"
  8. "sort"
  9. )
  10. // Visit visits all the packages in the import graph whose roots are
  11. // pkgs, calling the optional pre function the first time each package
  12. // is encountered (preorder), and the optional post function after a
  13. // package's dependencies have been visited (postorder).
  14. // The boolean result of pre(pkg) determines whether
  15. // the imports of package pkg are visited.
  16. func Visit(pkgs []*Package, pre func(*Package) bool, post func(*Package)) {
  17. seen := make(map[*Package]bool)
  18. var visit func(*Package)
  19. visit = func(pkg *Package) {
  20. if !seen[pkg] {
  21. seen[pkg] = true
  22. if pre == nil || pre(pkg) {
  23. paths := make([]string, 0, len(pkg.Imports))
  24. for path := range pkg.Imports {
  25. paths = append(paths, path)
  26. }
  27. sort.Strings(paths) // Imports is a map, this makes visit stable
  28. for _, path := range paths {
  29. visit(pkg.Imports[path])
  30. }
  31. }
  32. if post != nil {
  33. post(pkg)
  34. }
  35. }
  36. }
  37. for _, pkg := range pkgs {
  38. visit(pkg)
  39. }
  40. }
  41. // PrintErrors prints to os.Stderr the accumulated errors of all
  42. // packages in the import graph rooted at pkgs, dependencies first.
  43. // PrintErrors returns the number of errors printed.
  44. func PrintErrors(pkgs []*Package) int {
  45. var n int
  46. errModules := make(map[*Module]bool)
  47. Visit(pkgs, nil, func(pkg *Package) {
  48. for _, err := range pkg.Errors {
  49. fmt.Fprintln(os.Stderr, err)
  50. n++
  51. }
  52. // Print pkg.Module.Error once if present.
  53. mod := pkg.Module
  54. if mod != nil && mod.Error != nil && !errModules[mod] {
  55. errModules[mod] = true
  56. fmt.Fprintln(os.Stderr, mod.Error.Err)
  57. n++
  58. }
  59. })
  60. return n
  61. }