1*9e94795aSAndroid Build Coastguard Worker// Copyright 2021 Google LLC 2*9e94795aSAndroid Build Coastguard Worker// 3*9e94795aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*9e94795aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*9e94795aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*9e94795aSAndroid Build Coastguard Worker// 7*9e94795aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*9e94795aSAndroid Build Coastguard Worker// 9*9e94795aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*9e94795aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*9e94795aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*9e94795aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*9e94795aSAndroid Build Coastguard Worker// limitations under the License. 14*9e94795aSAndroid Build Coastguard Worker 15*9e94795aSAndroid Build Coastguard Workerpackage compliance 16*9e94795aSAndroid Build Coastguard Worker 17*9e94795aSAndroid Build Coastguard Workerimport ( 18*9e94795aSAndroid Build Coastguard Worker "fmt" 19*9e94795aSAndroid Build Coastguard Worker "sort" 20*9e94795aSAndroid Build Coastguard Worker "strings" 21*9e94795aSAndroid Build Coastguard Worker) 22*9e94795aSAndroid Build Coastguard Worker 23*9e94795aSAndroid Build Coastguard Worker// Resolution describes an action to resolve one or more license conditions. 24*9e94795aSAndroid Build Coastguard Worker// 25*9e94795aSAndroid Build Coastguard Worker// `AttachesTo` identifies the target node that when distributed triggers the action. 26*9e94795aSAndroid Build Coastguard Worker// `ActsOn` identifies the target node that is the object of the action. 27*9e94795aSAndroid Build Coastguard Worker// `Resolves` identifies one or more license conditions that the action resolves. 28*9e94795aSAndroid Build Coastguard Worker// 29*9e94795aSAndroid Build Coastguard Worker// e.g. Suppose an MIT library is linked to a binary that also links to GPL code. 30*9e94795aSAndroid Build Coastguard Worker// 31*9e94795aSAndroid Build Coastguard Worker// A resolution would attach to the binary to share (act on) the MIT library to 32*9e94795aSAndroid Build Coastguard Worker// resolve the restricted condition originating from the GPL code. 33*9e94795aSAndroid Build Coastguard Workertype Resolution struct { 34*9e94795aSAndroid Build Coastguard Worker attachesTo, actsOn *TargetNode 35*9e94795aSAndroid Build Coastguard Worker cs LicenseConditionSet 36*9e94795aSAndroid Build Coastguard Worker} 37*9e94795aSAndroid Build Coastguard Worker 38*9e94795aSAndroid Build Coastguard Worker// AttachesTo returns the target node the resolution attaches to. 39*9e94795aSAndroid Build Coastguard Workerfunc (r Resolution) AttachesTo() *TargetNode { 40*9e94795aSAndroid Build Coastguard Worker return r.attachesTo 41*9e94795aSAndroid Build Coastguard Worker} 42*9e94795aSAndroid Build Coastguard Worker 43*9e94795aSAndroid Build Coastguard Worker// ActsOn returns the target node that must be acted on to resolve the condition. 44*9e94795aSAndroid Build Coastguard Worker// 45*9e94795aSAndroid Build Coastguard Worker// i.e. The node for which notice must be given or whose source must be shared etc. 46*9e94795aSAndroid Build Coastguard Workerfunc (r Resolution) ActsOn() *TargetNode { 47*9e94795aSAndroid Build Coastguard Worker return r.actsOn 48*9e94795aSAndroid Build Coastguard Worker} 49*9e94795aSAndroid Build Coastguard Worker 50*9e94795aSAndroid Build Coastguard Worker// Resolves returns the set of license condition the resolution satisfies. 51*9e94795aSAndroid Build Coastguard Workerfunc (r Resolution) Resolves() LicenseConditionSet { 52*9e94795aSAndroid Build Coastguard Worker return r.cs 53*9e94795aSAndroid Build Coastguard Worker} 54*9e94795aSAndroid Build Coastguard Worker 55*9e94795aSAndroid Build Coastguard Worker// asString returns a string representation of the resolution. 56*9e94795aSAndroid Build Coastguard Workerfunc (r Resolution) asString() string { 57*9e94795aSAndroid Build Coastguard Worker var sb strings.Builder 58*9e94795aSAndroid Build Coastguard Worker names := r.cs.Names() 59*9e94795aSAndroid Build Coastguard Worker sort.Strings(names) 60*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(&sb, "%s -> %s{%s}", r.attachesTo.name, r.actsOn.name, strings.Join(names, ", ")) 61*9e94795aSAndroid Build Coastguard Worker return sb.String() 62*9e94795aSAndroid Build Coastguard Worker} 63*9e94795aSAndroid Build Coastguard Worker 64*9e94795aSAndroid Build Coastguard Worker// ResolutionList represents a partial order of Resolutions ordered by 65*9e94795aSAndroid Build Coastguard Worker// AttachesTo() and ActsOn() leaving `Resolves()` unordered. 66*9e94795aSAndroid Build Coastguard Workertype ResolutionList []Resolution 67*9e94795aSAndroid Build Coastguard Worker 68*9e94795aSAndroid Build Coastguard Worker// Len returns the count of elements in the list. 69*9e94795aSAndroid Build Coastguard Workerfunc (l ResolutionList) Len() int { return len(l) } 70*9e94795aSAndroid Build Coastguard Worker 71*9e94795aSAndroid Build Coastguard Worker// Swap rearranges 2 elements so that each occupies the other's former position. 72*9e94795aSAndroid Build Coastguard Workerfunc (l ResolutionList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } 73*9e94795aSAndroid Build Coastguard Worker 74*9e94795aSAndroid Build Coastguard Worker// Less returns true when the `i`th element is lexicographically less than tht `j`th. 75*9e94795aSAndroid Build Coastguard Workerfunc (l ResolutionList) Less(i, j int) bool { 76*9e94795aSAndroid Build Coastguard Worker if l[i].attachesTo.name == l[j].attachesTo.name { 77*9e94795aSAndroid Build Coastguard Worker return l[i].actsOn.name < l[j].actsOn.name 78*9e94795aSAndroid Build Coastguard Worker } 79*9e94795aSAndroid Build Coastguard Worker return l[i].attachesTo.name < l[j].attachesTo.name 80*9e94795aSAndroid Build Coastguard Worker} 81*9e94795aSAndroid Build Coastguard Worker 82*9e94795aSAndroid Build Coastguard Worker// String returns a string representation of the list. 83*9e94795aSAndroid Build Coastguard Workerfunc (rl ResolutionList) String() string { 84*9e94795aSAndroid Build Coastguard Worker var sb strings.Builder 85*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(&sb, "[") 86*9e94795aSAndroid Build Coastguard Worker sep := "" 87*9e94795aSAndroid Build Coastguard Worker for _, r := range rl { 88*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(&sb, "%s%s", sep, r.asString()) 89*9e94795aSAndroid Build Coastguard Worker sep = ", " 90*9e94795aSAndroid Build Coastguard Worker } 91*9e94795aSAndroid Build Coastguard Worker fmt.Fprintf(&sb, "]") 92*9e94795aSAndroid Build Coastguard Worker return sb.String() 93*9e94795aSAndroid Build Coastguard Worker} 94*9e94795aSAndroid Build Coastguard Worker 95*9e94795aSAndroid Build Coastguard Worker// AllConditions returns the union of all license conditions resolved by any 96*9e94795aSAndroid Build Coastguard Worker// element of the list. 97*9e94795aSAndroid Build Coastguard Workerfunc (rl ResolutionList) AllConditions() LicenseConditionSet { 98*9e94795aSAndroid Build Coastguard Worker result := NewLicenseConditionSet() 99*9e94795aSAndroid Build Coastguard Worker for _, r := range rl { 100*9e94795aSAndroid Build Coastguard Worker result = result.Union(r.cs) 101*9e94795aSAndroid Build Coastguard Worker } 102*9e94795aSAndroid Build Coastguard Worker return result 103*9e94795aSAndroid Build Coastguard Worker} 104*9e94795aSAndroid Build Coastguard Worker 105*9e94795aSAndroid Build Coastguard Worker// ByName returns the sub-list of resolutions resolving conditions matching 106*9e94795aSAndroid Build Coastguard Worker// `names`. 107*9e94795aSAndroid Build Coastguard Workerfunc (rl ResolutionList) Matching(conditions LicenseConditionSet) ResolutionList { 108*9e94795aSAndroid Build Coastguard Worker result := make(ResolutionList, 0, rl.CountMatching(conditions)) 109*9e94795aSAndroid Build Coastguard Worker for _, r := range rl { 110*9e94795aSAndroid Build Coastguard Worker if r.Resolves().MatchesAnySet(conditions) { 111*9e94795aSAndroid Build Coastguard Worker result = append(result, Resolution{r.attachesTo, r.actsOn, r.cs.MatchingAnySet(conditions)}) 112*9e94795aSAndroid Build Coastguard Worker } 113*9e94795aSAndroid Build Coastguard Worker } 114*9e94795aSAndroid Build Coastguard Worker return result 115*9e94795aSAndroid Build Coastguard Worker} 116*9e94795aSAndroid Build Coastguard Worker 117*9e94795aSAndroid Build Coastguard Worker// CountMatching returns the number of resolutions resolving conditions matching 118*9e94795aSAndroid Build Coastguard Worker// `conditions`. 119*9e94795aSAndroid Build Coastguard Workerfunc (rl ResolutionList) CountMatching(conditions LicenseConditionSet) int { 120*9e94795aSAndroid Build Coastguard Worker c := 0 121*9e94795aSAndroid Build Coastguard Worker for _, r := range rl { 122*9e94795aSAndroid Build Coastguard Worker if r.Resolves().MatchesAnySet(conditions) { 123*9e94795aSAndroid Build Coastguard Worker c++ 124*9e94795aSAndroid Build Coastguard Worker } 125*9e94795aSAndroid Build Coastguard Worker } 126*9e94795aSAndroid Build Coastguard Worker return c 127*9e94795aSAndroid Build Coastguard Worker} 128*9e94795aSAndroid Build Coastguard Worker 129*9e94795aSAndroid Build Coastguard Worker// ByActsOn returns the sub-list of resolutions matching `actsOn`. 130*9e94795aSAndroid Build Coastguard Workerfunc (rl ResolutionList) ByActsOn(actsOn *TargetNode) ResolutionList { 131*9e94795aSAndroid Build Coastguard Worker result := make(ResolutionList, 0, rl.CountByActsOn(actsOn)) 132*9e94795aSAndroid Build Coastguard Worker for _, r := range rl { 133*9e94795aSAndroid Build Coastguard Worker if r.actsOn == actsOn { 134*9e94795aSAndroid Build Coastguard Worker result = append(result, r) 135*9e94795aSAndroid Build Coastguard Worker } 136*9e94795aSAndroid Build Coastguard Worker } 137*9e94795aSAndroid Build Coastguard Worker return result 138*9e94795aSAndroid Build Coastguard Worker} 139*9e94795aSAndroid Build Coastguard Worker 140*9e94795aSAndroid Build Coastguard Worker// CountByActsOn returns the number of resolutions matching `actsOn`. 141*9e94795aSAndroid Build Coastguard Workerfunc (rl ResolutionList) CountByActsOn(actsOn *TargetNode) int { 142*9e94795aSAndroid Build Coastguard Worker c := 0 143*9e94795aSAndroid Build Coastguard Worker for _, r := range rl { 144*9e94795aSAndroid Build Coastguard Worker if r.actsOn == actsOn { 145*9e94795aSAndroid Build Coastguard Worker c++ 146*9e94795aSAndroid Build Coastguard Worker } 147*9e94795aSAndroid Build Coastguard Worker } 148*9e94795aSAndroid Build Coastguard Worker return c 149*9e94795aSAndroid Build Coastguard Worker} 150