+++ /dev/null
-// Copyright 2014 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.
-
-package main
-
-import (
- "errors"
- "flag"
- "fmt"
- "go/build"
- "go/types"
- "io/ioutil"
- "os"
- "path/filepath"
- "strings"
-)
-
-var (
- source = flag.String("s", "", "only consider packages from src, where src is one of the supported compilers")
- verbose = flag.Bool("v", false, "verbose mode")
-)
-
-// lists of registered sources and corresponding importers
-var (
- sources []string
- importers []types.Importer
- errImportFailed = errors.New("import failed")
-)
-
-func usage() {
- fmt.Fprintln(os.Stderr, "usage: godex [flags] {path|qualifiedIdent}")
- flag.PrintDefaults()
- os.Exit(2)
-}
-
-func report(msg string) {
- fmt.Fprintln(os.Stderr, "error: "+msg)
- os.Exit(2)
-}
-
-func main() {
- flag.Usage = usage
- flag.Parse()
-
- if flag.NArg() == 0 {
- report("no package name, path, or file provided")
- }
-
- var imp types.Importer = new(tryImporters)
- if *source != "" {
- imp = lookup(*source)
- if imp == nil {
- report("source (-s argument) must be one of: " + strings.Join(sources, ", "))
- }
- }
-
- for _, arg := range flag.Args() {
- path, name := splitPathIdent(arg)
- logf("\tprocessing %q: path = %q, name = %s\n", arg, path, name)
-
- // generate possible package path prefixes
- // (at the moment we do this for each argument - should probably cache the generated prefixes)
- prefixes := make(chan string)
- go genPrefixes(prefixes, !filepath.IsAbs(path) && !build.IsLocalImport(path))
-
- // import package
- pkg, err := tryPrefixes(prefixes, path, imp)
- if err != nil {
- logf("\t=> ignoring %q: %s\n", path, err)
- continue
- }
-
- // filter objects if needed
- var filter func(types.Object) bool
- if name != "" {
- filter = func(obj types.Object) bool {
- // TODO(gri) perhaps use regular expression matching here?
- return obj.Name() == name
- }
- }
-
- // print contents
- print(os.Stdout, pkg, filter)
- }
-}
-
-func logf(format string, args ...interface{}) {
- if *verbose {
- fmt.Fprintf(os.Stderr, format, args...)
- }
-}
-
-// splitPathIdent splits a path.name argument into its components.
-// All but the last path element may contain dots.
-func splitPathIdent(arg string) (path, name string) {
- if i := strings.LastIndex(arg, "."); i >= 0 {
- if j := strings.LastIndex(arg, "/"); j < i {
- // '.' is not part of path
- path = arg[:i]
- name = arg[i+1:]
- return
- }
- }
- path = arg
- return
-}
-
-// tryPrefixes tries to import the package given by (the possibly partial) path using the given importer imp
-// by prepending all possible prefixes to path. It returns with the first package that it could import, or
-// with an error.
-func tryPrefixes(prefixes chan string, path string, imp types.Importer) (pkg *types.Package, err error) {
- for prefix := range prefixes {
- actual := path
- if prefix == "" {
- // don't use filepath.Join as it will sanitize the path and remove
- // a leading dot and then the path is not recognized as a relative
- // package path by the importers anymore
- logf("\ttrying no prefix\n")
- } else {
- actual = filepath.Join(prefix, path)
- logf("\ttrying prefix %q\n", prefix)
- }
- pkg, err = imp.Import(actual)
- if err == nil {
- break
- }
- logf("\t=> importing %q failed: %s\n", actual, err)
- }
- return
-}
-
-// tryImporters is an importer that tries all registered importers
-// successively until one of them succeeds or all of them failed.
-type tryImporters struct{}
-
-func (t *tryImporters) Import(path string) (pkg *types.Package, err error) {
- for i, imp := range importers {
- logf("\t\ttrying %s import\n", sources[i])
- pkg, err = imp.Import(path)
- if err == nil {
- break
- }
- logf("\t\t=> %s import failed: %s\n", sources[i], err)
- }
- return
-}
-
-type protector struct {
- imp types.Importer
-}
-
-func (p *protector) Import(path string) (pkg *types.Package, err error) {
- defer func() {
- if recover() != nil {
- pkg = nil
- err = errImportFailed
- }
- }()
- return p.imp.Import(path)
-}
-
-// protect protects an importer imp from panics and returns the protected importer.
-func protect(imp types.Importer) types.Importer {
- return &protector{imp}
-}
-
-// register registers an importer imp for a given source src.
-func register(src string, imp types.Importer) {
- if lookup(src) != nil {
- panic(src + " importer already registered")
- }
- sources = append(sources, src)
- importers = append(importers, protect(imp))
-}
-
-// lookup returns the importer imp for a given source src.
-func lookup(src string) types.Importer {
- for i, s := range sources {
- if s == src {
- return importers[i]
- }
- }
- return nil
-}
-
-func genPrefixes(out chan string, all bool) {
- out <- ""
- if all {
- platform := build.Default.GOOS + "_" + build.Default.GOARCH
- dirnames := append([]string{build.Default.GOROOT}, filepath.SplitList(build.Default.GOPATH)...)
- for _, dirname := range dirnames {
- walkDir(filepath.Join(dirname, "pkg", platform), "", out)
- }
- }
- close(out)
-}
-
-func walkDir(dirname, prefix string, out chan string) {
- fiList, err := ioutil.ReadDir(dirname)
- if err != nil {
- return
- }
- for _, fi := range fiList {
- if fi.IsDir() && !strings.HasPrefix(fi.Name(), ".") {
- prefix := filepath.Join(prefix, fi.Name())
- out <- prefix
- walkDir(filepath.Join(dirname, fi.Name()), prefix, out)
- }
- }
-}