xref: /aosp_15_r20/build/make/tools/compliance/resolutionset.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	"strings"
20*9e94795aSAndroid Build Coastguard Worker)
21*9e94795aSAndroid Build Coastguard Worker
22*9e94795aSAndroid Build Coastguard Worker// ResolutionSet describes an immutable set of targets and the license
23*9e94795aSAndroid Build Coastguard Worker// conditions each target must satisfy or "resolve" in a specific context.
24*9e94795aSAndroid Build Coastguard Worker//
25*9e94795aSAndroid Build Coastguard Worker// Ultimately, the purpose of recording the license metadata and building a
26*9e94795aSAndroid Build Coastguard Worker// license graph is to identify, describe, and verify the necessary actions or
27*9e94795aSAndroid Build Coastguard Worker// operations for compliance policy.
28*9e94795aSAndroid Build Coastguard Worker//
29*9e94795aSAndroid Build Coastguard Worker// i.e. What is the source-sharing policy? Has it been met? Meet it.
30*9e94795aSAndroid Build Coastguard Worker//
31*9e94795aSAndroid Build Coastguard Worker// i.e. Are there incompatible policy requirements? Such as a source-sharing
32*9e94795aSAndroid Build Coastguard Worker// policy applied to code that policy also says may not be shared? If so, stop
33*9e94795aSAndroid Build Coastguard Worker// and remove the dependencies that create the situation.
34*9e94795aSAndroid Build Coastguard Worker//
35*9e94795aSAndroid Build Coastguard Worker// The ResolutionSet is the base unit for mapping license conditions to the
36*9e94795aSAndroid Build Coastguard Worker// targets triggering some necessary action per policy. Different ResolutionSet
37*9e94795aSAndroid Build Coastguard Worker// values may be calculated for different contexts.
38*9e94795aSAndroid Build Coastguard Worker//
39*9e94795aSAndroid Build Coastguard Worker// e.g. Suppose an unencumbered binary links in a notice .a library.
40*9e94795aSAndroid Build Coastguard Worker//
41*9e94795aSAndroid Build Coastguard Worker// An "unencumbered" condition would originate from the binary, and a "notice"
42*9e94795aSAndroid Build Coastguard Worker// condition would originate from the .a library. A ResolutionSet for the
43*9e94795aSAndroid Build Coastguard Worker// context of the Notice policy might attach both conditions to the binary to
44*9e94795aSAndroid Build Coastguard Worker// act on the origin of each condition. By attaching the notice condition to
45*9e94795aSAndroid Build Coastguard Worker// the binary, the ResolutionSet stipulates the policy that the release of the
46*9e94795aSAndroid Build Coastguard Worker// unencumbered binary must provide suitable notice for the .a library.
47*9e94795aSAndroid Build Coastguard Worker//
48*9e94795aSAndroid Build Coastguard Worker// The resulting ResolutionSet could be used for building a notice file, for
49*9e94795aSAndroid Build Coastguard Worker// validating that a suitable notice has been built into the distribution, or
50*9e94795aSAndroid Build Coastguard Worker// for reporting what notices need to be given.
51*9e94795aSAndroid Build Coastguard Worker//
52*9e94795aSAndroid Build Coastguard Worker// The action is defined by the context. In the above example, the action is
53*9e94795aSAndroid Build Coastguard Worker// providing notice for the module acted on. In another context, the action
54*9e94795aSAndroid Build Coastguard Worker// might be sharing the source-code or preserving the privacy of the module
55*9e94795aSAndroid Build Coastguard Worker// acted on.
56*9e94795aSAndroid Build Coastguard Workertype ResolutionSet map[*TargetNode]ActionSet
57*9e94795aSAndroid Build Coastguard Worker
58*9e94795aSAndroid Build Coastguard Worker// AttachesTo identifies the list of targets triggering action to resolve
59*9e94795aSAndroid Build Coastguard Worker// conditions. (unordered)
60*9e94795aSAndroid Build Coastguard Workerfunc (rs ResolutionSet) AttachesTo() TargetNodeList {
61*9e94795aSAndroid Build Coastguard Worker	result := make(TargetNodeList, 0, len(rs))
62*9e94795aSAndroid Build Coastguard Worker	for attachesTo := range rs {
63*9e94795aSAndroid Build Coastguard Worker		result = append(result, attachesTo)
64*9e94795aSAndroid Build Coastguard Worker	}
65*9e94795aSAndroid Build Coastguard Worker	return result
66*9e94795aSAndroid Build Coastguard Worker}
67*9e94795aSAndroid Build Coastguard Worker
68*9e94795aSAndroid Build Coastguard Worker// AttachesToTarget returns true if the set contains conditions that
69*9e94795aSAndroid Build Coastguard Worker// are `attachedTo`.
70*9e94795aSAndroid Build Coastguard Workerfunc (rs ResolutionSet) AttachesToTarget(target *TargetNode) bool {
71*9e94795aSAndroid Build Coastguard Worker	_, isPresent := rs[target]
72*9e94795aSAndroid Build Coastguard Worker	return isPresent
73*9e94795aSAndroid Build Coastguard Worker}
74*9e94795aSAndroid Build Coastguard Worker
75*9e94795aSAndroid Build Coastguard Worker// IsPureAggregate returns true if `target`, which must be in
76*9e94795aSAndroid Build Coastguard Worker// `AttachesTo()` resolves to a pure aggregate in the resolution.
77*9e94795aSAndroid Build Coastguard Workerfunc (rs ResolutionSet) IsPureAggregate(target *TargetNode) bool {
78*9e94795aSAndroid Build Coastguard Worker	_, isPresent := rs[target]
79*9e94795aSAndroid Build Coastguard Worker	if !isPresent {
80*9e94795aSAndroid Build Coastguard Worker		panic(fmt.Errorf("ResolutionSet.IsPureAggregate(%s): not attached to %s", target.Name(), target.Name()))
81*9e94795aSAndroid Build Coastguard Worker	}
82*9e94795aSAndroid Build Coastguard Worker	return target.pure
83*9e94795aSAndroid Build Coastguard Worker}
84*9e94795aSAndroid Build Coastguard Worker
85*9e94795aSAndroid Build Coastguard Worker// Resolutions returns the list of resolutions that `attachedTo`
86*9e94795aSAndroid Build Coastguard Worker// target must resolve. Returns empty list if no conditions apply.
87*9e94795aSAndroid Build Coastguard Workerfunc (rs ResolutionSet) Resolutions(attachesTo *TargetNode) ResolutionList {
88*9e94795aSAndroid Build Coastguard Worker	as, ok := rs[attachesTo]
89*9e94795aSAndroid Build Coastguard Worker	if !ok {
90*9e94795aSAndroid Build Coastguard Worker		return nil
91*9e94795aSAndroid Build Coastguard Worker	}
92*9e94795aSAndroid Build Coastguard Worker	result := make(ResolutionList, 0, len(as))
93*9e94795aSAndroid Build Coastguard Worker	for actsOn, cs := range as {
94*9e94795aSAndroid Build Coastguard Worker		result = append(result, Resolution{attachesTo, actsOn, cs})
95*9e94795aSAndroid Build Coastguard Worker	}
96*9e94795aSAndroid Build Coastguard Worker	return result
97*9e94795aSAndroid Build Coastguard Worker}
98*9e94795aSAndroid Build Coastguard Worker
99*9e94795aSAndroid Build Coastguard Worker// AllActions returns the set of actions required to resolve the set omitting
100*9e94795aSAndroid Build Coastguard Worker// the attachment.
101*9e94795aSAndroid Build Coastguard Workerfunc (rs ResolutionSet) AllActions() ActionSet {
102*9e94795aSAndroid Build Coastguard Worker	result := make(ActionSet)
103*9e94795aSAndroid Build Coastguard Worker	for _, as := range rs {
104*9e94795aSAndroid Build Coastguard Worker		for actsOn, cs := range as {
105*9e94795aSAndroid Build Coastguard Worker			if _, ok := result[actsOn]; ok {
106*9e94795aSAndroid Build Coastguard Worker				result[actsOn] = cs.Union(result[actsOn])
107*9e94795aSAndroid Build Coastguard Worker			} else {
108*9e94795aSAndroid Build Coastguard Worker				result[actsOn] = cs
109*9e94795aSAndroid Build Coastguard Worker			}
110*9e94795aSAndroid Build Coastguard Worker		}
111*9e94795aSAndroid Build Coastguard Worker	}
112*9e94795aSAndroid Build Coastguard Worker	return result
113*9e94795aSAndroid Build Coastguard Worker}
114*9e94795aSAndroid Build Coastguard Worker
115*9e94795aSAndroid Build Coastguard Worker// String returns a human-readable string representation of the set.
116*9e94795aSAndroid Build Coastguard Workerfunc (rs ResolutionSet) String() string {
117*9e94795aSAndroid Build Coastguard Worker	var sb strings.Builder
118*9e94795aSAndroid Build Coastguard Worker	fmt.Fprintf(&sb, "{")
119*9e94795aSAndroid Build Coastguard Worker	sep := ""
120*9e94795aSAndroid Build Coastguard Worker	for attachesTo, as := range rs {
121*9e94795aSAndroid Build Coastguard Worker		fmt.Fprintf(&sb, "%s%s -> %s", sep, attachesTo.Name(), as.String())
122*9e94795aSAndroid Build Coastguard Worker		sep = ", "
123*9e94795aSAndroid Build Coastguard Worker	}
124*9e94795aSAndroid Build Coastguard Worker	fmt.Fprintf(&sb, "}")
125*9e94795aSAndroid Build Coastguard Worker	return sb.String()
126*9e94795aSAndroid Build Coastguard Worker}
127*9e94795aSAndroid Build Coastguard Worker
128*9e94795aSAndroid Build Coastguard Worker// ActionSet identifies a set of targets to act on and the license conditions
129*9e94795aSAndroid Build Coastguard Worker// the action will resolve.
130*9e94795aSAndroid Build Coastguard Workertype ActionSet map[*TargetNode]LicenseConditionSet
131*9e94795aSAndroid Build Coastguard Worker
132*9e94795aSAndroid Build Coastguard Worker// String returns a human-readable string representation of the set.
133*9e94795aSAndroid Build Coastguard Workerfunc (as ActionSet) String() string {
134*9e94795aSAndroid Build Coastguard Worker	var sb strings.Builder
135*9e94795aSAndroid Build Coastguard Worker	fmt.Fprintf(&sb, "{")
136*9e94795aSAndroid Build Coastguard Worker	sep := ""
137*9e94795aSAndroid Build Coastguard Worker	for actsOn, cs := range as {
138*9e94795aSAndroid Build Coastguard Worker		fmt.Fprintf(&sb, "%s%s%s", sep, actsOn.Name(), cs.String())
139*9e94795aSAndroid Build Coastguard Worker		sep = ", "
140*9e94795aSAndroid Build Coastguard Worker	}
141*9e94795aSAndroid Build Coastguard Worker	fmt.Fprintf(&sb, "}")
142*9e94795aSAndroid Build Coastguard Worker	return sb.String()
143*9e94795aSAndroid Build Coastguard Worker}
144