Skip to content

Commit

Permalink
Support package resolution and filepaths (#187)
Browse files Browse the repository at this point in the history
* Support package resolution and filepaths

This change introduces the logic to resolve packages using gotool
and build packages from filepaths. It assumes that the packages
being scanned are located within the GOPATH.

If the GOPATH environment variable is not set the GOPATH is derived
as $HOME/go.

Relates to #184

* Fix build error

* Address unhandled error

* Fix formatting error

* Handle multiple paths on GOPATH
  • Loading branch information
gcmurphy committed Apr 16, 2018
1 parent b643ac2 commit 830cb81
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 2 deletions.
4 changes: 4 additions & 0 deletions analyzer.go
Expand Up @@ -108,6 +108,10 @@ func (gas *Analyzer) Process(packagePaths ...string) error {
if err != nil {
return err
}
if _, err := os.Stat(abspath); os.IsNotExist(err) {
gas.logger.Printf("Skipping: %s. Path doesn't exist.", abspath)
continue
}
gas.logger.Println("Searching directory:", abspath)

basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment)
Expand Down
84 changes: 82 additions & 2 deletions cmd/gas/main.go
Expand Up @@ -19,7 +19,10 @@ import (
"fmt"
"log"
"os"
"os/user"
"path/filepath"
"regexp"
"runtime"
"sort"
"strings"

Expand Down Expand Up @@ -171,6 +174,82 @@ func saveOutput(filename, format string, issues []*gas.Issue, metrics *gas.Metri
return nil
}

func getenv(key, userDefault string) string {
if val := os.Getenv(key); val != "" {
return val
}
return userDefault
}

func gopath() []string {
defaultGoPath := runtime.GOROOT()
if u, err := user.Current(); err == nil {
defaultGoPath = filepath.Join(u.HomeDir, "go")
}
path := getenv("GOPATH", defaultGoPath)
paths := strings.Split(path, string(os.PathListSeparator))
for idx, path := range paths {
if abs, err := filepath.Abs(path); err == nil {
paths[idx] = abs
}
}
return paths
}

func cleanPath(path string, gopaths []string) (string, error) {

cleanFailed := fmt.Errorf("%s is not within the $GOPATH and cannot be processed", path)
nonRecursivePath := strings.TrimSuffix(path, "/...")
// do not attempt to clean directs that are resolvable on gopath
if _, err := os.Stat(nonRecursivePath); err != nil && os.IsNotExist(err) {
log.Printf("directory %s doesn't exist, checking if is a package on $GOPATH", path)
for _, basedir := range gopaths {
dir := filepath.Join(basedir, "src", nonRecursivePath)
if st, err := os.Stat(dir); err == nil && st.IsDir() {
log.Printf("located %s in %s", path, dir)
return path, nil
}
}
return "", cleanFailed
}

// ensure we resolve package directory correctly based on $GOPATH
abspath, err := filepath.Abs(path)
if err != nil {
abspath = path
}
for _, base := range gopaths {
projectRoot := filepath.FromSlash(fmt.Sprintf("%s/src/", base))
if strings.HasPrefix(abspath, projectRoot) {
return strings.TrimPrefix(abspath, projectRoot), nil
}
}
return "", cleanFailed
}

func cleanPaths(paths []string) []string {
gopaths := gopath()
var clean []string
for _, path := range paths {
cleaned, err := cleanPath(path, gopaths)
if err != nil {
log.Fatal(err)
}
clean = append(clean, cleaned)
}
return clean
}

func resolvePackage(pkg string, searchPaths []string) string {
for _, basedir := range searchPaths {
dir := filepath.Join(basedir, "src", pkg)
if st, err := os.Stat(dir); err == nil && st.IsDir() {
return dir
}
}
return pkg
}

func main() {

// Setup usage description
Expand Down Expand Up @@ -218,13 +297,14 @@ func main() {

var packages []string
// Iterate over packages on the import paths
for _, pkg := range gotool.ImportPaths(flag.Args()) {
gopaths := gopath()
for _, pkg := range gotool.ImportPaths(cleanPaths(flag.Args())) {

// Skip vendor directory
if vendor.MatchString(pkg) {
continue
}
packages = append(packages, pkg)
packages = append(packages, resolvePackage(pkg, gopaths))
}

if err := analyzer.Process(packages...); err != nil {
Expand Down

0 comments on commit 830cb81

Please sign in to comment.