github.com/joey-fossa/fossa-cli@v0.7.34-0.20190708193710-569f1e8679f0/analyzers/golang/golang.go (about) 1 // Package golang implements the analyzer for Go. 2 // 3 // A `BuildTarget` in Go is defined as an import path (see `go help importpath` 4 // for details). 5 // 6 // This package is implemented by externally calling both the `go` tool and any 7 // external build tools. 8 // 9 // FAQ 10 // 11 // 1. Why not use `go/build`, or a library like `KyleBanks/depth`? 12 // 13 // The `go` tool's interface is incredibly stable over different releases, but 14 // the internals are not. Using these libraries causes crashes when analyzing 15 // code that is compiled using a different version of Go. (This was how the 16 // analyzer was originally implemented.) 17 package golang 18 19 import ( 20 "os" 21 22 "github.com/apex/log" 23 "github.com/mitchellh/mapstructure" 24 25 "github.com/fossas/fossa-cli/analyzers/golang/resolver" 26 "github.com/fossas/fossa-cli/buildtools/gocmd" 27 "github.com/fossas/fossa-cli/exec" 28 "github.com/fossas/fossa-cli/module" 29 ) 30 31 // An Analyzer contains structs used in the analysis of Go packages. It 32 // implements analyzer.Analyzer. 33 type Analyzer struct { 34 Go gocmd.Go 35 GoVersion string 36 37 Module module.Module 38 Options Options 39 40 BuildTags []string 41 42 // These caches prevent redundant filesystem lookups and execs, and help a lot 43 // when dealing with nested vendoring. 44 resolverCache map[string]resolver.Resolver 45 projectCache map[string]Project 46 } 47 48 // Options set analyzer options for Go modules. 49 type Options struct { 50 Tags []string `mapstructure:"tags"` // specify individual build configurations 51 AllTags bool `mapstructure:"all-tags"` // Turn on all fossa default build tags 52 Strategy string `mapstructure:"strategy"` // See the Go analyzer documentation. 53 LockfilePath string `mapstructure:"lockfile"` // For non-standard lockfile locations with strategies `manifest:*`. 54 ManifestPath string `mapstructure:"manifest"` // For non-standard manifest locations with strategies `manifest:*`. 55 AllowUnresolved bool `mapstructure:"allow-unresolved"` // Allow unresolved revisions. 56 AllowUnresolvedPrefix string `mapstructure:"allow-unresolved-prefix"` // If set, allows unresolved revisions for packages whose import path's prefix matches. Multiple space-delimited prefixes can be specified. 57 AllowNestedVendor bool `mapstructure:"allow-nested-vendor"` // Allows vendor folders to be nested and attempts to resolve using parent lockfile lookup. 58 AllowDeepVendor bool `mapstructure:"allow-deep-vendor"` // Allows nested vendored dependencies to be resolved using ancestor lockfiles farther than their direct parent. 59 AllowExternalVendor bool `mapstructure:"allow-external-vendor"` // Allows reading vendor lockfiles of other projects. 60 AllowExternalVendorPrefix string `mapstructure:"allow-external-vendor-prefix"` // If set, allow reading vendor lockfiles of projects whose import path's prefix matches. Multiple space-delimited prefixes can be specified. 61 SkipImportTracing bool `mapstructure:"skip-tracing"` // Skips dependency tracing. 62 SkipProject bool `mapstructure:"skip-project"` // Skips project detection. 63 } 64 65 var osTags = []string{"windows", "linux", "freebsd", "android", "darwin", "dragonfly", "nacl", "netbsd", "openbsd", "plan9", "solaris"} 66 var archTags = []string{"386", "amd64", "amd64p32", "arm", "armbe", "arm64", "arm64be", "ppc64", "ppc64le", "mips", "mipsle", "mips64", "mips64le", "mips64p32", "mips64p32le", "ppc", "s390", "s390x", "sparc", "sparc64"} 67 68 // New constructs an Analyzer. 69 func New(m module.Module) (*Analyzer, error) { 70 log.Debugf("%#v", m) 71 72 // Parse and validate options. 73 var options Options 74 err := mapstructure.Decode(m.Options, &options) 75 if err != nil { 76 return nil, err 77 } 78 log.WithField("options", options).Debug("parsed analyzer options") 79 80 // Construct analyzer. 81 cmd, version, err := exec.Which("version", os.Getenv("FOSSA_GO_CMD"), "go") 82 if err != nil { 83 return nil, err 84 } 85 86 // Compile a list of all user requested build constraints. 87 tags := options.Tags 88 if options.AllTags { 89 tags = append(tags, osTags...) 90 tags = append(tags, archTags...) 91 } 92 // Include the current build setup. 93 tags = append(tags, "") 94 95 return &Analyzer{ 96 Go: gocmd.Go{ 97 Cmd: cmd, 98 }, 99 GoVersion: version, 100 101 Module: m, 102 Options: options, 103 104 BuildTags: tags, 105 106 resolverCache: make(map[string]resolver.Resolver), 107 projectCache: make(map[string]Project), 108 }, nil 109 } 110 111 // Clean runs `go clean $PKG`. 112 func (a *Analyzer) Clean() error { 113 m := a.Module 114 return a.Go.Clean([]string{m.BuildTarget}) 115 } 116 117 // Build runs `go build $PKG`. 118 func (a *Analyzer) Build() error { 119 m := a.Module 120 return a.Go.Build([]string{m.BuildTarget}) 121 } 122 123 // IsBuilt runs `go list $PKG` and checks for errors. 124 func (a *Analyzer) IsBuilt() (bool, error) { 125 m := a.Module 126 log.Debugf("%#v", m) 127 pkg, err := a.Go.ListOne(m.BuildTarget, nil) 128 if err != nil { 129 return false, err 130 } 131 return pkg.Error == nil, nil 132 }