compliance package policy and resolves

package to read, consume, and analyze license metadata and dependency
graph.

Bug: 68860345
Bug: 151177513
Bug: 151953481

Change-Id: Ic08406fa2250a08ad26f2167d934f841c95d9148
diff --git a/tools/compliance/policy/shipped.go b/tools/compliance/policy/shipped.go
new file mode 100644
index 0000000..74eb343
--- /dev/null
+++ b/tools/compliance/policy/shipped.go
@@ -0,0 +1,54 @@
+// 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
+
+// ShippedNodes returns the set of nodes in a license graph where the target or
+// a derivative work gets distributed. (caches result)
+func ShippedNodes(lg *LicenseGraph) *TargetNodeSet {
+	lg.mu.Lock()
+	shipped := lg.shippedNodes
+	lg.mu.Unlock()
+	if shipped != nil {
+		return shipped
+	}
+
+	tset := make(map[*TargetNode]bool)
+
+	WalkTopDown(lg, func(lg *LicenseGraph, tn *TargetNode, path TargetEdgePath) bool {
+		if _, alreadyWalked := tset[tn]; alreadyWalked {
+			return false
+		}
+		if len(path) > 0 {
+			if !edgeIsDerivation(path[len(path)-1]) {
+				return false
+			}
+		}
+		tset[tn] = true
+		return true
+	})
+
+	shipped = &TargetNodeSet{tset}
+
+	lg.mu.Lock()
+	if lg.shippedNodes == nil {
+		lg.shippedNodes = shipped
+	} else {
+		// if we end up with 2, release the later for garbage collection.
+		shipped = lg.shippedNodes
+	}
+	lg.mu.Unlock()
+
+	return shipped
+}