github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/buildutil/allpackages.go (about) 1 // Copyright 2014 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 buildutil provides utilities related to the go/build 6 // package in the standard library. 7 // 8 // All I/O is done via the build.Context file system interface, which must 9 // be concurrency-safe. 10 package buildutil // import "llvm.org/llgo/third_party/gotools/go/buildutil" 11 12 import ( 13 "go/build" 14 "os" 15 "path/filepath" 16 "sort" 17 "strings" 18 "sync" 19 ) 20 21 // AllPackages returns the import path of each Go package in any source 22 // directory of the specified build context (e.g. $GOROOT or an element 23 // of $GOPATH). Errors are ignored. The results are sorted. 24 // 25 // The result may include import paths for directories that contain no 26 // *.go files, such as "archive" (in $GOROOT/src). 27 // 28 // All I/O is done via the build.Context file system interface, 29 // which must be concurrency-safe. 30 // 31 func AllPackages(ctxt *build.Context) []string { 32 var list []string 33 ForEachPackage(ctxt, func(pkg string, _ error) { 34 list = append(list, pkg) 35 }) 36 sort.Strings(list) 37 return list 38 } 39 40 // ForEachPackage calls the found function with the import path of 41 // each Go package it finds in any source directory of the specified 42 // build context (e.g. $GOROOT or an element of $GOPATH). 43 // 44 // If the package directory exists but could not be read, the second 45 // argument to the found function provides the error. 46 // 47 // All I/O is done via the build.Context file system interface, 48 // which must be concurrency-safe. 49 // 50 func ForEachPackage(ctxt *build.Context, found func(importPath string, err error)) { 51 // We use a counting semaphore to limit 52 // the number of parallel calls to ReadDir. 53 sema := make(chan bool, 20) 54 55 ch := make(chan item) 56 57 var wg sync.WaitGroup 58 for _, root := range ctxt.SrcDirs() { 59 root := root 60 wg.Add(1) 61 go func() { 62 allPackages(ctxt, sema, root, ch) 63 wg.Done() 64 }() 65 } 66 go func() { 67 wg.Wait() 68 close(ch) 69 }() 70 71 // All calls to found occur in the caller's goroutine. 72 for i := range ch { 73 found(i.importPath, i.err) 74 } 75 } 76 77 type item struct { 78 importPath string 79 err error // (optional) 80 } 81 82 func allPackages(ctxt *build.Context, sema chan bool, root string, ch chan<- item) { 83 root = filepath.Clean(root) + string(os.PathSeparator) 84 85 var wg sync.WaitGroup 86 87 var walkDir func(dir string) 88 walkDir = func(dir string) { 89 // Avoid .foo, _foo, and testdata directory trees. 90 base := filepath.Base(dir) 91 if base == "" || base[0] == '.' || base[0] == '_' || base == "testdata" { 92 return 93 } 94 95 pkg := filepath.ToSlash(strings.TrimPrefix(dir, root)) 96 97 // Prune search if we encounter any of these import paths. 98 switch pkg { 99 case "builtin": 100 return 101 } 102 103 sema <- true 104 files, err := ReadDir(ctxt, dir) 105 <-sema 106 if pkg != "" || err != nil { 107 ch <- item{pkg, err} 108 } 109 for _, fi := range files { 110 fi := fi 111 if fi.IsDir() { 112 wg.Add(1) 113 go func() { 114 walkDir(filepath.Join(dir, fi.Name())) 115 wg.Done() 116 }() 117 } 118 } 119 } 120 121 walkDir(root) 122 wg.Wait() 123 }