compliance package structures for license metadata
package to read, consume, and analyze license metadata and dependency
graph.
Bug: 68860345
Bug: 151177513
Bug: 151953481
Change-Id: I3ebf44e4d5195b9851fd076161049bf82ed76dd2
diff --git a/tools/compliance/resolution.go b/tools/compliance/resolution.go
new file mode 100644
index 0000000..0865ecd
--- /dev/null
+++ b/tools/compliance/resolution.go
@@ -0,0 +1,208 @@
+// Copyright 2021 Google LLC
+//
+// Licensed 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 compliance
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+)
+
+// Resolution describes an action to resolve one or more license conditions.
+//
+// `AttachesTo` identifies the target node that when distributed triggers the action.
+// `ActsOn` identifies the target node that is the object of the action.
+// `Resolves` identifies one or more license conditions that the action resolves.
+//
+// e.g. Suppose an MIT library is linked to a binary that also links to GPL code.
+//
+// A resolution would attach to the binary to share (act on) the MIT library to
+// resolve the restricted condition originating from the GPL code.
+type Resolution struct {
+ attachesTo, actsOn *TargetNode
+ cs *LicenseConditionSet
+}
+
+// AttachesTo returns the target node the resolution attaches to.
+func (r Resolution) AttachesTo() *TargetNode {
+ return r.attachesTo
+}
+
+// ActsOn returns the target node that must be acted on to resolve the condition.
+//
+// i.e. The node for which notice must be given or whose source must be shared etc.
+func (r Resolution) ActsOn() *TargetNode {
+ return r.actsOn
+}
+
+// Resolves returns the set of license condition the resolution satisfies.
+func (r Resolution) Resolves() *LicenseConditionSet {
+ return r.cs.Copy()
+}
+
+// asString returns a string representation of the resolution.
+func (r Resolution) asString() string {
+ var sb strings.Builder
+ cl := r.cs.AsList()
+ sort.Sort(cl)
+ fmt.Fprintf(&sb, "%s -> %s -> %s", r.attachesTo.name, r.actsOn.name, cl.String())
+ return sb.String()
+}
+
+// ResolutionList represents a partial order of Resolutions ordered by
+// AttachesTo() and ActsOn() leaving `Resolves()` unordered.
+type ResolutionList []Resolution
+
+// Len returns the count of elements in the list.
+func (l ResolutionList) Len() int { return len(l) }
+
+// Swap rearranges 2 elements so that each occupies the other's former position.
+func (l ResolutionList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
+
+// Less returns true when the `i`th element is lexicographically less than tht `j`th.
+func (l ResolutionList) Less(i, j int) bool {
+ if l[i].attachesTo.name == l[j].attachesTo.name {
+ return l[i].actsOn.name < l[j].actsOn.name
+ }
+ return l[i].attachesTo.name < l[j].attachesTo.name
+}
+
+// String returns a string representation of the list.
+func (rl ResolutionList) String() string {
+ var sb strings.Builder
+ fmt.Fprintf(&sb, "[")
+ sep := ""
+ for _, r := range rl {
+ fmt.Fprintf(&sb, "%s%s", sep, r.asString())
+ sep = ", "
+ }
+ fmt.Fprintf(&sb, "]")
+ return sb.String()
+}
+
+// AllConditions returns the union of all license conditions resolved by any
+// element of the list.
+func (rl ResolutionList) AllConditions() *LicenseConditionSet {
+ result := newLicenseConditionSet()
+ for _, r := range rl {
+ result.AddSet(r.cs)
+ }
+ return result
+}
+
+// ByName returns the sub-list of resolutions resolving conditions matching
+// `names`.
+func (rl ResolutionList) ByName(names ConditionNames) ResolutionList {
+ result := make(ResolutionList, 0, rl.CountByName(names))
+ for _, r := range rl {
+ if r.Resolves().HasAnyByName(names) {
+ result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.ByName(names)})
+ }
+ }
+ return result
+}
+
+// CountByName returns the number of resolutions resolving conditions matching
+// `names`.
+func (rl ResolutionList) CountByName(names ConditionNames) int {
+ c := 0
+ for _, r := range rl {
+ if r.Resolves().HasAnyByName(names) {
+ c++
+ }
+ }
+ return c
+}
+
+// CountConditionsByName returns a count of distinct resolution/conditions
+// pairs matching `names`.
+//
+// A single resolution might resolve multiple conditions matching `names`.
+func (rl ResolutionList) CountConditionsByName(names ConditionNames) int {
+ c := 0
+ for _, r := range rl {
+ c += r.Resolves().CountByName(names)
+ }
+ return c
+}
+
+// ByAttachesTo returns the sub-list of resolutions attached to `attachesTo`.
+func (rl ResolutionList) ByAttachesTo(attachesTo *TargetNode) ResolutionList {
+ result := make(ResolutionList, 0, rl.CountByActsOn(attachesTo))
+ for _, r := range rl {
+ if r.attachesTo == attachesTo {
+ result = append(result, r)
+ }
+ }
+ return result
+}
+
+// CountByAttachesTo returns the number of resolutions attached to
+// `attachesTo`.
+func (rl ResolutionList) CountByAttachesTo(attachesTo *TargetNode) int {
+ c := 0
+ for _, r := range rl {
+ if r.attachesTo == attachesTo {
+ c++
+ }
+ }
+ return c
+}
+
+// ByActsOn returns the sub-list of resolutions matching `actsOn`.
+func (rl ResolutionList) ByActsOn(actsOn *TargetNode) ResolutionList {
+ result := make(ResolutionList, 0, rl.CountByActsOn(actsOn))
+ for _, r := range rl {
+ if r.actsOn == actsOn {
+ result = append(result, r)
+ }
+ }
+ return result
+}
+
+// CountByActsOn returns the number of resolutions matching `actsOn`.
+func (rl ResolutionList) CountByActsOn(actsOn *TargetNode) int {
+ c := 0
+ for _, r := range rl {
+ if r.actsOn == actsOn {
+ c++
+ }
+ }
+ return c
+}
+
+// ByOrigin returns the sub-list of resolutions resolving license conditions
+// originating at `origin`.
+func (rl ResolutionList) ByOrigin(origin *TargetNode) ResolutionList {
+ result := make(ResolutionList, 0, rl.CountByOrigin(origin))
+ for _, r := range rl {
+ if r.Resolves().HasAnyByOrigin(origin) {
+ result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.ByOrigin(origin)})
+ }
+ }
+ return result
+}
+
+// CountByOrigin returns the number of resolutions resolving license conditions
+// originating at `origin`.
+func (rl ResolutionList) CountByOrigin(origin *TargetNode) int {
+ c := 0
+ for _, r := range rl {
+ if r.Resolves().HasAnyByOrigin(origin) {
+ c++
+ }
+ }
+ return c
+}