From 5de260e73b1608e62de7656781286279549d9ef8 Mon Sep 17 00:00:00 2001
From: Mrproliu <741550557@qq.com>
Date: Fri, 6 May 2022 17:17:53 +0800
Subject: [PATCH 1/7] Provide summary flag to generate the license summary file
---
README.md | 18 +++++-
commands/deps_resolve.go | 60 +++++++++++++++-----
pkg/deps/config.go | 9 ++-
pkg/deps/golang.go | 21 +++++--
pkg/deps/jar.go | 11 ++--
pkg/deps/jar_test.go | 2 +-
pkg/deps/maven.go | 22 +++++---
pkg/deps/maven_test.go | 2 +-
pkg/deps/npm.go | 17 +++++-
pkg/deps/resolve.go | 4 +-
pkg/deps/summary.go | 114 ++++++++++++++++++++++++++++++++++++++
pkg/license/identifier.go | 22 ++++++++
12 files changed, 261 insertions(+), 41 deletions(-)
create mode 100644 pkg/deps/summary.go
diff --git a/README.md b/README.md
index f2bb97ce..fde8e655 100644
--- a/README.md
+++ b/README.md
@@ -157,11 +157,15 @@ INFO Totally checked 20 files, valid: 10, invalid: 10, ignored: 0, fixed: 10
This command serves as assistance for human beings to audit the dependencies license, it's exit code is always 0.
-You can also use the `--output` or `-o` to save the dependencies' `LICENSE` files to a specified directory so that
-you can put them in distribution package if needed.
+We also support two flag:
+
+|Flag name|Short name|Description|
+|---------|----------|-----------|
+|--output|-o|Save the dependencies' `LICENSE` files to a specified directory so that you can put them in distribution package if needed.|
+|--summary|-s|Based on the template, aggregate all dependency information and generate a `LICENSE` file.|
```bash
-license-eye -c test/testdata/.licenserc_for_test_check.yaml dep resolve -o ./dependencies/licenses
+license-eye -c test/testdata/.licenserc_for_test_check.yaml dep resolve -o ./dependencies/licenses -s LICENSE.tpl
```
@@ -468,6 +472,10 @@ header: # <1>
dependency: # <15>
files: # <16>
- go.mod
+ license: # <17>
+ - name: dependency-name # <18>
+ version: dependency-version # <19>
+ license: Apache-2.0 # <20>
```
1. The `header` section is configurations for source codes license header.
@@ -486,6 +494,10 @@ dependency: # <15>
14. The `comment_style_id` set the license header comment style, it's the `id` at the `styles.yaml`.
15. The `dependency` section is configurations for resolving dependencies' licenses.
16. The `files` are the files that declare the dependencies of a project, typically, `go.mod` in Go project, `pom.xml` in maven project, and `package.json` in NodeJS project. If it's a relative path, it's relative to the `.licenserc.yaml`.
+17. Declare the license which cannot be identified as a dependency.
+18. The `name` of the dependency, The name is different for different projects, `PackagePath` in Go project, `GroupID:ArtifactID` in maven project, `PackageName` in NodeJS project.
+19. The `version` of the dependency, It's locked, prevent version update and change the License.
+20. The [SPDX ID](https://spdx.org/licenses/) of the dependency license.
**NOTE**: When the `SPDX-ID` is Apache-2.0 and the owner is Apache Software foundation, the content would be [a dedicated license](https://www.apache.org/legal/src-headers.html#headers) specified by the ASF, otherwise, the license would be [the standard one](https://www.apache.org/foundation/license-faq.html#Apply-My-Software).
diff --git a/commands/deps_resolve.go b/commands/deps_resolve.go
index d242eeb6..7ad20745 100644
--- a/commands/deps_resolve.go
+++ b/commands/deps_resolve.go
@@ -21,8 +21,8 @@ import (
"fmt"
"os"
"path/filepath"
- "regexp"
"strings"
+ "text/template"
"github.com/spf13/cobra"
@@ -31,29 +31,40 @@ import (
)
var outDir string
+var summaryTplPath string
+var summaryTpl *template.Template
func init() {
DepsResolveCommand.PersistentFlags().StringVarP(&outDir, "output", "o", "",
"the directory to output the resolved dependencies' licenses, if not set the dependencies' licenses won't be saved")
+ DepsResolveCommand.PersistentFlags().StringVarP(&summaryTplPath, "summary", "s", "",
+ "the template file to write the summary the dependencies' licenses, if not set the licenses just print as the table")
}
-var fileNamePattern = regexp.MustCompile(`[^a-zA-Z0-9\\.\-]`)
-
var DepsResolveCommand = &cobra.Command{
Use: "resolve",
Aliases: []string{"r"},
Long: "resolves all dependencies of a module and their transitive dependencies",
PreRunE: func(cmd *cobra.Command, args []string) error {
- if outDir == "" {
- return nil
- }
- absPath, err := filepath.Abs(outDir)
- if err != nil {
- return err
+ if outDir != "" {
+ absPath, err := filepath.Abs(outDir)
+ if err != nil {
+ return err
+ }
+ outDir = absPath
+ if err := os.MkdirAll(outDir, 0o700); err != nil && !os.IsExist(err) {
+ return err
+ }
}
- outDir = absPath
- if err := os.MkdirAll(outDir, 0o700); err != nil && !os.IsExist(err) {
- return err
+ if summaryTplPath != "" {
+ if outDir == "" {
+ return fmt.Errorf("please provide the output directory to write the license summary file")
+ }
+ tpl, err := deps.ParseTemplate(summaryTplPath)
+ if err != nil {
+ return err
+ }
+ summaryTpl = tpl
}
return nil
},
@@ -70,6 +81,10 @@ var DepsResolveCommand = &cobra.Command{
}
}
+ if summaryTpl != nil {
+ writeSummary(&report)
+ }
+
fmt.Println(report.String())
if skipped := len(report.Skipped); skipped > 0 {
@@ -88,8 +103,7 @@ var DepsResolveCommand = &cobra.Command{
}
func writeLicense(result *deps.Result) {
- filename := string(fileNamePattern.ReplaceAll([]byte(result.Dependency), []byte("-")))
- filename = filepath.Join(outDir, "license-"+filename+".txt")
+ filename := filepath.Join(outDir, deps.GenerateDependencyLicenseFilename(result))
file, err := os.Create(filename)
if err != nil {
logger.Log.Errorf("failed to create license file %v: %v", filename, err)
@@ -102,3 +116,21 @@ func writeLicense(result *deps.Result) {
return
}
}
+
+func writeSummary(rep *deps.Report) {
+ file, err := os.Create(filepath.Join(outDir, "LICENSE"))
+ if err != nil {
+ logger.Log.Errorf("failed to create summary license file %s: %v", "LICENSE", err)
+ return
+ }
+ defer file.Close()
+ summary, err := deps.GenerateSummary(summaryTpl, &Config.Header, rep)
+ if err != nil {
+ logger.Log.Errorf("failed to generate summary content: %v", err)
+ return
+ }
+ _, err = file.WriteString(summary)
+ if err != nil {
+ logger.Log.Errorf("failed to write summary file, %v", err)
+ }
+}
diff --git a/pkg/deps/config.go b/pkg/deps/config.go
index 0633b96c..64c0a53b 100644
--- a/pkg/deps/config.go
+++ b/pkg/deps/config.go
@@ -23,7 +23,14 @@ import (
)
type ConfigDeps struct {
- Files []string `yaml:"files"`
+ Files []string `yaml:"files"`
+ License []*ConfigDepLicense `yaml:"licenses"`
+}
+
+type ConfigDepLicense struct {
+ Name string `yaml:"name"`
+ Version string `yaml:"version"`
+ License string `yaml:"license"`
}
func (config *ConfigDeps) Finalize(configFile string) error {
diff --git a/pkg/deps/golang.go b/pkg/deps/golang.go
index 063fbf32..7e3af85d 100644
--- a/pkg/deps/golang.go
+++ b/pkg/deps/golang.go
@@ -45,7 +45,7 @@ func (resolver *GoModResolver) CanResolve(file string) bool {
}
// Resolve resolves licenses of all dependencies declared in the go.mod file.
-func (resolver *GoModResolver) Resolve(goModFile string, report *Report) error {
+func (resolver *GoModResolver) Resolve(goModFile string, licenses []*ConfigDepLicense, report *Report) error {
if err := os.Chdir(filepath.Dir(goModFile)); err != nil {
return err
}
@@ -78,13 +78,19 @@ func (resolver *GoModResolver) Resolve(goModFile string, report *Report) error {
logger.Log.Debugln("Module size:", len(modules))
- return resolver.ResolvePackages(modules, report)
+ return resolver.ResolvePackages(modules, licenses, report)
}
// ResolvePackages resolves the licenses of the given packages.
-func (resolver *GoModResolver) ResolvePackages(modules []*packages.Module, report *Report) error {
+func (resolver *GoModResolver) ResolvePackages(modules []*packages.Module, licenses []*ConfigDepLicense, report *Report) error {
for _, module := range modules {
- err := resolver.ResolvePackageLicense(module, report)
+ var decalreLicense *ConfigDepLicense
+ for _, l := range licenses {
+ if l.Name == module.Path && l.Version == module.Version {
+ decalreLicense = l
+ }
+ }
+ err := resolver.ResolvePackageLicense(module, decalreLicense, report)
if err != nil {
logger.Log.Warnf("Failed to resolve the license of <%s>: %v\n", module.Path, err)
report.Skip(&Result{
@@ -99,7 +105,7 @@ func (resolver *GoModResolver) ResolvePackages(modules []*packages.Module, repor
var possibleLicenseFileName = regexp.MustCompile(`(?i)^LICENSE|LICENCE(\.txt)?|COPYING(\.txt)?$`)
-func (resolver *GoModResolver) ResolvePackageLicense(module *packages.Module, report *Report) error {
+func (resolver *GoModResolver) ResolvePackageLicense(module *packages.Module, declareLicense *ConfigDepLicense, report *Report) error {
dir := module.Dir
for {
@@ -119,7 +125,10 @@ func (resolver *GoModResolver) ResolvePackageLicense(module *packages.Module, re
}
identifier, err := license.Identify(module.Path, string(content))
if err != nil {
- return err
+ if declareLicense == nil {
+ return err
+ }
+ identifier = declareLicense.License
}
report.Resolve(&Result{
Dependency: module.Path,
diff --git a/pkg/deps/jar.go b/pkg/deps/jar.go
index fada99c4..09868bc0 100644
--- a/pkg/deps/jar.go
+++ b/pkg/deps/jar.go
@@ -37,7 +37,7 @@ func (resolver *JarResolver) CanResolve(jarFile string) bool {
return filepath.Ext(jarFile) == ".jar"
}
-func (resolver *JarResolver) Resolve(jarFile string, report *Report) error {
+func (resolver *JarResolver) Resolve(jarFile string, licenses []*ConfigDepLicense, report *Report) error {
state := NotFound
if err := resolver.ResolveJar(&state, jarFile, Unknown, report); err != nil {
dep := filepath.Base(jarFile)
@@ -76,7 +76,7 @@ func (resolver *JarResolver) ResolveJar(state *State, jarFile, version string, r
return err
}
- return resolver.IdentifyLicense(jarFile, dep, buf.String(), version, report)
+ return resolver.IdentifyLicense(jarFile, dep, buf.String(), version, nil, report)
}
}
@@ -122,10 +122,13 @@ func (resolver *JarResolver) ReadFileFromZip(archiveFile *zip.File) (*bytes.Buff
return buf, nil
}
-func (resolver *JarResolver) IdentifyLicense(path, dep, content, version string, report *Report) error {
+func (resolver *JarResolver) IdentifyLicense(path, dep, content, version string, declareLicense *ConfigDepLicense, report *Report) error {
identifier, err := license.Identify(path, content)
if err != nil {
- return err
+ if declareLicense == nil {
+ return err
+ }
+ identifier = declareLicense.License
}
report.Resolve(&Result{
diff --git a/pkg/deps/jar_test.go b/pkg/deps/jar_test.go
index de31b0b1..62156859 100644
--- a/pkg/deps/jar_test.go
+++ b/pkg/deps/jar_test.go
@@ -132,7 +132,7 @@ func TestResolveJar(t *testing.T) {
report := deps.Report{}
for _, jar := range jars {
if resolver.CanResolve(jar) {
- if err := resolver.Resolve(jar, &report); err != nil {
+ if err := resolver.Resolve(jar, nil, &report); err != nil {
t.Error(err)
return
}
diff --git a/pkg/deps/maven.go b/pkg/deps/maven.go
index 32740746..28d1ce33 100644
--- a/pkg/deps/maven.go
+++ b/pkg/deps/maven.go
@@ -48,7 +48,7 @@ func (resolver *MavenPomResolver) CanResolve(mavenPomFile string) bool {
}
// Resolve resolves licenses of all dependencies declared in the pom.xml file.
-func (resolver *MavenPomResolver) Resolve(mavenPomFile string, report *Report) error {
+func (resolver *MavenPomResolver) Resolve(mavenPomFile string, licenses []*ConfigDepLicense, report *Report) error {
if err := os.Chdir(filepath.Dir(mavenPomFile)); err != nil {
return err
}
@@ -70,7 +70,7 @@ func (resolver *MavenPomResolver) Resolve(mavenPomFile string, report *Report) e
}
}
- return resolver.ResolveDependencies(deps, report)
+ return resolver.ResolveDependencies(deps, licenses, report)
}
// CheckMVN check available maven tools, find local repositories and download all dependencies
@@ -142,10 +142,16 @@ func (resolver *MavenPomResolver) LoadDependencies() ([]*Dependency, error) {
}
// ResolveDependencies resolves the licenses of the given dependencies
-func (resolver *MavenPomResolver) ResolveDependencies(deps []*Dependency, report *Report) error {
+func (resolver *MavenPomResolver) ResolveDependencies(deps []*Dependency, licenses []*ConfigDepLicense, report *Report) error {
for _, dep := range deps {
state := NotFound
- err := resolver.ResolveLicense(&state, dep, report)
+ var declareLicense *ConfigDepLicense
+ for _, l := range licenses {
+ if l.Name == fmt.Sprintf("%s:%s", dep.GroupID, dep.ArtifactID) && l.Version == dep.Version {
+ declareLicense = l
+ }
+ }
+ err := resolver.ResolveLicense(&state, dep, declareLicense, report)
if err != nil {
logger.Log.Warnf("Failed to resolve the license of <%s>: %v\n", dep.Jar(), state.String())
report.Skip(&Result{
@@ -159,17 +165,17 @@ func (resolver *MavenPomResolver) ResolveDependencies(deps []*Dependency, report
}
// ResolveLicense search all possible locations of the license, such as pom file, jar package
-func (resolver *MavenPomResolver) ResolveLicense(state *State, dep *Dependency, report *Report) error {
+func (resolver *MavenPomResolver) ResolveLicense(state *State, dep *Dependency, declareLicense *ConfigDepLicense, report *Report) error {
err := resolver.ResolveJar(state, filepath.Join(resolver.repo, dep.Path(), dep.Jar()), dep.Version, report)
if err == nil {
return nil
}
- return resolver.ResolveLicenseFromPom(state, dep, report)
+ return resolver.ResolveLicenseFromPom(state, dep, declareLicense, report)
}
// ResolveLicenseFromPom search for license in the pom file, which may appear in the header comments or in license element of xml
-func (resolver *MavenPomResolver) ResolveLicenseFromPom(state *State, dep *Dependency, report *Report) (err error) {
+func (resolver *MavenPomResolver) ResolveLicenseFromPom(state *State, dep *Dependency, declareLicense *ConfigDepLicense, report *Report) (err error) {
pomFile := filepath.Join(resolver.repo, dep.Path(), dep.Pom())
pom, err := resolver.ReadLicensesFromPom(pomFile)
@@ -192,7 +198,7 @@ func (resolver *MavenPomResolver) ResolveLicenseFromPom(state *State, dep *Depen
return err
} else if headerComments != "" {
*state |= FoundLicenseInPomHeader
- return resolver.IdentifyLicense(pomFile, dep.Jar(), headerComments, dep.Version, report)
+ return resolver.IdentifyLicense(pomFile, dep.Jar(), headerComments, dep.Version, declareLicense, report)
}
return fmt.Errorf("not found in pom file")
diff --git a/pkg/deps/maven_test.go b/pkg/deps/maven_test.go
index 5c4b7976..75c6ae05 100644
--- a/pkg/deps/maven_test.go
+++ b/pkg/deps/maven_test.go
@@ -113,7 +113,7 @@ func TestResolveMaven(t *testing.T) {
if resolver.CanResolve(pomFile) {
report := deps.Report{}
- if err := resolver.Resolve(pomFile, &report); err != nil {
+ if err := resolver.Resolve(pomFile, nil, &report); err != nil {
t.Error(err)
return
}
diff --git a/pkg/deps/npm.go b/pkg/deps/npm.go
index 77e814ea..d1d19274 100644
--- a/pkg/deps/npm.go
+++ b/pkg/deps/npm.go
@@ -63,7 +63,7 @@ func (resolver *NpmResolver) CanResolve(file string) bool {
}
// Resolve resolves licenses of all dependencies declared in the package.json file.
-func (resolver *NpmResolver) Resolve(pkgFile string, report *Report) error {
+func (resolver *NpmResolver) Resolve(pkgFile string, licenses []*ConfigDepLicense, report *Report) error {
workDir := filepath.Dir(pkgFile)
if err := os.Chdir(workDir); err != nil {
return err
@@ -88,6 +88,10 @@ func (resolver *NpmResolver) Resolve(pkgFile string, report *Report) error {
if result := resolver.ResolvePackageLicense(pkg.Name, pkg.Path); result.LicenseSpdxID != "" {
report.Resolve(result)
} else {
+ if resolver.tryToResolve(pkg, licenses, result) {
+ report.Resolve(result)
+ continue
+ }
result.LicenseSpdxID = Unknown
report.Skip(result)
logger.Log.Warnln("Failed to resolve the license of dependency:", pkg.Name, result.ResolveErrors)
@@ -96,6 +100,17 @@ func (resolver *NpmResolver) Resolve(pkgFile string, report *Report) error {
return nil
}
+// TryToResolve trying to resolve the license by declaration
+func (resolver *NpmResolver) tryToResolve(p *Package, licenses []*ConfigDepLicense, r *Result) bool {
+ for _, l := range licenses {
+ if l.Name == p.Name && l.Version == p.Version {
+ r.LicenseSpdxID = l.License
+ return true
+ }
+ }
+ return false
+}
+
// NeedSkipInstallPkgs queries whether to skip the procedure of installing or updating packages
func (resolver *NpmResolver) NeedSkipInstallPkgs() bool {
const countdown = 5
diff --git a/pkg/deps/resolve.go b/pkg/deps/resolve.go
index 3c0d3b48..325b9d0e 100644
--- a/pkg/deps/resolve.go
+++ b/pkg/deps/resolve.go
@@ -23,7 +23,7 @@ import (
type Resolver interface {
CanResolve(string) bool
- Resolve(string, *Report) error
+ Resolve(string, []*ConfigDepLicense, *Report) error
}
var Resolvers = []Resolver{
@@ -39,7 +39,7 @@ resolveFile:
if !resolver.CanResolve(file) {
continue
}
- if err := resolver.Resolve(file, report); err != nil {
+ if err := resolver.Resolve(file, config.License, report); err != nil {
return err
}
continue resolveFile
diff --git a/pkg/deps/summary.go b/pkg/deps/summary.go
new file mode 100644
index 00000000..e4195805
--- /dev/null
+++ b/pkg/deps/summary.go
@@ -0,0 +1,114 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package deps
+
+import (
+ "bytes"
+ "io/ioutil"
+ "path/filepath"
+ "regexp"
+ "text/template"
+
+ "github.com/apache/skywalking-eyes/pkg/header"
+ "github.com/apache/skywalking-eyes/pkg/license"
+)
+
+var fileNamePattern = regexp.MustCompile(`[^a-zA-Z0-9\\.\-]`)
+
+type SummaryRenderContext struct {
+ LicenseContent string // Current project license content
+ Groups []*SummaryRenderLicenseGroup // All dependency license groups
+}
+
+type SummaryRenderLicenseGroup struct {
+ Name string // Aggregate all same license ID dependencies
+ Deps []*SummaryRenderLicense // Same license ID dependencies
+}
+
+type SummaryRenderLicense struct {
+ Name string // Dependency name
+ Version string // Dependency version
+ Location string // The filename of generated license file
+ LicenseID string // License ID
+}
+
+func GenerateDependencyLicenseFilename(result *Result) string {
+ filename := string(fileNamePattern.ReplaceAll([]byte(result.Dependency), []byte("-")))
+ return "license-" + filename + ".txt"
+}
+
+func ParseTemplate(path string) (*template.Template, error) {
+ absPath, err := filepath.Abs(path)
+ if err != nil {
+ return nil, err
+ }
+ tpl, err := ioutil.ReadFile(absPath)
+ if err != nil {
+ return nil, err
+ }
+ return template.New("summary").Parse(string(tpl))
+}
+
+// GenerateSummary generate the summary content by template, license config and dependency report
+func GenerateSummary(tpl *template.Template, head *header.ConfigHeader, rep *Report) (string, error) {
+ var r bytes.Buffer
+ context, err := generateSummaryRenderContext(head, rep)
+ if err != nil {
+ return "", err
+ }
+ if err := tpl.Execute(&r, context); err != nil {
+ return "", err
+ }
+ return r.String(), nil
+}
+
+func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) (*SummaryRenderContext, error) {
+ // the license id of the project
+ licenseContent, err := license.GetLicenseContent(head.License.SpdxID)
+ if err != nil {
+ return nil, err
+ }
+
+ groups := make(map[string]*SummaryRenderLicenseGroup)
+ for _, r := range rep.Resolved {
+ group := groups[r.LicenseSpdxID]
+ if group == nil {
+ group = &SummaryRenderLicenseGroup{
+ Name: r.LicenseSpdxID,
+ Deps: make([]*SummaryRenderLicense, 0),
+ }
+ groups[r.LicenseSpdxID] = group
+ }
+
+ group.Deps = append(group.Deps, &SummaryRenderLicense{
+ Name: r.Dependency,
+ Version: r.Version,
+ Location: GenerateDependencyLicenseFilename(r),
+ LicenseID: r.LicenseSpdxID,
+ })
+ }
+
+ groupArray := make([]*SummaryRenderLicenseGroup, 0)
+ for _, g := range groups {
+ groupArray = append(groupArray, g)
+ }
+ return &SummaryRenderContext{
+ LicenseContent: licenseContent,
+ Groups: groupArray,
+ }, nil
+}
diff --git a/pkg/license/identifier.go b/pkg/license/identifier.go
index 7a09a154..167b8c4c 100644
--- a/pkg/license/identifier.go
+++ b/pkg/license/identifier.go
@@ -102,3 +102,25 @@ func Identify(pkgPath, content string) (string, error) {
return "", fmt.Errorf("cannot identify license content")
}
}
+
+// GetLicenseContent from license id
+func GetLicenseContent(spdxID string) (string, error) {
+ for _, dir := range templatesDirs {
+ files, err := assets.AssetDir(dir)
+ if err != nil {
+ continue
+ }
+ for _, f := range files {
+ if spdxID != strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) {
+ continue
+ }
+
+ res, err := assets.Asset(filepath.Join(dir, f.Name()))
+ if err != nil {
+ return "", err
+ }
+ return string(res), nil
+ }
+ }
+ return "", fmt.Errorf("could not found license: %s", spdxID)
+}
From 6c21a03c5959ca725f48ca6f513977218ff4ab41 Mon Sep 17 00:00:00 2001
From: Mrproliu <741550557@qq.com>
Date: Fri, 6 May 2022 17:30:36 +0800
Subject: [PATCH 2/7] fix CI
---
pkg/deps/summary.go | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pkg/deps/summary.go b/pkg/deps/summary.go
index e4195805..1907ffe1 100644
--- a/pkg/deps/summary.go
+++ b/pkg/deps/summary.go
@@ -19,7 +19,7 @@ package deps
import (
"bytes"
- "io/ioutil"
+ "os"
"path/filepath"
"regexp"
"text/template"
@@ -57,7 +57,7 @@ func ParseTemplate(path string) (*template.Template, error) {
if err != nil {
return nil, err
}
- tpl, err := ioutil.ReadFile(absPath)
+ tpl, err := os.ReadFile(absPath)
if err != nil {
return nil, err
}
From f7f978d6e1c38a014c55b575d8a7ef733aac758c Mon Sep 17 00:00:00 2001
From: Mrproliu <741550557@qq.com>
Date: Fri, 6 May 2022 21:59:29 +0800
Subject: [PATCH 3/7] fix issue
---
README.md | 10 +++++-----
commands/deps_resolve.go | 32 ++++++++++++++++++--------------
pkg/deps/golang.go | 14 +++++++++-----
pkg/deps/jar.go | 13 ++++++++-----
pkg/deps/npm.go | 25 +++++++++++++++++++------
pkg/deps/npm_test.go | 2 +-
pkg/deps/summary.go | 37 +++++++++++--------------------------
7 files changed, 71 insertions(+), 62 deletions(-)
diff --git a/README.md b/README.md
index fde8e655..4a5bda0d 100644
--- a/README.md
+++ b/README.md
@@ -157,12 +157,12 @@ INFO Totally checked 20 files, valid: 10, invalid: 10, ignored: 0, fixed: 10
This command serves as assistance for human beings to audit the dependencies license, it's exit code is always 0.
-We also support two flag:
+We also support two flags:
|Flag name|Short name|Description|
|---------|----------|-----------|
-|--output|-o|Save the dependencies' `LICENSE` files to a specified directory so that you can put them in distribution package if needed.|
-|--summary|-s|Based on the template, aggregate all dependency information and generate a `LICENSE` file.|
+|`--output`|`-o`|Save the dependencies' `LICENSE` files to a specified directory so that you can put them in distribution package if needed.|
+|`--summary`|`-s`|Based on the template, aggregate all dependency information and generate a `LICENSE` file.|
```bash
license-eye -c test/testdata/.licenserc_for_test_check.yaml dep resolve -o ./dependencies/licenses -s LICENSE.tpl
@@ -494,9 +494,9 @@ dependency: # <15>
14. The `comment_style_id` set the license header comment style, it's the `id` at the `styles.yaml`.
15. The `dependency` section is configurations for resolving dependencies' licenses.
16. The `files` are the files that declare the dependencies of a project, typically, `go.mod` in Go project, `pom.xml` in maven project, and `package.json` in NodeJS project. If it's a relative path, it's relative to the `.licenserc.yaml`.
-17. Declare the license which cannot be identified as a dependency.
+17. Declare the licenses which cannot be identified by this tool.
18. The `name` of the dependency, The name is different for different projects, `PackagePath` in Go project, `GroupID:ArtifactID` in maven project, `PackageName` in NodeJS project.
-19. The `version` of the dependency, It's locked, prevent version update and change the License.
+19. The `version` of the dependency, it's locked, preventing license changed between different versions.
20. The [SPDX ID](https://spdx.org/licenses/) of the dependency license.
**NOTE**: When the `SPDX-ID` is Apache-2.0 and the owner is Apache Software foundation, the content would be [a dedicated license](https://www.apache.org/legal/src-headers.html#headers) specified by the ASF, otherwise, the license would be [the standard one](https://www.apache.org/foundation/license-faq.html#Apply-My-Software).
diff --git a/commands/deps_resolve.go b/commands/deps_resolve.go
index 7ad20745..3e57bc14 100644
--- a/commands/deps_resolve.go
+++ b/commands/deps_resolve.go
@@ -21,6 +21,7 @@ import (
"fmt"
"os"
"path/filepath"
+ "regexp"
"strings"
"text/template"
@@ -38,9 +39,11 @@ func init() {
DepsResolveCommand.PersistentFlags().StringVarP(&outDir, "output", "o", "",
"the directory to output the resolved dependencies' licenses, if not set the dependencies' licenses won't be saved")
DepsResolveCommand.PersistentFlags().StringVarP(&summaryTplPath, "summary", "s", "",
- "the template file to write the summary the dependencies' licenses, if not set the licenses just print as the table")
+ "the template file to write the summary the dependencies' licenses into \"LICENSE\" file into directory which same with template file.")
}
+var fileNamePattern = regexp.MustCompile(`[^a-zA-Z0-9\\.\-]`)
+
var DepsResolveCommand = &cobra.Command{
Use: "resolve",
Aliases: []string{"r"},
@@ -57,9 +60,11 @@ var DepsResolveCommand = &cobra.Command{
}
}
if summaryTplPath != "" {
- if outDir == "" {
- return fmt.Errorf("please provide the output directory to write the license summary file")
+ absPath, err := filepath.Abs(summaryTplPath)
+ if err != nil {
+ return err
}
+ summaryTplPath = absPath
tpl, err := deps.ParseTemplate(summaryTplPath)
if err != nil {
return err
@@ -82,7 +87,9 @@ var DepsResolveCommand = &cobra.Command{
}
if summaryTpl != nil {
- writeSummary(&report)
+ if err := writeSummary(&report); err != nil {
+ logger.Log.Warnf("write summary file error: %v", err)
+ }
}
fmt.Println(report.String())
@@ -103,7 +110,8 @@ var DepsResolveCommand = &cobra.Command{
}
func writeLicense(result *deps.Result) {
- filename := filepath.Join(outDir, deps.GenerateDependencyLicenseFilename(result))
+ filename := string(fileNamePattern.ReplaceAll([]byte(result.Dependency), []byte("-")))
+ filename = filepath.Join(outDir, "license-"+filename+".txt")
file, err := os.Create(filename)
if err != nil {
logger.Log.Errorf("failed to create license file %v: %v", filename, err)
@@ -117,20 +125,16 @@ func writeLicense(result *deps.Result) {
}
}
-func writeSummary(rep *deps.Report) {
- file, err := os.Create(filepath.Join(outDir, "LICENSE"))
+func writeSummary(rep *deps.Report) error {
+ file, err := os.Create(filepath.Join(filepath.Dir(summaryTplPath), "LICENSE"))
if err != nil {
- logger.Log.Errorf("failed to create summary license file %s: %v", "LICENSE", err)
- return
+ return err
}
defer file.Close()
summary, err := deps.GenerateSummary(summaryTpl, &Config.Header, rep)
if err != nil {
- logger.Log.Errorf("failed to generate summary content: %v", err)
- return
+ return err
}
_, err = file.WriteString(summary)
- if err != nil {
- logger.Log.Errorf("failed to write summary file, %v", err)
- }
+ return err
}
diff --git a/pkg/deps/golang.go b/pkg/deps/golang.go
index 7e3af85d..a65c20cf 100644
--- a/pkg/deps/golang.go
+++ b/pkg/deps/golang.go
@@ -123,18 +123,22 @@ func (resolver *GoModResolver) ResolvePackageLicense(module *packages.Module, de
if err != nil {
return err
}
- identifier, err := license.Identify(module.Path, string(content))
- if err != nil {
- if declareLicense == nil {
+ var licenseID string
+ if declareLicense != nil {
+ licenseID = declareLicense.License
+ } else {
+ identifier, err := license.Identify(module.Path, string(content))
+ if err != nil {
return err
}
- identifier = declareLicense.License
+ licenseID = identifier
}
+
report.Resolve(&Result{
Dependency: module.Path,
LicenseFilePath: licenseFilePath,
LicenseContent: string(content),
- LicenseSpdxID: identifier,
+ LicenseSpdxID: licenseID,
Version: module.Version,
})
return nil
diff --git a/pkg/deps/jar.go b/pkg/deps/jar.go
index 09868bc0..0121da7b 100644
--- a/pkg/deps/jar.go
+++ b/pkg/deps/jar.go
@@ -123,19 +123,22 @@ func (resolver *JarResolver) ReadFileFromZip(archiveFile *zip.File) (*bytes.Buff
}
func (resolver *JarResolver) IdentifyLicense(path, dep, content, version string, declareLicense *ConfigDepLicense, report *Report) error {
- identifier, err := license.Identify(path, content)
- if err != nil {
- if declareLicense == nil {
+ var licenseID string
+ if declareLicense != nil {
+ licenseID = declareLicense.License
+ } else {
+ identifier, err := license.Identify(path, content)
+ if err != nil {
return err
}
- identifier = declareLicense.License
+ licenseID = identifier
}
report.Resolve(&Result{
Dependency: dep,
LicenseFilePath: path,
LicenseContent: content,
- LicenseSpdxID: identifier,
+ LicenseSpdxID: licenseID,
Version: version,
})
return nil
diff --git a/pkg/deps/npm.go b/pkg/deps/npm.go
index d1d19274..71bde355 100644
--- a/pkg/deps/npm.go
+++ b/pkg/deps/npm.go
@@ -85,7 +85,7 @@ func (resolver *NpmResolver) Resolve(pkgFile string, licenses []*ConfigDepLicens
// Walk through each package's root directory to resolve licenses
// Resolve from a package's package.json file or its license file
for _, pkg := range pkgs {
- if result := resolver.ResolvePackageLicense(pkg.Name, pkg.Path); result.LicenseSpdxID != "" {
+ if result := resolver.ResolvePackageLicense(pkg.Name, pkg.Path, licenses); result.LicenseSpdxID != "" {
report.Resolve(result)
} else {
if resolver.tryToResolve(pkg, licenses, result) {
@@ -200,17 +200,17 @@ func (resolver *NpmResolver) GetInstalledPkgs(pkgDir string) []*Package {
// First, try to find and parse the package's package.json file to check the license file
// If the previous step fails, then try to identify the package's LICENSE file
// It's a necessary procedure to check the LICENSE file, because the resolver needs to record the license content
-func (resolver *NpmResolver) ResolvePackageLicense(pkgName, pkgPath string) *Result {
+func (resolver *NpmResolver) ResolvePackageLicense(pkgName, pkgPath string, licenses []*ConfigDepLicense) *Result {
result := &Result{
Dependency: pkgName,
}
// resolve from the package.json file
- if err := resolver.ResolvePkgFile(result, pkgPath); err != nil {
+ if err := resolver.ResolvePkgFile(result, pkgPath, licenses); err != nil {
result.ResolveErrors = append(result.ResolveErrors, err)
}
// resolve from the LICENSE file
- if err := resolver.ResolveLcsFile(result, pkgPath); err != nil {
+ if err := resolver.ResolveLcsFile(result, pkgPath, licenses); err != nil {
result.ResolveErrors = append(result.ResolveErrors, err)
}
@@ -218,7 +218,7 @@ func (resolver *NpmResolver) ResolvePackageLicense(pkgName, pkgPath string) *Res
}
// ResolvePkgFile tries to find and parse the package.json file to capture the license field
-func (resolver *NpmResolver) ResolvePkgFile(result *Result, pkgPath string) error {
+func (resolver *NpmResolver) ResolvePkgFile(result *Result, pkgPath string, licenses []*ConfigDepLicense) error {
expectedPkgFile := filepath.Join(pkgPath, PkgFileName)
packageInfo, err := resolver.ParsePkgFile(expectedPkgFile)
if err != nil {
@@ -226,6 +226,13 @@ func (resolver *NpmResolver) ResolvePkgFile(result *Result, pkgPath string) erro
}
result.Version = packageInfo.Version
+ for _, l := range licenses {
+ if l.Name == packageInfo.Name && l.Version == packageInfo.Version {
+ result.LicenseSpdxID = l.License
+ return nil
+ }
+ }
+
if lcs, ok := resolver.ResolveLicenseField(packageInfo.License); ok {
result.LicenseSpdxID = lcs
return nil
@@ -274,7 +281,7 @@ func (resolver *NpmResolver) ResolveLicensesField(licenses []Lcs) (string, bool)
}
// ResolveLcsFile tries to find the license file to identify the license
-func (resolver *NpmResolver) ResolveLcsFile(result *Result, pkgPath string) error {
+func (resolver *NpmResolver) ResolveLcsFile(result *Result, pkgPath string, licenses []*ConfigDepLicense) error {
depFiles, err := os.ReadDir(pkgPath)
if err != nil {
return err
@@ -293,6 +300,12 @@ func (resolver *NpmResolver) ResolveLcsFile(result *Result, pkgPath string) erro
if result.LicenseSpdxID != "" {
return nil
}
+ for _, l := range licenses {
+ if l.Name == info.Name() && l.Version == result.Version {
+ result.LicenseSpdxID = l.License
+ return nil
+ }
+ }
identifier, err := license.Identify(result.Dependency, string(content))
if err != nil {
return err
diff --git a/pkg/deps/npm_test.go b/pkg/deps/npm_test.go
index f30cba57..5d761107 100644
--- a/pkg/deps/npm_test.go
+++ b/pkg/deps/npm_test.go
@@ -95,7 +95,7 @@ func TestResolvePkgFile(t *testing.T) {
if err != nil {
t.Fatal(err)
}
- err = resolver.ResolvePkgFile(result, f.Name())
+ err = resolver.ResolvePkgFile(result, f.Name(), nil)
if result.LicenseSpdxID != data.result && (err != nil) == data.hasErr {
t.Fail()
}
diff --git a/pkg/deps/summary.go b/pkg/deps/summary.go
index 1907ffe1..8e49ea6f 100644
--- a/pkg/deps/summary.go
+++ b/pkg/deps/summary.go
@@ -20,16 +20,12 @@ package deps
import (
"bytes"
"os"
- "path/filepath"
- "regexp"
"text/template"
"github.com/apache/skywalking-eyes/pkg/header"
"github.com/apache/skywalking-eyes/pkg/license"
)
-var fileNamePattern = regexp.MustCompile(`[^a-zA-Z0-9\\.\-]`)
-
type SummaryRenderContext struct {
LicenseContent string // Current project license content
Groups []*SummaryRenderLicenseGroup // All dependency license groups
@@ -43,21 +39,11 @@ type SummaryRenderLicenseGroup struct {
type SummaryRenderLicense struct {
Name string // Dependency name
Version string // Dependency version
- Location string // The filename of generated license file
LicenseID string // License ID
}
-func GenerateDependencyLicenseFilename(result *Result) string {
- filename := string(fileNamePattern.ReplaceAll([]byte(result.Dependency), []byte("-")))
- return "license-" + filename + ".txt"
-}
-
func ParseTemplate(path string) (*template.Template, error) {
- absPath, err := filepath.Abs(path)
- if err != nil {
- return nil, err
- }
- tpl, err := os.ReadFile(absPath)
+ tpl, err := os.ReadFile(path)
if err != nil {
return nil, err
}
@@ -67,21 +53,21 @@ func ParseTemplate(path string) (*template.Template, error) {
// GenerateSummary generate the summary content by template, license config and dependency report
func GenerateSummary(tpl *template.Template, head *header.ConfigHeader, rep *Report) (string, error) {
var r bytes.Buffer
- context, err := generateSummaryRenderContext(head, rep)
- if err != nil {
- return "", err
- }
+ context := generateSummaryRenderContext(head, rep)
if err := tpl.Execute(&r, context); err != nil {
return "", err
}
return r.String(), nil
}
-func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) (*SummaryRenderContext, error) {
+func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) *SummaryRenderContext {
// the license id of the project
- licenseContent, err := license.GetLicenseContent(head.License.SpdxID)
- if err != nil {
- return nil, err
+ var headerContent string
+ if head.License.SpdxID != "" {
+ headerContent, _ = license.GetLicenseContent(head.License.SpdxID)
+ }
+ if headerContent == "" {
+ headerContent = head.GetLicenseContent()
}
groups := make(map[string]*SummaryRenderLicenseGroup)
@@ -98,7 +84,6 @@ func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) (*Summ
group.Deps = append(group.Deps, &SummaryRenderLicense{
Name: r.Dependency,
Version: r.Version,
- Location: GenerateDependencyLicenseFilename(r),
LicenseID: r.LicenseSpdxID,
})
}
@@ -108,7 +93,7 @@ func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) (*Summ
groupArray = append(groupArray, g)
}
return &SummaryRenderContext{
- LicenseContent: licenseContent,
+ LicenseContent: headerContent,
Groups: groupArray,
- }, nil
+ }
}
From 40abd32b0fae99f287bc9821b16536ee2453d833 Mon Sep 17 00:00:00 2001
From: Mrproliu <741550557@qq.com>
Date: Fri, 6 May 2022 22:09:11 +0800
Subject: [PATCH 4/7] remove unnecessary code
---
pkg/deps/npm.go | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/pkg/deps/npm.go b/pkg/deps/npm.go
index 71bde355..cbecd4e0 100644
--- a/pkg/deps/npm.go
+++ b/pkg/deps/npm.go
@@ -88,10 +88,6 @@ func (resolver *NpmResolver) Resolve(pkgFile string, licenses []*ConfigDepLicens
if result := resolver.ResolvePackageLicense(pkg.Name, pkg.Path, licenses); result.LicenseSpdxID != "" {
report.Resolve(result)
} else {
- if resolver.tryToResolve(pkg, licenses, result) {
- report.Resolve(result)
- continue
- }
result.LicenseSpdxID = Unknown
report.Skip(result)
logger.Log.Warnln("Failed to resolve the license of dependency:", pkg.Name, result.ResolveErrors)
@@ -100,17 +96,6 @@ func (resolver *NpmResolver) Resolve(pkgFile string, licenses []*ConfigDepLicens
return nil
}
-// TryToResolve trying to resolve the license by declaration
-func (resolver *NpmResolver) tryToResolve(p *Package, licenses []*ConfigDepLicense, r *Result) bool {
- for _, l := range licenses {
- if l.Name == p.Name && l.Version == p.Version {
- r.LicenseSpdxID = l.License
- return true
- }
- }
- return false
-}
-
// NeedSkipInstallPkgs queries whether to skip the procedure of installing or updating packages
func (resolver *NpmResolver) NeedSkipInstallPkgs() bool {
const countdown = 5
From dca36b428b37778aa27a4c7b0290fc21aa01977c Mon Sep 17 00:00:00 2001
From: Mrproliu <741550557@qq.com>
Date: Sat, 7 May 2022 11:25:53 +0800
Subject: [PATCH 5/7] fix issue
---
README.md | 292 ++++++++++++++++++++++++++++++++++++++
commands/deps_resolve.go | 14 +-
pkg/license/identifier.go | 26 ++--
3 files changed, 312 insertions(+), 20 deletions(-)
diff --git a/README.md b/README.md
index 4a5bda0d..64258426 100644
--- a/README.md
+++ b/README.md
@@ -363,6 +363,298 @@ gopkg.in/check.v1
+##### Summary Template
+
+The summary is a template to generate the summary of dependencies' licenses based on the [Golang Template](https://pkg.go.dev/text/template). It includes these variables:
+
+|Name|Type|Example|Description|
+|----|----|-------|-----------|
+|LicenseContent|string|`{{.LicenseContent}}`|The project license content, it's relate to the `header.license.spdx-id` config. |
+|Groups|list structure|`{{ range .Groups }}`|The dependency group, all license is aggregate by the same license [SPDX ID](https://spdx.org/licenses/). |
+|Groups.Name|string|`{{.Name}}`|The [SPDX ID](https://spdx.org/licenses/) of dependency. |
+|Groups.Deps|list structure|`{{ range .Deps }}`|All dependencies, it including all of same [SPDX ID](https://spdx.org/licenses/) dependencies under `Groups.Name`. |
+|Groups.Deps.Name|string|`{{.Name}}`|The name of the dependency. |
+|Groups.Deps.Version|string|`{{.Version}}`|The version of the dependency. |
+|Groups.Deps.LicenseID|string|`{{.LicenseID}}`|The [SPDX ID](https://spdx.org/licenses/) of the dependency license. |
+
+
+Summary Template Generate
+
+Summary template content:
+```
+{{.LicenseContent }}
+{{ range .Groups }}
+========================================================================
+{{.Name}} licenses
+========================================================================
+{{range .Deps}}
+ {{.Name}} {{.Version}} {{.LicenseID}}
+{{- end }}
+{{ end }}
+```
+
+Generate LICENSE file content:
+```
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+
+========================================================================
+MIT licenses
+========================================================================
+
+ github.com/BurntSushi/toml v0.3.1 MIT
+ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf MIT
+ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e MIT
+ github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da MIT
+ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310 MIT
+ github.com/beorn7/perks v1.0.0 MIT
+ github.com/bgentry/speakeasy v0.1.0 MIT
+ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c MIT
+ github.com/bmatcuk/doublestar/v2 v2.0.4 MIT
+
+========================================================================
+ISC licenses
+========================================================================
+
+ github.com/davecgh/go-spew v1.1.1 ISC
+
+========================================================================
+BSD-2-Clause licenses
+========================================================================
+
+ github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 BSD-2-Clause
+ github.com/gorilla/websocket v1.4.2 BSD-2-Clause
+ github.com/pkg/errors v0.8.1 BSD-2-Clause
+ github.com/russross/blackfriday/v2 v2.0.1 BSD-2-Clause
+
+========================================================================
+MPL-2.0-no-copyleft-exception licenses
+========================================================================
+
+ github.com/hashicorp/consul/api v1.1.0 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/consul/sdk v0.1.1 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/go-cleanhttp v0.5.1 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/go-immutable-radix v1.0.0 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/go-multierror v1.0.0 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/go-rootcerts v1.0.0 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/go-sockaddr v1.0.0 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/go-uuid v1.0.1 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/golang-lru v0.5.1 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/logutils v1.0.0 MPL-2.0-no-copyleft-exception
+ github.com/hashicorp/memberlist v0.1.3 MPL-2.0-no-copyleft-exception
+
+========================================================================
+MPL-2.0 licenses
+========================================================================
+
+ github.com/hashicorp/errwrap v1.0.0 MPL-2.0
+ github.com/hashicorp/hcl v1.0.0 MPL-2.0
+ github.com/hashicorp/serf v0.8.2 MPL-2.0
+ github.com/mitchellh/cli v1.0.0 MPL-2.0
+ github.com/mitchellh/gox v0.4.0 MPL-2.0
+
+========================================================================
+MIT and Apache licenses
+========================================================================
+
+ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 MIT and Apache
+
+========================================================================
+Apache-2.0 licenses
+========================================================================
+
+ cloud.google.com/go v0.46.3 Apache-2.0
+ cloud.google.com/go/bigquery v1.0.1 Apache-2.0
+ cloud.google.com/go/datastore v1.0.0 Apache-2.0
+ cloud.google.com/go/firestore v1.1.0 Apache-2.0
+ cloud.google.com/go/pubsub v1.0.1 Apache-2.0
+ cloud.google.com/go/storage v1.0.0 Apache-2.0
+
+========================================================================
+BSD-3-Clause licenses
+========================================================================
+
+ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 BSD-3-Clause
+ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 BSD-3-Clause
+ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc BSD-3-Clause
+ github.com/fsnotify/fsnotify v1.4.7 BSD-3-Clause
+```
+
+
+
#### Check Dependencies' licenses
This command can be used to perform automatic license compatibility check, when there is incompatible licenses found,
diff --git a/commands/deps_resolve.go b/commands/deps_resolve.go
index 3e57bc14..ce889186 100644
--- a/commands/deps_resolve.go
+++ b/commands/deps_resolve.go
@@ -39,7 +39,7 @@ func init() {
DepsResolveCommand.PersistentFlags().StringVarP(&outDir, "output", "o", "",
"the directory to output the resolved dependencies' licenses, if not set the dependencies' licenses won't be saved")
DepsResolveCommand.PersistentFlags().StringVarP(&summaryTplPath, "summary", "s", "",
- "the template file to write the summary the dependencies' licenses into \"LICENSE\" file into directory which same with template file.")
+ "the template file to write the summary of dependencies' licenses, a new file named \"LICENSE\" will be created in the same directory as the template file, to save the final summary.")
}
var fileNamePattern = regexp.MustCompile(`[^a-zA-Z0-9\\.\-]`)
@@ -80,15 +80,15 @@ var DepsResolveCommand = &cobra.Command{
return err
}
- if outDir != "" {
- for _, result := range report.Resolved {
- writeLicense(result)
+ if summaryTpl != nil {
+ if err := writeSummary(&report); err != nil {
+ return err
}
}
- if summaryTpl != nil {
- if err := writeSummary(&report); err != nil {
- logger.Log.Warnf("write summary file error: %v", err)
+ if outDir != "" {
+ for _, result := range report.Resolved {
+ writeLicense(result)
}
}
diff --git a/pkg/license/identifier.go b/pkg/license/identifier.go
index 167b8c4c..92372b0a 100644
--- a/pkg/license/identifier.go
+++ b/pkg/license/identifier.go
@@ -29,8 +29,10 @@ import (
"github.com/apache/skywalking-eyes/internal/logger"
)
+var licenseTemplatesDir = "lcs-templates"
+
var templatesDirs = []string{
- "lcs-templates",
+ licenseTemplatesDir,
// Some projects simply use the header text as their LICENSE content...
"header-templates",
}
@@ -105,22 +107,20 @@ func Identify(pkgPath, content string) (string, error) {
// GetLicenseContent from license id
func GetLicenseContent(spdxID string) (string, error) {
- for _, dir := range templatesDirs {
- files, err := assets.AssetDir(dir)
- if err != nil {
+ files, err := assets.AssetDir(licenseTemplatesDir)
+ if err != nil {
+ return "", err
+ }
+ for _, f := range files {
+ if spdxID != strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) {
continue
}
- for _, f := range files {
- if spdxID != strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) {
- continue
- }
- res, err := assets.Asset(filepath.Join(dir, f.Name()))
- if err != nil {
- return "", err
- }
- return string(res), nil
+ res, err := assets.Asset(filepath.Join(licenseTemplatesDir, f.Name()))
+ if err != nil {
+ return "", err
}
+ return string(res), nil
}
return "", fmt.Errorf("could not found license: %s", spdxID)
}
From 1b048a6afab66f7386ff940b2297a37a5b6d019d Mon Sep 17 00:00:00 2001
From: Mrproliu <741550557@qq.com>
Date: Sat, 7 May 2022 11:27:50 +0800
Subject: [PATCH 6/7] fix lint
---
commands/deps_resolve.go | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/commands/deps_resolve.go b/commands/deps_resolve.go
index ce889186..4c8e197e 100644
--- a/commands/deps_resolve.go
+++ b/commands/deps_resolve.go
@@ -39,7 +39,8 @@ func init() {
DepsResolveCommand.PersistentFlags().StringVarP(&outDir, "output", "o", "",
"the directory to output the resolved dependencies' licenses, if not set the dependencies' licenses won't be saved")
DepsResolveCommand.PersistentFlags().StringVarP(&summaryTplPath, "summary", "s", "",
- "the template file to write the summary of dependencies' licenses, a new file named \"LICENSE\" will be created in the same directory as the template file, to save the final summary.")
+ "the template file to write the summary of dependencies' licenses, a new file named \"LICENSE\" will be "+
+ "created in the same directory as the template file, to save the final summary.")
}
var fileNamePattern = regexp.MustCompile(`[^a-zA-Z0-9\\.\-]`)
From 8ec00b43ad90f94175055933f1e4cc33d74d5129 Mon Sep 17 00:00:00 2001
From: Mrproliu <741550557@qq.com>
Date: Sat, 7 May 2022 13:37:04 +0800
Subject: [PATCH 7/7] fix issue
---
README.md | 10 +++++-----
pkg/deps/summary.go | 23 +++++++++++++++--------
pkg/license/identifier.go | 15 ++-------------
3 files changed, 22 insertions(+), 26 deletions(-)
diff --git a/README.md b/README.md
index 64258426..44da58da 100644
--- a/README.md
+++ b/README.md
@@ -369,10 +369,10 @@ The summary is a template to generate the summary of dependencies' licenses base
|Name|Type|Example|Description|
|----|----|-------|-----------|
-|LicenseContent|string|`{{.LicenseContent}}`|The project license content, it's relate to the `header.license.spdx-id` config. |
-|Groups|list structure|`{{ range .Groups }}`|The dependency group, all license is aggregate by the same license [SPDX ID](https://spdx.org/licenses/). |
-|Groups.Name|string|`{{.Name}}`|The [SPDX ID](https://spdx.org/licenses/) of dependency. |
-|Groups.Deps|list structure|`{{ range .Deps }}`|All dependencies, it including all of same [SPDX ID](https://spdx.org/licenses/) dependencies under `Groups.Name`. |
+|LicenseContent|string|`{{.LicenseContent}}`|The project license content, it's the license of `header.license.spdx-id` (if set), otherwise it's the `header.license.content`. |
+|Groups|list structure|`{{ range .Groups }}`|The dependency groups, all licenses are grouped by the same license [SPDX ID](https://spdx.org/licenses/). |
+|Groups.LicenseID|string|`{{.LicenseID}}`|The [SPDX ID](https://spdx.org/licenses/) of dependency. |
+|Groups.Deps|list structure|`{{ range .Deps }}`|All dependencies with the same [SPDX ID](https://spdx.org/licenses/). |
|Groups.Deps.Name|string|`{{.Name}}`|The name of the dependency. |
|Groups.Deps.Version|string|`{{.Version}}`|The version of the dependency. |
|Groups.Deps.LicenseID|string|`{{.LicenseID}}`|The [SPDX ID](https://spdx.org/licenses/) of the dependency license. |
@@ -385,7 +385,7 @@ Summary template content:
{{.LicenseContent }}
{{ range .Groups }}
========================================================================
-{{.Name}} licenses
+{{.LicenseID}} licenses
========================================================================
{{range .Deps}}
{{.Name}} {{.Version}} {{.LicenseID}}
diff --git a/pkg/deps/summary.go b/pkg/deps/summary.go
index 8e49ea6f..d14acb75 100644
--- a/pkg/deps/summary.go
+++ b/pkg/deps/summary.go
@@ -32,8 +32,8 @@ type SummaryRenderContext struct {
}
type SummaryRenderLicenseGroup struct {
- Name string // Aggregate all same license ID dependencies
- Deps []*SummaryRenderLicense // Same license ID dependencies
+ LicenseID string // Aggregate all same license ID dependencies
+ Deps []*SummaryRenderLicense // Same license ID dependencies
}
type SummaryRenderLicense struct {
@@ -53,18 +53,25 @@ func ParseTemplate(path string) (*template.Template, error) {
// GenerateSummary generate the summary content by template, license config and dependency report
func GenerateSummary(tpl *template.Template, head *header.ConfigHeader, rep *Report) (string, error) {
var r bytes.Buffer
- context := generateSummaryRenderContext(head, rep)
+ context, err := generateSummaryRenderContext(head, rep)
+ if err != nil {
+ return "", err
+ }
if err := tpl.Execute(&r, context); err != nil {
return "", err
}
return r.String(), nil
}
-func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) *SummaryRenderContext {
+func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) (*SummaryRenderContext, error) {
// the license id of the project
var headerContent string
if head.License.SpdxID != "" {
- headerContent, _ = license.GetLicenseContent(head.License.SpdxID)
+ c, err := license.GetLicenseContent(head.License.SpdxID)
+ if err != nil {
+ return nil, err
+ }
+ headerContent = c
}
if headerContent == "" {
headerContent = head.GetLicenseContent()
@@ -75,8 +82,8 @@ func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) *Summa
group := groups[r.LicenseSpdxID]
if group == nil {
group = &SummaryRenderLicenseGroup{
- Name: r.LicenseSpdxID,
- Deps: make([]*SummaryRenderLicense, 0),
+ LicenseID: r.LicenseSpdxID,
+ Deps: make([]*SummaryRenderLicense, 0),
}
groups[r.LicenseSpdxID] = group
}
@@ -95,5 +102,5 @@ func generateSummaryRenderContext(head *header.ConfigHeader, rep *Report) *Summa
return &SummaryRenderContext{
LicenseContent: headerContent,
Groups: groupArray,
- }
+ }, nil
}
diff --git a/pkg/license/identifier.go b/pkg/license/identifier.go
index 92372b0a..c23ea758 100644
--- a/pkg/license/identifier.go
+++ b/pkg/license/identifier.go
@@ -107,20 +107,9 @@ func Identify(pkgPath, content string) (string, error) {
// GetLicenseContent from license id
func GetLicenseContent(spdxID string) (string, error) {
- files, err := assets.AssetDir(licenseTemplatesDir)
+ res, err := assets.Asset(filepath.Join(licenseTemplatesDir, spdxID+".txt"))
if err != nil {
return "", err
}
- for _, f := range files {
- if spdxID != strings.TrimSuffix(f.Name(), filepath.Ext(f.Name())) {
- continue
- }
-
- res, err := assets.Asset(filepath.Join(licenseTemplatesDir, f.Name()))
- if err != nil {
- return "", err
- }
- return string(res), nil
- }
- return "", fmt.Errorf("could not found license: %s", spdxID)
+ return string(res), nil
}