github.com/pankona/gometalinter@v2.0.11+incompatible/_linters/src/golang.org/x/tools/imports/mkindex.go (about) 1 // +build ignore 2 3 // Copyright 2013 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 // Command mkindex creates the file "pkgindex.go" containing an index of the Go 8 // standard library. The file is intended to be built as part of the imports 9 // package, so that the package may be used in environments where a GOROOT is 10 // not available (such as App Engine). 11 package main 12 13 import ( 14 "bytes" 15 "fmt" 16 "go/ast" 17 "go/build" 18 "go/format" 19 "go/parser" 20 "go/token" 21 "io/ioutil" 22 "log" 23 "os" 24 "path" 25 "path/filepath" 26 "strings" 27 ) 28 29 var ( 30 pkgIndex = make(map[string][]pkg) 31 exports = make(map[string]map[string]bool) 32 ) 33 34 func main() { 35 // Don't use GOPATH. 36 ctx := build.Default 37 ctx.GOPATH = "" 38 39 // Populate pkgIndex global from GOROOT. 40 for _, path := range ctx.SrcDirs() { 41 f, err := os.Open(path) 42 if err != nil { 43 log.Print(err) 44 continue 45 } 46 children, err := f.Readdir(-1) 47 f.Close() 48 if err != nil { 49 log.Print(err) 50 continue 51 } 52 for _, child := range children { 53 if child.IsDir() { 54 loadPkg(path, child.Name()) 55 } 56 } 57 } 58 // Populate exports global. 59 for _, ps := range pkgIndex { 60 for _, p := range ps { 61 e := loadExports(p.dir) 62 if e != nil { 63 exports[p.dir] = e 64 } 65 } 66 } 67 68 // Construct source file. 69 var buf bytes.Buffer 70 fmt.Fprint(&buf, pkgIndexHead) 71 fmt.Fprintf(&buf, "var pkgIndexMaster = %#v\n", pkgIndex) 72 fmt.Fprintf(&buf, "var exportsMaster = %#v\n", exports) 73 src := buf.Bytes() 74 75 // Replace main.pkg type name with pkg. 76 src = bytes.Replace(src, []byte("main.pkg"), []byte("pkg"), -1) 77 // Replace actual GOROOT with "/go". 78 src = bytes.Replace(src, []byte(ctx.GOROOT), []byte("/go"), -1) 79 // Add some line wrapping. 80 src = bytes.Replace(src, []byte("}, "), []byte("},\n"), -1) 81 src = bytes.Replace(src, []byte("true, "), []byte("true,\n"), -1) 82 83 var err error 84 src, err = format.Source(src) 85 if err != nil { 86 log.Fatal(err) 87 } 88 89 // Write out source file. 90 err = ioutil.WriteFile("pkgindex.go", src, 0644) 91 if err != nil { 92 log.Fatal(err) 93 } 94 } 95 96 const pkgIndexHead = `package imports 97 98 func init() { 99 pkgIndexOnce.Do(func() { 100 pkgIndex.m = pkgIndexMaster 101 }) 102 loadExports = func(dir string) map[string]bool { 103 return exportsMaster[dir] 104 } 105 } 106 ` 107 108 type pkg struct { 109 importpath string // full pkg import path, e.g. "net/http" 110 dir string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt" 111 } 112 113 var fset = token.NewFileSet() 114 115 func loadPkg(root, importpath string) { 116 shortName := path.Base(importpath) 117 if shortName == "testdata" { 118 return 119 } 120 121 dir := filepath.Join(root, importpath) 122 pkgIndex[shortName] = append(pkgIndex[shortName], pkg{ 123 importpath: importpath, 124 dir: dir, 125 }) 126 127 pkgDir, err := os.Open(dir) 128 if err != nil { 129 return 130 } 131 children, err := pkgDir.Readdir(-1) 132 pkgDir.Close() 133 if err != nil { 134 return 135 } 136 for _, child := range children { 137 name := child.Name() 138 if name == "" { 139 continue 140 } 141 if c := name[0]; c == '.' || ('0' <= c && c <= '9') { 142 continue 143 } 144 if child.IsDir() { 145 loadPkg(root, filepath.Join(importpath, name)) 146 } 147 } 148 } 149 150 func loadExports(dir string) map[string]bool { 151 exports := make(map[string]bool) 152 buildPkg, err := build.ImportDir(dir, 0) 153 if err != nil { 154 if strings.Contains(err.Error(), "no buildable Go source files in") { 155 return nil 156 } 157 log.Printf("could not import %q: %v", dir, err) 158 return nil 159 } 160 for _, file := range buildPkg.GoFiles { 161 f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0) 162 if err != nil { 163 log.Printf("could not parse %q: %v", file, err) 164 continue 165 } 166 for name := range f.Scope.Objects { 167 if ast.IsExported(name) { 168 exports[name] = true 169 } 170 } 171 } 172 return exports 173 }