blob: cd5fd5908bd9f95430af5edfcaf686f3ead74a67 [file] [log] [blame]
Bob Badoura99ac622021-10-25 16:21:00 -07001// Copyright 2021 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package compliance
16
17import (
18 "fmt"
19 "sort"
20 "strings"
21 "sync"
22)
23
24// LicenseGraph describes the immutable license metadata for a set of root
25// targets and the transitive closure of their dependencies.
26//
27// Alternatively, a graph is a set of edges. In this case directed, annotated
28// edges from targets to dependencies.
29//
30// A LicenseGraph provides the frame of reference for all of the other types
31// defined here. It is possible to have multiple graphs, and to have targets,
32// edges, and resolutions from multiple graphs. But it is an error to try to
33// mix items from different graphs in the same operation.
34// May panic if attempted.
35//
36// The compliance package assumes specific private implementations of each of
37// these interfaces. May panic if attempts are made to combine different
38// implementations of some interfaces with expected implementations of other
39// interfaces here.
40type LicenseGraph struct {
41 // rootFiles identifies the original set of files to read. (immutable)
42 //
43 // Defines the starting "top" for top-down walks.
44 //
45 // Alternatively, an instance of licenseGraphImp conceptually defines a scope within
46 // the universe of build graphs as a sub-graph rooted at rootFiles where all edges
47 // and targets for the instance are defined relative to and within that scope. For
48 // most analyses, the correct scope is to root the graph at all of the distributed
49 // artifacts.
50 rootFiles []string
51
52 // edges lists the directed edges in the graph from target to dependency. (guarded by mu)
53 //
54 // Alternatively, the graph is the set of `edges`.
Bob Badour103eb0f2022-01-10 13:50:57 -080055 edges TargetEdgeList
Bob Badoura99ac622021-10-25 16:21:00 -070056
Bob Badour103eb0f2022-01-10 13:50:57 -080057 // targets identifies, indexes, and describes the entire set of target node files.
Bob Badoura99ac622021-10-25 16:21:00 -070058 /// (guarded by mu)
59 targets map[string]*TargetNode
60
Bob Badour5c12c662022-10-29 22:45:12 -070061 // onceBottomUp makes sure the bottom-up resolve walk only happens one time.
62 onceBottomUp sync.Once
Bob Badoura99ac622021-10-25 16:21:00 -070063
Bob Badour5c12c662022-10-29 22:45:12 -070064 // onceTopDown makes sure the top-down resolve walk only happens one time.
65 onceTopDown sync.Once
Bob Badoura99ac622021-10-25 16:21:00 -070066
67 // shippedNodes caches the results of a full walk of nodes identifying targets
68 // distributed either directly or as derivative works. (creation guarded by mu)
69 shippedNodes *TargetNodeSet
70
71 // mu guards against concurrent update.
72 mu sync.Mutex
73}
74
Bob Badoura99ac622021-10-25 16:21:00 -070075// Edges returns the list of edges in the graph. (unordered)
76func (lg *LicenseGraph) Edges() TargetEdgeList {
77 edges := make(TargetEdgeList, 0, len(lg.edges))
Bob Badour103eb0f2022-01-10 13:50:57 -080078 edges = append(edges, lg.edges...)
Bob Badoura99ac622021-10-25 16:21:00 -070079 return edges
80}
81
82// Targets returns the list of target nodes in the graph. (unordered)
83func (lg *LicenseGraph) Targets() TargetNodeList {
84 targets := make(TargetNodeList, 0, len(lg.targets))
Bob Badour103eb0f2022-01-10 13:50:57 -080085 for _, target := range lg.targets {
86 targets = append(targets, target)
Bob Badoura99ac622021-10-25 16:21:00 -070087 }
88 return targets
89}
90
91// compliance-only LicenseGraph methods
92
93// newLicenseGraph constructs a new, empty instance of LicenseGraph.
94func newLicenseGraph() *LicenseGraph {
95 return &LicenseGraph{
96 rootFiles: []string{},
Bob Badoura99ac622021-10-25 16:21:00 -070097 targets: make(map[string]*TargetNode),
98 }
99}
100
Bob Badoura99ac622021-10-25 16:21:00 -0700101// TargetEdge describes a directed, annotated edge from a target to a
102// dependency. (immutable)
103//
104// A LicenseGraph, above, is a set of TargetEdges.
105//
106// i.e. `Target` depends on `Dependency` in the manner described by
107// `Annotations`.
108type TargetEdge struct {
Bob Badour103eb0f2022-01-10 13:50:57 -0800109 // target and dependency identify the nodes connected by the edge.
110 target, dependency *TargetNode
Bob Badoura99ac622021-10-25 16:21:00 -0700111
Bob Badour103eb0f2022-01-10 13:50:57 -0800112 // annotations identifies the set of compliance-relevant annotations describing the edge.
113 annotations TargetEdgeAnnotations
Bob Badoura99ac622021-10-25 16:21:00 -0700114}
115
116// Target identifies the target that depends on the dependency.
117//
118// Target needs Dependency to build.
Bob Badour103eb0f2022-01-10 13:50:57 -0800119func (e *TargetEdge) Target() *TargetNode {
120 return e.target
Bob Badoura99ac622021-10-25 16:21:00 -0700121}
122
123// Dependency identifies the target depended on by the target.
124//
125// Dependency builds without Target, but Target needs Dependency to build.
Bob Badour103eb0f2022-01-10 13:50:57 -0800126func (e *TargetEdge) Dependency() *TargetNode {
127 return e.dependency
Bob Badoura99ac622021-10-25 16:21:00 -0700128}
129
130// Annotations describes the type of edge by the set of annotations attached to
131// it.
132//
133// Only annotations prescribed by policy have any meaning for licensing, and
134// the meaning for licensing is likewise prescribed by policy. Other annotations
135// are preserved and ignored by policy.
Bob Badour103eb0f2022-01-10 13:50:57 -0800136func (e *TargetEdge) Annotations() TargetEdgeAnnotations {
137 return e.annotations
138}
139
140// String returns a human-readable string representation of the edge.
141func (e *TargetEdge) String() string {
142 return fmt.Sprintf("%s -[%s]> %s", e.target.name, strings.Join(e.annotations.AsList(), ", "), e.dependency.name)
Bob Badoura99ac622021-10-25 16:21:00 -0700143}
144
145// TargetEdgeList orders lists of edges by target then dependency then annotations.
Bob Badour103eb0f2022-01-10 13:50:57 -0800146type TargetEdgeList []*TargetEdge
Bob Badoura99ac622021-10-25 16:21:00 -0700147
148// Len returns the count of the elmements in the list.
Colin Cross35f79c32022-01-27 15:18:52 -0800149func (l TargetEdgeList) Len() int { return len(l) }
Bob Badoura99ac622021-10-25 16:21:00 -0700150
151// Swap rearranges 2 elements so that each occupies the other's former position.
152func (l TargetEdgeList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
153
154// Less returns true when the `i`th element is lexicographically less than the `j`th.
155func (l TargetEdgeList) Less(i, j int) bool {
Bob Badour103eb0f2022-01-10 13:50:57 -0800156 namei := l[i].target.name
157 namej := l[j].target.name
158 if namei == namej {
159 namei = l[i].dependency.name
160 namej = l[j].dependency.name
Bob Badoura99ac622021-10-25 16:21:00 -0700161 }
Bob Badour103eb0f2022-01-10 13:50:57 -0800162 if namei == namej {
163 return l[i].annotations.Compare(l[j].annotations) < 0
164 }
165 return namei < namej
166}
167
168// TargetEdgePathSegment describes a single arc in a TargetPath associating the
169// edge with a context `ctx` defined by whatever process is creating the path.
170type TargetEdgePathSegment struct {
171 edge *TargetEdge
Colin Cross35f79c32022-01-27 15:18:52 -0800172 ctx interface{}
Bob Badour103eb0f2022-01-10 13:50:57 -0800173}
174
175// Target identifies the target that depends on the dependency.
176//
177// Target needs Dependency to build.
178func (s TargetEdgePathSegment) Target() *TargetNode {
179 return s.edge.target
180}
181
182// Dependency identifies the target depended on by the target.
183//
184// Dependency builds without Target, but Target needs Dependency to build.
185func (s TargetEdgePathSegment) Dependency() *TargetNode {
186 return s.edge.dependency
187}
188
189// Annotations describes the type of edge by the set of annotations attached to
190// it.
191//
192// Only annotations prescribed by policy have any meaning for licensing, and
193// the meaning for licensing is likewise prescribed by policy. Other annotations
194// are preserved and ignored by policy.
195func (s TargetEdgePathSegment) Annotations() TargetEdgeAnnotations {
196 return s.edge.annotations
197}
198
199// Context returns the context associated with the path segment. The type and
200// value of the context defined by the process creating the path.
201func (s TargetEdgePathSegment) Context() interface{} {
202 return s.ctx
203}
204
205// String returns a human-readable string representation of the edge.
206func (s TargetEdgePathSegment) String() string {
207 return fmt.Sprintf("%s -[%s]> %s", s.edge.target.name, strings.Join(s.edge.annotations.AsList(), ", "), s.edge.dependency.name)
Bob Badoura99ac622021-10-25 16:21:00 -0700208}
209
210// TargetEdgePath describes a sequence of edges starting at a root and ending
211// at some final dependency.
Bob Badour103eb0f2022-01-10 13:50:57 -0800212type TargetEdgePath []TargetEdgePathSegment
Bob Badoura99ac622021-10-25 16:21:00 -0700213
214// NewTargetEdgePath creates a new, empty path with capacity `cap`.
215func NewTargetEdgePath(cap int) *TargetEdgePath {
216 p := make(TargetEdgePath, 0, cap)
217 return &p
218}
219
220// Push appends a new edge to the list verifying that the target of the new
221// edge is the dependency of the prior.
Bob Badour103eb0f2022-01-10 13:50:57 -0800222func (p *TargetEdgePath) Push(edge *TargetEdge, ctx interface{}) {
Bob Badoura99ac622021-10-25 16:21:00 -0700223 if len(*p) == 0 {
Bob Badour103eb0f2022-01-10 13:50:57 -0800224 *p = append(*p, TargetEdgePathSegment{edge, ctx})
Bob Badoura99ac622021-10-25 16:21:00 -0700225 return
226 }
Bob Badour103eb0f2022-01-10 13:50:57 -0800227 if (*p)[len(*p)-1].edge.dependency != edge.target {
228 panic(fmt.Errorf("disjoint path %s does not end at %s", p.String(), edge.target.name))
Bob Badoura99ac622021-10-25 16:21:00 -0700229 }
Bob Badour103eb0f2022-01-10 13:50:57 -0800230 *p = append(*p, TargetEdgePathSegment{edge, ctx})
Bob Badoura99ac622021-10-25 16:21:00 -0700231}
232
233// Pop shortens the path by 1 edge.
234func (p *TargetEdgePath) Pop() {
235 if len(*p) == 0 {
236 panic(fmt.Errorf("attempt to remove edge from empty path"))
237 }
238 *p = (*p)[:len(*p)-1]
239}
240
241// Clear makes the path length 0.
242func (p *TargetEdgePath) Clear() {
243 *p = (*p)[:0]
244}
245
Bob Badoure6fdd142021-12-09 22:10:43 -0800246// Copy makes a new path with the same value.
247func (p *TargetEdgePath) Copy() *TargetEdgePath {
248 result := make(TargetEdgePath, 0, len(*p))
249 for _, e := range *p {
250 result = append(result, e)
251 }
252 return &result
253}
254
Bob Badoura99ac622021-10-25 16:21:00 -0700255// String returns a string representation of the path: [n1 -> n2 -> ... -> nn].
256func (p *TargetEdgePath) String() string {
257 if p == nil {
258 return "nil"
259 }
260 if len(*p) == 0 {
261 return "[]"
262 }
263 var sb strings.Builder
264 fmt.Fprintf(&sb, "[")
Bob Badour103eb0f2022-01-10 13:50:57 -0800265 for _, s := range *p {
266 fmt.Fprintf(&sb, "%s -> ", s.edge.target.name)
Bob Badoura99ac622021-10-25 16:21:00 -0700267 }
Bob Badour103eb0f2022-01-10 13:50:57 -0800268 lastSegment := (*p)[len(*p)-1]
269 fmt.Fprintf(&sb, "%s]", lastSegment.edge.dependency.name)
Bob Badoura99ac622021-10-25 16:21:00 -0700270 return sb.String()
271}
272
273// TargetNode describes a module or target identified by the name of a specific
274// metadata file. (immutable)
275//
276// Each metadata file corresponds to a Soong module or to a Make target.
277//
278// A target node can appear as the target or as the dependency in edges.
279// Most target nodes appear as both target in one edge and as dependency in
280// other edges.
281type TargetNode targetNode
282
283// Name returns the string that identifies the target node.
284// i.e. path to license metadata file
285func (tn *TargetNode) Name() string {
286 return tn.name
287}
288
Bob Badour103eb0f2022-01-10 13:50:57 -0800289// Dependencies returns the list of edges to dependencies of `tn`.
290func (tn *TargetNode) Dependencies() TargetEdgeList {
291 edges := make(TargetEdgeList, 0, len(tn.edges))
292 edges = append(edges, tn.edges...)
293 return edges
294}
295
Bob Badoura99ac622021-10-25 16:21:00 -0700296// PackageName returns the string that identifes the package for the target.
297func (tn *TargetNode) PackageName() string {
298 return tn.proto.GetPackageName()
299}
300
Bob Badoura99ac622021-10-25 16:21:00 -0700301// Projects returns the projects defining the target node. (unordered)
302//
303// In an ideal world, only 1 project defines a target, but the interaction
304// between Soong and Make for a variety of architectures and for host versus
305// product means a module is sometimes defined more than once.
306func (tn *TargetNode) Projects() []string {
307 return append([]string{}, tn.proto.Projects...)
308}
309
Bob Badoura99ac622021-10-25 16:21:00 -0700310// LicenseConditions returns a copy of the set of license conditions
311// originating at the target. The values that appear and how each is resolved
312// is a matter of policy. (unordered)
313//
314// e.g. notice or proprietary
Bob Badour103eb0f2022-01-10 13:50:57 -0800315func (tn *TargetNode) LicenseConditions() LicenseConditionSet {
316 return tn.licenseConditions
Bob Badoura99ac622021-10-25 16:21:00 -0700317}
318
319// LicenseTexts returns the paths to the files containing the license texts for
320// the target. (unordered)
321func (tn *TargetNode) LicenseTexts() []string {
322 return append([]string{}, tn.proto.LicenseTexts...)
323}
324
325// IsContainer returns true if the target represents a container that merely
326// aggregates other targets.
327func (tn *TargetNode) IsContainer() bool {
328 return tn.proto.GetIsContainer()
329}
330
331// Built returns the list of files built by the module or target. (unordered)
332func (tn *TargetNode) Built() []string {
333 return append([]string{}, tn.proto.Built...)
334}
335
336// Installed returns the list of files installed by the module or target.
337// (unordered)
338func (tn *TargetNode) Installed() []string {
339 return append([]string{}, tn.proto.Installed...)
340}
341
Bob Badoure6fdd142021-12-09 22:10:43 -0800342// TargetFiles returns the list of files built or installed by the module or
343// target. (unordered)
344func (tn *TargetNode) TargetFiles() []string {
345 return append(tn.proto.Built, tn.proto.Installed...)
346}
347
Bob Badoura99ac622021-10-25 16:21:00 -0700348// InstallMap returns the list of path name transformations to make to move
349// files from their original location in the file system to their destination
350// inside a container. (unordered)
351func (tn *TargetNode) InstallMap() []InstallMap {
352 result := make([]InstallMap, 0, len(tn.proto.InstallMap))
353 for _, im := range tn.proto.InstallMap {
354 result = append(result, InstallMap{im.GetFromPath(), im.GetContainerPath()})
355 }
356 return result
357}
358
359// Sources returns the list of file names depended on by the target, which may
360// be a proper subset of those made available by dependency modules.
361// (unordered)
362func (tn *TargetNode) Sources() []string {
363 return append([]string{}, tn.proto.Sources...)
364}
365
366// InstallMap describes the mapping from an input filesystem file to file in a
367// container.
368type InstallMap struct {
369 // FromPath is the input path on the filesystem.
370 FromPath string
371
372 // ContainerPath is the path to the same file inside the container or
373 // installed location.
374 ContainerPath string
375}
376
377// TargetEdgeAnnotations describes an immutable set of annotations attached to
378// an edge from a target to a dependency.
379//
380// Annotations typically distinguish between static linkage versus dynamic
381// versus tools that are used at build time but are not linked in any way.
382type TargetEdgeAnnotations struct {
Bob Badour5446a6f2022-01-10 18:44:59 -0800383 annotations map[string]struct{}
Bob Badoura99ac622021-10-25 16:21:00 -0700384}
385
386// newEdgeAnnotations creates a new instance of TargetEdgeAnnotations.
387func newEdgeAnnotations() TargetEdgeAnnotations {
Bob Badour5446a6f2022-01-10 18:44:59 -0800388 return TargetEdgeAnnotations{make(map[string]struct{})}
Bob Badoura99ac622021-10-25 16:21:00 -0700389}
390
391// HasAnnotation returns true if an annotation `ann` is in the set.
392func (ea TargetEdgeAnnotations) HasAnnotation(ann string) bool {
393 _, ok := ea.annotations[ann]
394 return ok
395}
396
397// Compare orders TargetAnnotations returning:
398// -1 when ea < other,
399// +1 when ea > other, and
400// 0 when ea == other.
401func (ea TargetEdgeAnnotations) Compare(other TargetEdgeAnnotations) int {
402 a1 := ea.AsList()
403 a2 := other.AsList()
404 sort.Strings(a1)
405 sort.Strings(a2)
406 for k := 0; k < len(a1) && k < len(a2); k++ {
407 if a1[k] < a2[k] {
408 return -1
409 }
410 if a1[k] > a2[k] {
411 return 1
412 }
413 }
414 if len(a1) < len(a2) {
415 return -1
416 }
417 if len(a1) > len(a2) {
418 return 1
419 }
420 return 0
421}
422
423// AsList returns the list of annotation names attached to the edge.
424// (unordered)
425func (ea TargetEdgeAnnotations) AsList() []string {
426 l := make([]string, 0, len(ea.annotations))
427 for ann := range ea.annotations {
428 l = append(l, ann)
429 }
430 return l
431}
432
433// TargetNodeSet describes a set of distinct nodes in a license graph.
434type TargetNodeSet struct {
Bob Badour5446a6f2022-01-10 18:44:59 -0800435 nodes map[*TargetNode]struct{}
Bob Badoura99ac622021-10-25 16:21:00 -0700436}
437
438// Contains returns true when `target` is an element of the set.
439func (ts *TargetNodeSet) Contains(target *TargetNode) bool {
440 _, isPresent := ts.nodes[target]
441 return isPresent
442}
443
444// AsList returns the list of target nodes in the set. (unordered)
445func (ts *TargetNodeSet) AsList() TargetNodeList {
446 result := make(TargetNodeList, 0, len(ts.nodes))
447 for tn := range ts.nodes {
448 result = append(result, tn)
449 }
450 return result
451}
452
453// Names returns the array of target node namess in the set. (unordered)
454func (ts *TargetNodeSet) Names() []string {
455 result := make([]string, 0, len(ts.nodes))
456 for tn := range ts.nodes {
457 result = append(result, tn.name)
458 }
459 return result
460}
461
Bob Badour103eb0f2022-01-10 13:50:57 -0800462// String returns a human-readable string representation of the set.
463func (ts *TargetNodeSet) String() string {
464 return fmt.Sprintf("{%s}", strings.Join(ts.Names(), ", "))
465}
466
Bob Badoura99ac622021-10-25 16:21:00 -0700467// TargetNodeList orders a list of targets by name.
468type TargetNodeList []*TargetNode
469
470// Len returns the count of elements in the list.
Colin Cross35f79c32022-01-27 15:18:52 -0800471func (l TargetNodeList) Len() int { return len(l) }
Bob Badoura99ac622021-10-25 16:21:00 -0700472
473// Swap rearranges 2 elements so that each occupies the other's former position.
474func (l TargetNodeList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
475
476// Less returns true when the `i`th element is lexicographicallt less than the `j`th.
477func (l TargetNodeList) Less(i, j int) bool {
478 return l[i].name < l[j].name
479}
480
481// String returns a string representation of the list.
482func (l TargetNodeList) String() string {
483 var sb strings.Builder
484 fmt.Fprintf(&sb, "[")
485 sep := ""
486 for _, tn := range l {
487 fmt.Fprintf(&sb, "%s%s", sep, tn.name)
488 sep = " "
489 }
490 fmt.Fprintf(&sb, "]")
491 return sb.String()
492}
493
494// Names returns an array the names of the nodes in the same order as the nodes in the list.
495func (l TargetNodeList) Names() []string {
496 result := make([]string, 0, len(l))
497 for _, tn := range l {
498 result = append(result, tn.name)
499 }
500 return result
501}