compliance package: listshare and checkshare
package to read, consume, and analyze license metadata and dependency
graph.
Includes the below command-line tools:
listshare outputs csv of projects to share to meet restricted and
reciprocal license requirements with one project per line. The first
field is the path to the project, and subsequent fields identify the
license resolutions as colon-separated target:annotations tuples.
checkshare outputs error messages to stderr for any targets where
policy dictates both sharing and not sharing the source-code, and PASS
or FAIL to stdout. exit status indicates success 0 or conflict found 1
Bug: 68860345
Bug: 151177513
Bug: 151953481
Test: m all
Test: m systemlicense
Test: m listshare; out/soong/host/linux-x86/bin/listshare ...
Test: m checkshare; out/soong/host/linux-x86/bin/checkshare ...
Test: m dumpgraph; out/soong/host/linux-x86/dumpgraph ...
Test: m dumpresolutions; out/soong/host/linux-x86/dumpresolutions ...
where ... is the path to the .meta_lic file for the system image. In my
case if
$ export PRODUCT=$(realpath $ANDROID_PRODUCT_OUT --relative-to=$PWD)
... can be expressed as:
${PRODUCT}/gen/META/lic_intermediates/${PRODUCT}/system.img.meta_lic
Change-Id: I4ff3f98848f7e6d03a35734300d763ef5f245d53
diff --git a/tools/compliance/cmd/listshare.go b/tools/compliance/cmd/listshare.go
new file mode 100644
index 0000000..bba2308
--- /dev/null
+++ b/tools/compliance/cmd/listshare.go
@@ -0,0 +1,124 @@
+// 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 main
+
+import (
+ "compliance"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+)
+
+func init() {
+ flag.Usage = func() {
+ fmt.Fprintf(os.Stderr, `Usage: %s file.meta_lic {file.meta_lic...}
+
+Outputs a csv file with 1 project per line in the first field followed
+by target:condition pairs describing why the project must be shared.
+
+Each target is the path to a generated license metadata file for a
+Soong module or Make target, and the license condition is either
+restricted (e.g. GPL) or reciprocal (e.g. MPL).
+`, filepath.Base(os.Args[0]))
+ }
+}
+
+var (
+ failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
+ failNoLicenses = fmt.Errorf("No licenses found")
+)
+
+func main() {
+ flag.Parse()
+
+ // Must specify at least one root target.
+ if flag.NArg() == 0 {
+ flag.Usage()
+ os.Exit(2)
+ }
+
+ err := listShare(os.Stdout, os.Stderr, flag.Args()...)
+ if err != nil {
+ if err == failNoneRequested {
+ flag.Usage()
+ }
+ fmt.Fprintf(os.Stderr, "%s\n", err.Error())
+ os.Exit(1)
+ }
+ os.Exit(0)
+}
+
+// listShare implements the listshare utility.
+func listShare(stdout, stderr io.Writer, files ...string) error {
+ // Must be at least one root file.
+ if len(files) < 1 {
+ return failNoneRequested
+ }
+
+ // Read the license graph from the license metadata files (*.meta_lic).
+ licenseGraph, err := compliance.ReadLicenseGraph(os.DirFS("."), stderr, files)
+ if err != nil {
+ return fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err)
+ }
+ if licenseGraph == nil {
+ return failNoLicenses
+ }
+
+ // shareSource contains all source-sharing resolutions.
+ shareSource := compliance.ResolveSourceSharing(licenseGraph)
+
+ // Group the resolutions by project.
+ presolution := make(map[string]*compliance.LicenseConditionSet)
+ for _, target := range shareSource.AttachesTo() {
+ rl := shareSource.Resolutions(target)
+ sort.Sort(rl)
+ for _, r := range rl {
+ for _, p := range r.ActsOn().Projects() {
+ if _, ok := presolution[p]; !ok {
+ presolution[p] = r.Resolves().Copy()
+ continue
+ }
+ presolution[p].AddSet(r.Resolves())
+ }
+ }
+ }
+
+ // Sort the projects for repeatability/stability.
+ projects := make([]string, 0, len(presolution))
+ for p := range presolution {
+ projects = append(projects, p)
+ }
+ sort.Strings(projects)
+
+ // Output the sorted projects and the source-sharing license conditions that each project resolves.
+ for _, p := range projects {
+ fmt.Fprintf(stdout, "%s", p)
+
+ // Sort the conditions for repeatability/stability.
+ conditions := presolution[p].AsList()
+ sort.Sort(conditions)
+
+ // Output the sorted origin:condition pairs.
+ for _, lc := range conditions {
+ fmt.Fprintf(stdout, ",%s:%s", lc.Origin().Name(), lc.Name())
+ }
+ fmt.Fprintf(stdout, "\n")
+ }
+
+ return nil
+}