diff --git a/cli.go b/cli.go index 9667cc1..a61e4e3 100644 --- a/cli.go +++ b/cli.go @@ -25,6 +25,7 @@ type List struct { NoColor bool `long:"no-color" description:"disable colored output"` CoverageThreshold float64 `short:"c" long:"coverage" description:"coverage threshold is the minimum percentage of the file that must contain license text" default:"75"` CheckTestFiles bool `short:"t" long:"check-test-files" description:"check imported dependencies for test files"` + ExperimentalModCheck bool `long:"experimental-mod-check" description:"inspect packages in go mod cache instead of vendor folder"` } type Check struct { @@ -32,6 +33,7 @@ type Check struct { NoColor bool `long:"no-color" description:"disable colored output"` CoverageThreshold float64 `short:"c" long:"coverage" description:"coverage threshold is the minimum percentage of the file that must contain license text" default:"75"` CheckTestFiles bool `short:"t" long:"check-test-files" description:"check imported dependencies for test files"` + ExperimentalModCheck bool `long:"experimental-mod-check" description:"inspect packages in go mod cache instead of vendor folder"` } type Graph struct { @@ -128,11 +130,19 @@ func (l *List) Execute(args []string) error { if err != nil { return err } - - pkgs, err := WalkImports(root, l.CheckTestFiles) - if err != nil { - return err + var pkgs map[string]bool + if l.ExperimentalModCheck { + pkgs, err = WalkImportsFromModCache(root, l.CheckTestFiles) + if err != nil { + return err + } + } else { + pkgs, err = WalkImports(root, l.CheckTestFiles) + if err != nil { + return err + } } + lics := GetLicenses(root, pkgs, l.CoverageThreshold) for k, v := range lics { @@ -243,7 +253,7 @@ PackageList: for wc := range exceptionsWildcard { if strings.HasPrefix(pkg, wc) { // we have a match - contextLogger.Warn("Found exceptioned package") + contextLogger.Warn("Found exception package") continue PackageList } } @@ -251,7 +261,7 @@ PackageList: // match single-package exceptions if _, exists := exceptions[pkg]; exists { - contextLogger.Warn("Found exceptioned package") + contextLogger.Warn("Found exception package") continue PackageList } diff --git a/go.sum b/go.sum index 20582b2..cba735c 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,4 @@ +github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -8,6 +9,7 @@ github.com/google/licensecheck v0.3.1 h1:QoxgoDkaeC4nFrtGN1jV7IPmDCHFNIVh54e5hSt github.com/google/licensecheck v0.3.1/go.mod h1:ORkR35t/JjW+emNKtfJDII0zlciG9JgbT7SmsohlHmY= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= diff --git a/walker.go b/walker.go index 14ca706..094d8cb 100644 --- a/walker.go +++ b/walker.go @@ -6,6 +6,7 @@ import ( "go/token" "io/ioutil" "os" + "os/exec" "path/filepath" "strings" "sync" @@ -245,6 +246,69 @@ func (g *dependencies) WalkNode(n *node) { } +func (g *dependencies) WalkNodeFromModCache(n *node) { + var walkFn = func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + log.Debugf("walking %q", path) + + // check if we need to skip this + if ok, err := shouldSkip(path, info, g.checkTest); ok { + return err + } + + fs := token.NewFileSet() + f, err := parser.ParseFile(fs, path, nil, parser.ImportsOnly) + if err != nil { + return err + } + + for _, s := range f.Imports { + vendorpkg := strings.Replace(s.Path.Value, "\"", "", -1) + log.Debugf("found import %q", vendorpkg) + + args := []string{"list", "-mod=mod", "-f", `'{{.Dir}}'`, "-m", vendorpkg} + cmd := exec.Command("go", args...) + log.Debugf("checking import with go command: %q", cmd) + cmd.Env = append(os.Environ(), + "PATH=/usr/local/Cellar/go/1.16.3/libexec/bin", + ) + out, err := cmd.Output() + if err != nil { + log.Debugf("error returned: %q", err) + //return err + } + pkgdir := strings.TrimSuffix(string(out), "\n") + pkgdir = strings.Trim(pkgdir, "'") + log.Debugf("import check result: %q", pkgdir) + + if _, err := os.Stat(pkgdir); !os.IsNotExist(err) { + + // Add imported pkg to the graph + var vendornode = node{pkg: vendorpkg, dir: pkgdir, vendor: n.vendor} + log.Debugf("[%s] adding node", vendornode.pkg) + if err := g.addNode(&vendornode); err != nil { + log.Debug(err.Error()) + continue + } + log.Debugf("[%s] adding node as edge of %s", vendornode.pkg, n.pkg) + g.addEdge(n, &vendornode) + log.Debugf("[%s] walking node", vendornode.pkg) + g.WalkNode(&vendornode) + } + + } + return nil + } + + if err := filepath.Walk(n.dir, walkFn); err != nil { + return + } + +} + func WalkImports(root string, checkTest bool) (map[string]bool, error) { graph := newGraph(checkTest) @@ -259,6 +323,20 @@ func WalkImports(root string, checkTest bool) (map[string]bool, error) { return graph.nodesList, nil } +func WalkImportsFromModCache(root string, checkTest bool) (map[string]bool, error) { + + graph := newGraph(checkTest) + rootNode := node{pkg: "root", dir: root, vendor: root} + if err := graph.addNode(&rootNode); err != nil { + log.Debug(err.Error()) + } + + log.Debugf("[%s] walking root node", rootNode.pkg) + graph.WalkNodeFromModCache(&rootNode) + + return graph.nodesList, nil +} + func GraphImports(root string, checkTest bool) (string, error) { graph := newGraph(checkTest) @@ -282,9 +360,9 @@ func GetLicenses(root string, list map[string]bool, threshold float64) map[strin var lics = make(map[string]string) - if !strings.HasSuffix(root, "vendor") { - root = filepath.Join(root, "vendor") - } + //if !strings.HasSuffix(root, "vendor") { + // root = filepath.Join(root, "vendor") + //} log.Debug("Start walking paths for LICENSE discovery") for k := range list {