diff --git a/cmd/showimp/README.md b/cmd/showimp/README.md new file mode 100644 index 0000000..cd45897 --- /dev/null +++ b/cmd/showimp/README.md @@ -0,0 +1,21 @@ +# showimp +## show imports + +This will run over a source tree and print any imports that are not in +the standard library or inside the project. + +``` +kyle@nocturne:~/src/github.com/kisom/cryptutils$ showimp +External imports: + code.google.com/p/go.crypto/bcrypt + code.google.com/p/go.crypto/nacl/box + code.google.com/p/go.crypto/nacl/secretbox + code.google.com/p/go.crypto/scrypt + code.google.com/p/rsc/qr + github.com/agl/ed25519 + github.com/conformal/yubikey + github.com/gokyle/readpass + github.com/gokyle/twofactor + github.com/gorilla/mux +``` + diff --git a/cmd/showimp/main.go b/cmd/showimp/main.go new file mode 100644 index 0000000..d47c770 --- /dev/null +++ b/cmd/showimp/main.go @@ -0,0 +1,110 @@ +// showimp is a utility for displaying the imports in a package. +package main + +import ( + "flag" + "fmt" + "go/parser" + "go/token" + "os" + "path/filepath" + "regexp" + "sort" + "strings" + + "github.com/kisom/goutils/die" + "github.com/kisom/goutils/logging" +) + +var ( + gopath string + project string +) + +var ( + stdLibRegexp = regexp.MustCompile(`^\w+(/\w+)*$`) + sourceRegexp = regexp.MustCompile(`^[^.].*\.go$`) + log = logging.Init() +) + +func init() { + gopath = os.Getenv("GOPATH") + if gopath == "" { + fmt.Fprintf(os.Stderr, "GOPATH isn't set, can't proceed.") + os.Exit(1) + } + gopath += "/src/" + + wd, err := os.Getwd() + if err != nil { + fmt.Fprintf(os.Stderr, "Unable to establish working directory: %v", err) + os.Exit(1) + } + + if !strings.HasPrefix(wd, gopath) { + fmt.Fprintf(os.Stderr, "Can't determine my location in the GOPATH.\n") + fmt.Fprintf(os.Stderr, "Working directory is %s\n", wd) + fmt.Fprintf(os.Stderr, "Go source path is %s\n", gopath) + os.Exit(1) + } + + project = wd[len(gopath):] +} + +var ( + imports = map[string]bool{} + fset = &token.FileSet{} +) + +func walkFile(path string, info os.FileInfo, err error) error { + if !sourceRegexp.MatchString(path) { + return nil + } + + log.Debug(path) + + f, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly) + if err != nil { + return err + } + + for _, importSpec := range f.Imports { + importPath := strings.Trim(importSpec.Path.Value, `"`) + if stdLibRegexp.MatchString(importPath) { + log.Debug("standard lib:", importPath) + continue + } else if strings.HasPrefix(importPath, project) { + log.Debug("internal import:", importPath) + continue + } else if strings.HasPrefix(importPath, "golang.org/") { + log.Debug("extended lib:", importPath) + continue + } + log.Debug("import:", importPath) + imports[importPath] = true + } + + return nil +} + +func main() { + verbose := flag.Bool("v", false, "log debugging information") + flag.Parse() + + if *verbose { + log.SetLevel(logging.LevelDebug) + } + err := filepath.Walk(".", walkFile) + die.If(err) + + fmt.Println("External imports:") + importList := make([]string, 0, len(imports)) + for imp := range imports { + importList = append(importList, imp) + } + sort.Strings(importList) + + for _, imp := range importList { + fmt.Println("\t", imp) + } +} diff --git a/lib/lib.go b/lib/lib.go index 42178fc..9d207ed 100644 --- a/lib/lib.go +++ b/lib/lib.go @@ -45,3 +45,12 @@ func Err(exit int, err error, format string, a ...interface{}) { fmt.Fprintf(os.Stderr, format, a...) os.Exit(exit) } + +// CheckFatal calls Err if err isn't nil. +func CheckFatal(err error, format string, a ...interface{}) { + if err == nil { + return + } + + Err(ExitFailure, err, format, a...) +}