diff --git a/parsers/golang/modules.go b/parsers/golang/modules.go index 2a33701..c1125dc 100644 --- a/parsers/golang/modules.go +++ b/parsers/golang/modules.go @@ -101,6 +101,16 @@ func (gp *golangParser) getDependenciesFromModules(pkgPath string) []*structs.De dependency.Name = strings.Join(depName[:len(depName)-1], "/") } + // Version might contain "+incompatible", which might break + // license URL generation. + if strings.Contains(dependency.Version, "incompatible") { + dependency.Version = strings.Split(dependency.Version, "+incompat")[0] + } + + // As we're using specific version - we should assume it as + // branch name. + dependency.VCS.Branch = dependency.Version + deps = append(deps, dependency) // Mark dependency as processed. diff --git a/projecter/project.go b/projecter/project.go index 0beea3e..8b15322 100644 --- a/projecter/project.go +++ b/projecter/project.go @@ -83,6 +83,11 @@ func (p *Project) process() { // Get licensing information for every dependency. for _, dep := range p.deps { + // Prepare dependency's things. For now - only check if + // file/directory templates defined and, if not, generate + // them. + dep.VCS.FormatSourcePaths() + depDir, err := filer.FromDirectory(dep.LocalPath) if err != nil { log.Println("Failed to prepare directory path for dependency license scan:", err.Error()) @@ -104,6 +109,7 @@ func (p *Project) process() { // Get highest ranked license. var ( + licenseFile string licenseName string licenseRank float32 ) @@ -112,6 +118,13 @@ func (p *Project) process() { if licenseRank < result.Confidence { licenseName = name licenseRank = result.Confidence + + for fileName, confidence := range result.Files { + if confidence == licenseRank { + licenseFile = fileName + break + } + } } } @@ -123,5 +136,9 @@ func (p *Project) process() { log.Printf("Got license for '%s': %s", dep.Name, licenseName) dep.License.Name = licenseName + + // Generate license path. + urlFormatter := strings.NewReplacer("{dir}", "", "{/dir}", "", "{file}", licenseFile, "{/file}", licenseFile, "#L{line}", "") + dep.License.URL = urlFormatter.Replace(dep.VCS.SourceURLFileTemplate) } } diff --git a/structs/vcsdata.go b/structs/vcsdata.go index 761e3c2..94889ff 100644 --- a/structs/vcsdata.go +++ b/structs/vcsdata.go @@ -1,5 +1,10 @@ package structs +import ( + // stdlib + "strings" +) + // VCSData describes structure of go-import and go-source data. type VCSData struct { // Branch is a VCS branch used. @@ -17,3 +22,25 @@ type VCSData struct { // VCSPath is a VCS repository path. VCSPath string } + +// FormatSourcePaths tries to create templates which will be used for +// paths formatting. E.g. when generating path to license file. +// This is required because for some repositories github.com (and +// probably gitlab.com too) might not return go-source element in +// page's tag. +func (vd *VCSData) FormatSourcePaths() { + // Do nothing if templates was filled (e.g. when parsing HTML page + // for repository with "?go-get=1" parameter). + if vd.SourceURLDirTemplate != "" && vd.SourceURLFileTemplate != "" { + return + } + + // If no URL templates was provided by github and we know that + // dependency is using it as VCS storage - generate proper + // template URLs. + if vd.VCS == "git" && vd.VCSPath != "" && strings.Contains(vd.VCSPath, "github.com") { + repoPathSplitted := strings.Split(vd.VCSPath, ".") + vd.SourceURLDirTemplate = strings.Join(repoPathSplitted[:len(repoPathSplitted)-1], ".") + "/blob/" + vd.Branch + "{/dir}" + vd.SourceURLFileTemplate = strings.Join(repoPathSplitted[:len(repoPathSplitted)-1], ".") + "/blob/" + vd.Branch + "{/dir}/{file}#L{line}" + } +}