xref: /aosp_15_r20/build/make/tools/compliance/resolution.go (revision 9e94795a3d4ef5c1d47486f9a02bb378756cea8a)
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