Get dependencies for go modules powered projects.

This commit is contained in:
Stanislav Nikitin 2020-02-07 21:22:40 +05:00
parent 633aa28ef1
commit f423fb9ac7
No known key found for this signature in database
GPG Key ID: 106900B32F8192EE
3 changed files with 79 additions and 1 deletions

View File

@ -2,9 +2,15 @@ package golang
import ( import (
// stdlib // stdlib
"bufio"
"log" "log"
"os" "os"
"path/filepath" "path/filepath"
"strings"
// local
"go.dev.pztrn.name/glp/structs"
) )
var goModulesFilesToCheck = []string{"go.mod", "go.sum"} var goModulesFilesToCheck = []string{"go.mod", "go.sum"}
@ -25,3 +31,73 @@ func (gp *golangParser) detectModulesUsage(pkgPath string) bool {
return goModulesFileFound return goModulesFileFound
} }
// Gets dependencies from go.mod/go.sum files.
func (gp *golangParser) getDependenciesFromModules(pkgPath string) []*structs.Dependency {
deps := make([]*structs.Dependency, 0)
// Try to figure out parent package name for all dependencies.
parent := gp.getParentForDep(pkgPath)
// Get GOPATH for future dependency path composing.
gopath, found := os.LookupEnv("GOPATH")
if !found {
log.Fatalln("Go modules project found but no GOPATH environment variable defined. Cannot continue.")
}
// To get really all dependencies we should use go.sum file.
filePath := filepath.Join(pkgPath, "go.sum")
f, err := os.Open(filePath)
if err != nil {
log.Println("Failed to open go.sum file for reading:", err.Error())
return nil
}
// We do not need multiple lines of dependencies in reports which
// describes same name and version.
createdDeps := make(map[string]bool)
// Read file data line by line.
gosum := bufio.NewScanner(f)
gosum.Split(bufio.ScanLines)
for gosum.Scan() {
depLine := strings.Split(gosum.Text(), " ")
// Version should be cleared out from possible "/go.mod"
// substring.
version := strings.Split(depLine[1], "/")[0]
// Check if we've already processed that dependency.
_, processed := createdDeps[depLine[0]+"@"+version]
if processed {
continue
}
// Go modules present on disk either in vendor or in GOPATH/pkg
// directory. But vendor here should not be trusted because it
// might contain old versions.
dependencyPath := filepath.Join(gopath, "pkg", "mod", depLine[0]+"@"+version)
// Check if this module exists on disk. Absence means that it
// isn't actually used and just pollute go.sum.
if _, err := os.Stat(dependencyPath); err != nil {
continue
}
dependency := &structs.Dependency{
LocalPath: dependencyPath,
Name: depLine[0],
Parent: parent,
Version: version,
}
deps = append(deps, dependency)
// Mark dependency as processed.
createdDeps[depLine[0]+"@"+version] = true
}
return deps
}

View File

@ -42,6 +42,8 @@ func (gp *golangParser) GetDependencies(flavor string, pkgPath string) []*struct
switch flavor { switch flavor {
case packageManagerDep: case packageManagerDep:
deps = gp.getDependenciesFromDep(pkgPath) deps = gp.getDependenciesFromDep(pkgPath)
case packageManagerGoMod:
deps = gp.getDependenciesFromModules(pkgPath)
} }
// Return early if no dependencies was found. // Return early if no dependencies was found.

View File

@ -85,7 +85,7 @@ func (p *Project) process() {
for _, dep := range p.deps { for _, dep := range p.deps {
depDir, err := filer.FromDirectory(dep.LocalPath) depDir, err := filer.FromDirectory(dep.LocalPath)
if err != nil { if err != nil {
log.Println("Failed to prepare directory path for depencendy license scan:", err.Error()) log.Println("Failed to prepare directory path for dependency license scan:", err.Error())
continue continue
} }