diff options
author | Steve Winslow <steve@swinslow.net> | 2020-06-14 15:35:55 -0400 |
---|---|---|
committer | Steve Winslow <steve@swinslow.net> | 2020-06-14 15:35:55 -0400 |
commit | dfaf5f3e3ed8a977d4ba1783ec6b95afa3faa150 (patch) | |
tree | 6ad3c33eb2df2918d319452fb182cdecfb6c4c23 | |
parent | aa88812312f0f42b5e3646d5bab8e3144614557f (diff) | |
download | spdx-tools-dfaf5f3e3ed8a977d4ba1783ec6b95afa3faa150.tar.gz |
Add idsearcher and tests for 2.2
Signed-off-by: Steve Winslow <steve@swinslow.net>
-rw-r--r-- | idsearcher/idsearcher.go | 136 | ||||
-rw-r--r-- | idsearcher/idsearcher_test.go | 14 |
2 files changed, 138 insertions, 12 deletions
diff --git a/idsearcher/idsearcher.go b/idsearcher/idsearcher.go index 0d40674..3982109 100644 --- a/idsearcher/idsearcher.go +++ b/idsearcher/idsearcher.go @@ -18,10 +18,12 @@ import ( "github.com/spdx/tools-golang/utils" ) -// Config is a collection of configuration settings for docbuilder +// ===== 2.1 Searcher functions ===== + +// Config2_1 is a collection of configuration settings for docbuilder // (for version 2.1 SPDX Documents). A few mandatory fields are set here // so that they can be repeatedly reused in multiple calls to Build2_1. -type Config struct { +type Config2_1 struct { // NamespacePrefix should be a URI representing a prefix for the // namespace with which the SPDX Document will be associated. // It will be used in the DocumentNamespace field in the CreationInfo @@ -41,14 +43,14 @@ type Config struct { SearcherPathsIgnored []string } -// BuildIDsDocument creates an SPDX Document (version 2.1) and searches for +// BuildIDsDocument2_1 creates an SPDX Document (version 2.1) and searches for // short-form IDs in each file, filling in license fields as appropriate. It // returns that document or error if any is encountered. Arguments: // - packageName: name of package / directory // - dirRoot: path to directory to be analyzed // - namespacePrefix: URI representing a prefix for the // namespace with which the SPDX Document will be associated -func BuildIDsDocument(packageName string, dirRoot string, idconfig *Config) (*spdx.Document2_1, error) { +func BuildIDsDocument2_1(packageName string, dirRoot string, idconfig *Config2_1) (*spdx.Document2_1, error) { // first, build the Document using builder bconfig := &builder.Config2_1{ NamespacePrefix: idconfig.NamespacePrefix, @@ -140,7 +142,131 @@ func BuildIDsDocument(packageName string, dirRoot string, idconfig *Config) (*sp return doc, nil } -// ===== Utility functions ===== +// ===== 2.2 Searcher functions ===== + +// Config2_2 is a collection of configuration settings for docbuilder +// (for version 2.2 SPDX Documents). A few mandatory fields are set here +// so that they can be repeatedly reused in multiple calls to Build2_2. +type Config2_2 struct { + // NamespacePrefix should be a URI representing a prefix for the + // namespace with which the SPDX Document will be associated. + // It will be used in the DocumentNamespace field in the CreationInfo + // section, followed by the per-Document package name and a random UUID. + NamespacePrefix string + + // BuilderPathsIgnored lists certain paths to be omitted from the built + // document. Each string should be a path, relative to the package's + // dirRoot, to a specific file or (for all files in a directory) ending + // in a slash. Prefix the string with "**" to omit all instances of that + // file / directory, regardless of where it is in the file tree. + BuilderPathsIgnored []string + + // SearcherPathsIgnored lists certain paths that should not be searched + // by idsearcher, even if those paths have Files present. It uses the + // same format as BuilderPathsIgnored. + SearcherPathsIgnored []string +} + +// BuildIDsDocument2_2 creates an SPDX Document (version 2.2) and searches for +// short-form IDs in each file, filling in license fields as appropriate. It +// returns that document or error if any is encountered. Arguments: +// - packageName: name of package / directory +// - dirRoot: path to directory to be analyzed +// - namespacePrefix: URI representing a prefix for the +// namespace with which the SPDX Document will be associated +func BuildIDsDocument2_2(packageName string, dirRoot string, idconfig *Config2_2) (*spdx.Document2_2, error) { + // first, build the Document using builder + bconfig := &builder.Config2_2{ + NamespacePrefix: idconfig.NamespacePrefix, + CreatorType: "Tool", + Creator: "github.com/spdx/tools-golang/idsearcher", + PathsIgnored: idconfig.BuilderPathsIgnored, + } + doc, err := builder.Build2_2(packageName, dirRoot, bconfig) + if err != nil { + return nil, err + } + if doc == nil { + return nil, fmt.Errorf("builder returned nil Document") + } + if doc.Packages == nil { + return nil, fmt.Errorf("builder returned nil Packages map") + } + if len(doc.Packages) != 1 { + return nil, fmt.Errorf("builder returned %d Packages", len(doc.Packages)) + } + + // now, walk through each file and find its licenses (if any) + pkg := doc.Packages[spdx.ElementID("Package-"+packageName)] + if pkg == nil { + return nil, fmt.Errorf("builder returned nil Package") + } + if pkg.Files == nil { + return nil, fmt.Errorf("builder returned nil Files in Package") + } + licsForPackage := map[string]int{} + for _, f := range pkg.Files { + // start by initializing / clearing values + f.LicenseInfoInFile = []string{"NOASSERTION"} + f.LicenseConcluded = "NOASSERTION" + + // check whether the searcher should ignore this file + if utils.ShouldIgnore(f.FileName, idconfig.SearcherPathsIgnored) { + continue + } + + fPath := filepath.Join(dirRoot, f.FileName) + // FIXME this is not preferable -- ignoring error + ids, _ := searchFileIDs(fPath) + // FIXME for now, proceed onwards with whatever IDs we obtained. + // FIXME instead of ignoring the error, should probably either log it, + // FIXME and/or enable the caller to configure what should happen. + + // separate out for this file's licenses + licsForFile := map[string]int{} + licsParens := []string{} + for _, lid := range ids { + // get individual elements and add for file and package + licElements := getIndividualLicenses(lid) + for _, elt := range licElements { + licsForFile[elt] = 1 + licsForPackage[elt] = 1 + } + // parenthesize if needed and add to slice for joining + licsParens = append(licsParens, makeElement(lid)) + } + + // OK -- now we can fill in the file's details, or NOASSERTION if none + if len(licsForFile) > 0 { + f.LicenseInfoInFile = []string{} + for lic := range licsForFile { + f.LicenseInfoInFile = append(f.LicenseInfoInFile, lic) + } + sort.Strings(f.LicenseInfoInFile) + // avoid adding parens and joining for single-ID items + if len(licsParens) == 1 { + f.LicenseConcluded = ids[0] + } else { + f.LicenseConcluded = strings.Join(licsParens, " AND ") + } + } + } + + // and finally, we can fill in the package's details + if len(licsForPackage) == 0 { + pkg.PackageLicenseInfoFromFiles = []string{"NOASSERTION"} + } else { + pkg.PackageLicenseInfoFromFiles = []string{} + for lic := range licsForPackage { + pkg.PackageLicenseInfoFromFiles = append(pkg.PackageLicenseInfoFromFiles, lic) + } + sort.Strings(pkg.PackageLicenseInfoFromFiles) + } + + return doc, nil +} + +// ===== Utility functions (not version-specific) ===== func searchFileIDs(filePath string) ([]string, error) { idsMap := map[string]int{} ids := []string{} diff --git a/idsearcher/idsearcher_test.go b/idsearcher/idsearcher_test.go index c9c6285..d6e2bfa 100644 --- a/idsearcher/idsearcher_test.go +++ b/idsearcher/idsearcher_test.go @@ -8,15 +8,15 @@ import ( "github.com/spdx/tools-golang/spdx" ) -// ===== Searcher top-level function tests ===== +// ===== 2.1 Searcher top-level function tests ===== func TestSearcherCanFillInIDs(t *testing.T) { packageName := "project2" dirRoot := "../testdata/project2/" - config := &Config{ + config := &Config2_1{ NamespacePrefix: "https://github.com/swinslow/spdx-docs/spdx-go/testdata-", } - doc, err := BuildIDsDocument(packageName, dirRoot, config) + doc, err := BuildIDsDocument2_1(packageName, dirRoot, config) if err != nil { t.Fatalf("expected nil error, got %v", err) } @@ -180,7 +180,7 @@ func TestSearcherCanFillInIDs(t *testing.T) { func TestSearcherCanFillInIDsAndIgnorePaths(t *testing.T) { packageName := "project3" dirRoot := "../testdata/project3/" - config := &Config{ + config := &Config2_1{ NamespacePrefix: "https://github.com/swinslow/spdx-docs/spdx-go/testdata-", BuilderPathsIgnored: []string{ "**/ignoredir/", @@ -193,7 +193,7 @@ func TestSearcherCanFillInIDsAndIgnorePaths(t *testing.T) { }, } - doc, err := BuildIDsDocument(packageName, dirRoot, config) + doc, err := BuildIDsDocument2_1(packageName, dirRoot, config) if err != nil { t.Fatalf("expected nil error, got %v", err) } @@ -287,11 +287,11 @@ func TestSearcherCanFillInIDsAndIgnorePaths(t *testing.T) { func TestSearcherFailsWithInvalidPath(t *testing.T) { packageName := "project2" dirRoot := "./oops/invalid" - config := &Config{ + config := &Config2_1{ NamespacePrefix: "whatever", } - _, err := BuildIDsDocument(packageName, dirRoot, config) + _, err := BuildIDsDocument2_1(packageName, dirRoot, config) if err == nil { t.Fatalf("expected non-nil error, got nil") } |