Skip to content

Commit

Permalink
Merge pull request #52 from github/ajhenry/extract-licenses
Browse files Browse the repository at this point in the history
Add method for extracting licenses from expression
  • Loading branch information
ajhenry authored Sep 19, 2023
2 parents 304897a + 0f05021 commit e0a077a
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 0 deletions.
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,30 @@ assert.True(valid)
assert.NotContains(invalidLicenses, "MIT AND APACHE-2.0")
```

### ExtractLicenses

```go
func ExtractLicenses(expression string) ([]string, error)
```

Function `ExtractLicenses` is used to extract licenses from the given expression without duplicates.

**parameter: expression**

`expression` is an SPDX expression string.

**returns**

Function `ExtractLicenses` has 2 return values. First is `[]string` which contains all of the SPDX licenses without duplicates.

The second return value is an `error` which is not `nil` if the given expression is not a valid SPDX expression.

#### Example

```go
licenses, err := ExtractLicenses("(MIT AND APACHE-2.0) OR (APACHE-2.0)")
assert.Equal(licenses, []string{"MIT", "Apache-2.0"})
```

## Background

Expand Down
21 changes: 21 additions & 0 deletions spdxexp/extracts.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package spdxexp

// ExtractLicenses extracts licenses from the given expression without duplicates.
// Returns an array of licenses or error if error occurs during processing.
func ExtractLicenses(expression string) ([]string, error) {
node, err := parse(expression)
if err != nil {
return nil, err
}

expanded := node.expand(true)
licenses := make([]string, 0)
allLicenses := flatten(expanded)
for _, licenseNode := range allLicenses {
licenses = append(licenses, *licenseNode.reconstructedLicenseString())
}

licenses = removeDuplicateStrings(licenses)

return licenses, nil
}
34 changes: 34 additions & 0 deletions spdxexp/extracts_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package spdxexp

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestExtractLicenses(t *testing.T) {
tests := []struct {
name string
inputExpression string
extractedLicenses []string
}{
{"Single license", "MIT", []string{"MIT"}},
{"AND'ed licenses", "MIT AND Apache-2.0", []string{"MIT", "Apache-2.0"}},
{"AND'ed & OR'ed licenses", "(MIT AND Apache-2.0) OR GPL-3.0", []string{"GPL-3.0", "MIT", "Apache-2.0"}},
{"ONLY modifiers", "LGPL-2.1-only OR MIT OR BSD-3-Clause", []string{"MIT", "BSD-3-Clause", "LGPL-2.1-only"}},
{"WITH modifiers", "GPL-2.0-or-later WITH Bison-exception-2.2", []string{"GPL-2.0-or-later+ WITH Bison-exception-2.2"}},
{"Invalid SPDX expression", "MIT OR INVALID", nil},
}

for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
licenses, err := ExtractLicenses(test.inputExpression)
assert.ElementsMatch(t, test.extractedLicenses, licenses)
if test.extractedLicenses == nil {
assert.Error(t, err)
} else {
assert.NoError(t, err)
}
})
}
}
24 changes: 24 additions & 0 deletions spdxexp/helpers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package spdxexp

// flatten will take an array of nested array and return
// all nested elements in an array. e.g. [[1,2,[3]],4] -> [1,2,3,4]
func flatten[T any](lists [][]T) []T {
var res []T
for _, list := range lists {
res = append(res, list...)
}
return res
}

// removeDuplicateStrings will remove all duplicates from a slice
func removeDuplicateStrings(sliceList []string) []string {
allKeys := make(map[string]bool)
list := []string{}
for _, item := range sliceList {
if _, value := allKeys[item]; !value {
allKeys[item] = true
list = append(list, item)
}
}
return list
}

0 comments on commit e0a077a

Please sign in to comment.