1package packages
2
3import (
4 "fmt"
5 "os"
6 "sort"
7)
8
9// Visit visits all the packages in the import graph whose roots are
10// pkgs, calling the optional pre function the first time each package
11// is encountered (preorder), and the optional post function after a
12// package's dependencies have been visited (postorder).
13// The boolean result of pre(pkg) determines whether
14// the imports of package pkg are visited.
15func Visit(pkgs []*Package, pre func(*Package) bool, post func(*Package)) {
16 seen := make(map[*Package]bool)
17 var visit func(*Package)
18 visit = func(pkg *Package) {
19 if !seen[pkg] {
20 seen[pkg] = true
21
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
33 if post != nil {
34 post(pkg)
35 }
36 }
37 }
38 for _, pkg := range pkgs {
39 visit(pkg)
40 }
41}
42
43// PrintErrors prints to os.Stderr the accumulated errors of all
44// packages in the import graph rooted at pkgs, dependencies first.
45// PrintErrors returns the number of errors printed.
46func PrintErrors(pkgs []*Package) int {
47 var n int
48 Visit(pkgs, nil, func(pkg *Package) {
49 for _, err := range pkg.Errors {
50 fmt.Fprintln(os.Stderr, err)
51 n++
52 }
53 })
54 return n
55}