aboutsummaryrefslogblamecommitdiffstats
path: root/vendor/golang.org/x/tools/imports/mkindex.go
blob: 755e2394f2d75ff74b4c753e0776b2381afc6cf3 (plain) (tree)












































































































































































                                                                                           
// +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
}