Do a single build for all packages.

This is much faster because the loader can reuse packages.
This commit is contained in:
Andrew S. Brown 2018-01-07 15:02:33 -08:00
parent 085e0f65af
commit 22dc89384d
3 changed files with 45 additions and 17 deletions

View file

@ -27,6 +27,8 @@ import (
"reflect" "reflect"
"strings" "strings"
"path/filepath"
"golang.org/x/tools/go/loader" "golang.org/x/tools/go/loader"
) )
@ -93,20 +95,25 @@ func (gas *Analyzer) LoadRules(ruleDefinitions ...RuleBuilder) {
} }
// Process kicks off the analysis process for a given package // Process kicks off the analysis process for a given package
func (gas *Analyzer) Process(packagePath string) error { func (gas *Analyzer) Process(packagePaths ...string) error {
packageConfig := loader.Config{Build: &build.Default, ParserMode: parser.ParseComments}
for _, packagePath := range packagePaths {
abspath, _ := filepath.Abs(packagePath)
gas.logger.Println("Searching directory:", abspath)
basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment) basePackage, err := build.Default.ImportDir(packagePath, build.ImportComment)
if err != nil { if err != nil {
return err return err
} }
packageConfig := loader.Config{Build: &build.Default, ParserMode: parser.ParseComments}
var packageFiles []string var packageFiles []string
for _, filename := range basePackage.GoFiles { for _, filename := range basePackage.GoFiles {
packageFiles = append(packageFiles, path.Join(packagePath, filename)) packageFiles = append(packageFiles, path.Join(packagePath, filename))
} }
packageConfig.CreateFromFilenames(basePackage.Name, packageFiles...) packageConfig.CreateFromFilenames(basePackage.Name, packageFiles...)
}
builtPackage, err := packageConfig.Load() builtPackage, err := packageConfig.Load()
if err != nil { if err != nil {
return err return err

View file

@ -73,6 +73,28 @@ var _ = Describe("Analyzer", func() {
Expect(metrics.NumFiles).To(Equal(2)) Expect(metrics.NumFiles).To(Equal(2))
}) })
It("should be able to analyze mulitple Go packages", func() {
analyzer.LoadRules(rules.Generate().Builders()...)
pkg1 := testutils.NewTestPackage()
pkg2 := testutils.NewTestPackage()
defer pkg1.Close()
defer pkg2.Close()
pkg1.AddFile("foo.go", `
package main
func main(){
}`)
pkg2.AddFile("bar.go", `
package main
func bar(){
}`)
pkg1.Build()
pkg2.Build()
err := analyzer.Process(pkg1.Path, pkg2.Path)
Expect(err).ShouldNot(HaveOccurred())
_, metrics := analyzer.Report()
Expect(metrics.NumFiles).To(Equal(2))
})
It("should find errors when nosec is not in use", func() { It("should find errors when nosec is not in use", func() {
// Rule for MD5 weak crypto usage // Rule for MD5 weak crypto usage

View file

@ -19,7 +19,6 @@ import (
"fmt" "fmt"
"log" "log"
"os" "os"
"path/filepath"
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
@ -202,6 +201,7 @@ func main() {
vendor := regexp.MustCompile(`[\\/]vendor([\\/]|$)`) vendor := regexp.MustCompile(`[\\/]vendor([\\/]|$)`)
var packages []string
// Iterate over packages on the import paths // Iterate over packages on the import paths
for _, pkg := range gotool.ImportPaths(flag.Args()) { for _, pkg := range gotool.ImportPaths(flag.Args()) {
@ -209,12 +209,11 @@ func main() {
if vendor.MatchString(pkg) { if vendor.MatchString(pkg) {
continue continue
} }
packages = append(packages, pkg)
abspath, _ := filepath.Abs(pkg)
logger.Println("Searching directory:", abspath)
if err := analyzer.Process(pkg); err != nil {
logger.Fatal(err)
} }
if err := analyzer.Process(packages...); err != nil {
logger.Fatal(err)
} }
// Collect the results // Collect the results