2014-03-25 16:26:38 -06:00
|
|
|
// 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"
|
|
|
|
"os"
|
2014-03-26 10:54:20 -06:00
|
|
|
"path/filepath"
|
2014-03-25 16:26:38 -06:00
|
|
|
"strings"
|
|
|
|
|
|
|
|
"code.google.com/p/go.tools/go/types"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
source = flag.String("s", "", "only consider packages from this source")
|
|
|
|
verbose = flag.Bool("v", false, "verbose mode")
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2014-03-26 10:54:20 -06:00
|
|
|
sources []string // sources of export data corresponding to importers
|
|
|
|
importers []types.Importer // importers for corresponding sources
|
2014-03-25 16:26:38 -06:00
|
|
|
importFailed = errors.New("import failed")
|
|
|
|
packages = make(map[string]*types.Package)
|
|
|
|
)
|
|
|
|
|
|
|
|
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")
|
|
|
|
}
|
|
|
|
|
|
|
|
imp := tryImport
|
|
|
|
if *source != "" {
|
2014-03-26 10:54:20 -06:00
|
|
|
imp = lookup(*source)
|
2014-03-25 16:26:38 -06:00
|
|
|
if imp == nil {
|
2014-03-26 10:54:20 -06:00
|
|
|
report("source (-s argument) must be one of: " + strings.Join(sources, ", "))
|
2014-03-25 16:26:38 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, arg := range flag.Args() {
|
2014-03-26 10:54:20 -06:00
|
|
|
path, name := splitPathIdent(arg)
|
2014-03-25 16:26:38 -06:00
|
|
|
if *verbose {
|
2014-03-26 10:54:20 -06:00
|
|
|
fmt.Fprintf(os.Stderr, "(processing %q: path = %q, name = %s)\n", arg, path, name)
|
2014-03-25 16:26:38 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// import package
|
|
|
|
pkg, err := imp(packages, path)
|
|
|
|
if err != nil {
|
|
|
|
fmt.Fprintf(os.Stderr, "ignoring %q: %s\n", path, err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
// filter objects if needed
|
2014-03-26 10:54:20 -06:00
|
|
|
filter := types.Object.Exported
|
2014-03-25 16:26:38 -06:00
|
|
|
if name != "" {
|
|
|
|
f := filter
|
|
|
|
filter = func(obj types.Object) bool {
|
|
|
|
// TODO(gri) perhaps use regular expression matching here?
|
|
|
|
return f(obj) && obj.Name() == name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// print contents
|
|
|
|
print(os.Stdout, pkg, filter)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// protect protects an importer imp from panics and returns the protected importer.
|
|
|
|
func protect(imp types.Importer) types.Importer {
|
|
|
|
return func(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
|
|
|
|
defer func() {
|
|
|
|
if recover() != nil {
|
|
|
|
pkg = nil
|
|
|
|
err = importFailed
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
return imp(packages, path)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func tryImport(packages map[string]*types.Package, path string) (pkg *types.Package, err error) {
|
2014-03-26 10:54:20 -06:00
|
|
|
for i, imp := range importers {
|
2014-03-25 16:26:38 -06:00
|
|
|
if *verbose {
|
2014-03-26 10:54:20 -06:00
|
|
|
fmt.Fprintf(os.Stderr, "(trying source: %s)\n", sources[i])
|
2014-03-25 16:26:38 -06:00
|
|
|
}
|
|
|
|
pkg, err = imp(packages, path)
|
|
|
|
if err == nil {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2014-03-26 10:54:20 -06:00
|
|
|
// splitPathIdent splits a path.name argument into its components.
|
|
|
|
// All but the last path element may contain dots.
|
|
|
|
// TODO(gri) document this also in doc.go.
|
|
|
|
func splitPathIdent(arg string) (path, name string) {
|
|
|
|
const sep = string(filepath.Separator)
|
|
|
|
if i := strings.LastIndex(arg, "."); i >= 0 {
|
|
|
|
if j := strings.LastIndex(arg, sep); j < i {
|
|
|
|
// '.' is not part of path
|
|
|
|
path = arg[:i]
|
|
|
|
name = arg[i+1:]
|
|
|
|
return
|
|
|
|
}
|
2014-03-25 16:26:38 -06:00
|
|
|
}
|
2014-03-26 10:54:20 -06:00
|
|
|
path = arg
|
|
|
|
return
|
2014-03-25 16:26:38 -06:00
|
|
|
}
|
|
|
|
|
2014-03-26 10:54:20 -06:00
|
|
|
func register(src string, imp types.Importer) {
|
|
|
|
if lookup(src) != nil {
|
|
|
|
panic(src + " importer already registered")
|
2014-03-25 16:26:38 -06:00
|
|
|
}
|
2014-03-26 10:54:20 -06:00
|
|
|
sources = append(sources, src)
|
|
|
|
importers = append(importers, imp)
|
2014-03-25 16:26:38 -06:00
|
|
|
}
|
|
|
|
|
2014-03-26 10:54:20 -06:00
|
|
|
func lookup(src string) types.Importer {
|
|
|
|
for i, s := range sources {
|
|
|
|
if s == src {
|
|
|
|
return importers[i]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
2014-03-25 16:26:38 -06:00
|
|
|
}
|