123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- // +build ignore
- // Copyright 2013 The Go Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style
- // license that can be found in the LICENSE file.
- // Command mkindex creates the file "pkgindex.go" containing an index of the Go
- // standard library. The file is intended to be built as part of the imports
- // package, so that the package may be used in environments where a GOROOT is
- // not available (such as App Engine).
- package main
- import (
- "bytes"
- "fmt"
- "go/ast"
- "go/build"
- "go/format"
- "go/parser"
- "go/token"
- "io/ioutil"
- "log"
- "os"
- "path"
- "path/filepath"
- "strings"
- )
- var (
- pkgIndex = make(map[string][]pkg)
- exports = make(map[string]map[string]bool)
- )
- func main() {
- // Don't use GOPATH.
- ctx := build.Default
- ctx.GOPATH = ""
- // Populate pkgIndex global from GOROOT.
- for _, path := range ctx.SrcDirs() {
- f, err := os.Open(path)
- if err != nil {
- log.Print(err)
- continue
- }
- children, err := f.Readdir(-1)
- f.Close()
- if err != nil {
- log.Print(err)
- continue
- }
- for _, child := range children {
- if child.IsDir() {
- loadPkg(path, child.Name())
- }
- }
- }
- // Populate exports global.
- for _, ps := range pkgIndex {
- for _, p := range ps {
- e := loadExports(p.dir)
- if e != nil {
- exports[p.dir] = e
- }
- }
- }
- // Construct source file.
- var buf bytes.Buffer
- fmt.Fprint(&buf, pkgIndexHead)
- fmt.Fprintf(&buf, "var pkgIndexMaster = %#v\n", pkgIndex)
- fmt.Fprintf(&buf, "var exportsMaster = %#v\n", exports)
- src := buf.Bytes()
- // Replace main.pkg type name with pkg.
- src = bytes.Replace(src, []byte("main.pkg"), []byte("pkg"), -1)
- // Replace actual GOROOT with "/go".
- src = bytes.Replace(src, []byte(ctx.GOROOT), []byte("/go"), -1)
- // Add some line wrapping.
- src = bytes.Replace(src, []byte("}, "), []byte("},\n"), -1)
- src = bytes.Replace(src, []byte("true, "), []byte("true,\n"), -1)
- var err error
- src, err = format.Source(src)
- if err != nil {
- log.Fatal(err)
- }
- // Write out source file.
- err = ioutil.WriteFile("pkgindex.go", src, 0644)
- if err != nil {
- log.Fatal(err)
- }
- }
- const pkgIndexHead = `package imports
- func init() {
- pkgIndexOnce.Do(func() {
- pkgIndex.m = pkgIndexMaster
- })
- loadExports = func(dir string) map[string]bool {
- return exportsMaster[dir]
- }
- }
- `
- type pkg struct {
- importpath string // full pkg import path, e.g. "net/http"
- dir string // absolute file path to pkg directory e.g. "/usr/lib/go/src/fmt"
- }
- var fset = token.NewFileSet()
- func loadPkg(root, importpath string) {
- shortName := path.Base(importpath)
- if shortName == "testdata" {
- return
- }
- dir := filepath.Join(root, importpath)
- pkgIndex[shortName] = append(pkgIndex[shortName], pkg{
- importpath: importpath,
- dir: dir,
- })
- pkgDir, err := os.Open(dir)
- if err != nil {
- return
- }
- children, err := pkgDir.Readdir(-1)
- pkgDir.Close()
- if err != nil {
- return
- }
- for _, child := range children {
- name := child.Name()
- if name == "" {
- continue
- }
- if c := name[0]; c == '.' || ('0' <= c && c <= '9') {
- continue
- }
- if child.IsDir() {
- loadPkg(root, filepath.Join(importpath, name))
- }
- }
- }
- func loadExports(dir string) map[string]bool {
- exports := make(map[string]bool)
- buildPkg, err := build.ImportDir(dir, 0)
- if err != nil {
- if strings.Contains(err.Error(), "no buildable Go source files in") {
- return nil
- }
- log.Printf("could not import %q: %v", dir, err)
- return nil
- }
- for _, file := range buildPkg.GoFiles {
- f, err := parser.ParseFile(fset, filepath.Join(dir, file), nil, 0)
- if err != nil {
- log.Printf("could not parse %q: %v", file, err)
- continue
- }
- for name := range f.Scope.Objects {
- if ast.IsExported(name) {
- exports[name] = true
- }
- }
- }
- return exports
- }
|