Merge "Improve flags for compliance tools." am: 10714789a9

Original change: https://android-review.googlesource.com/c/platform/build/+/2116674

Change-Id: Ia092df3daa4a98aadebfb9010c1272c27b813f5d
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Treehugger Robot 2022-06-07 01:13:10 +00:00 committed by Automerger Merge Worker
commit 4033d64768
11 changed files with 649 additions and 239 deletions

View file

@ -20,14 +20,20 @@ package {
blueprint_go_binary {
name: "compliance_checkshare",
srcs: ["cmd/checkshare/checkshare.go"],
deps: ["compliance-module"],
deps: [
"compliance-module",
"soong-response",
],
testSrcs: ["cmd/checkshare/checkshare_test.go"],
}
blueprint_go_binary {
name: "compliancenotice_bom",
srcs: ["cmd/bom/bom.go"],
deps: ["compliance-module"],
deps: [
"compliance-module",
"soong-response",
],
testSrcs: ["cmd/bom/bom_test.go"],
}
@ -44,21 +50,30 @@ blueprint_go_binary {
blueprint_go_binary {
name: "compliance_listshare",
srcs: ["cmd/listshare/listshare.go"],
deps: ["compliance-module"],
deps: [
"compliance-module",
"soong-response",
],
testSrcs: ["cmd/listshare/listshare_test.go"],
}
blueprint_go_binary {
name: "compliance_dumpgraph",
srcs: ["cmd/dumpgraph/dumpgraph.go"],
deps: ["compliance-module"],
deps: [
"compliance-module",
"soong-response",
],
testSrcs: ["cmd/dumpgraph/dumpgraph_test.go"],
}
blueprint_go_binary {
name: "compliance_dumpresolutions",
srcs: ["cmd/dumpresolutions/dumpresolutions.go"],
deps: ["compliance-module"],
deps: [
"compliance-module",
"soong-response",
],
testSrcs: ["cmd/dumpresolutions/dumpresolutions_test.go"],
}
@ -68,6 +83,7 @@ blueprint_go_binary {
deps: [
"compliance-module",
"blueprint-deptools",
"soong-response",
],
testSrcs: ["cmd/htmlnotice/htmlnotice_test.go"],
}
@ -75,7 +91,10 @@ blueprint_go_binary {
blueprint_go_binary {
name: "compliance_rtrace",
srcs: ["cmd/rtrace/rtrace.go"],
deps: ["compliance-module"],
deps: [
"compliance-module",
"soong-response",
],
testSrcs: ["cmd/rtrace/rtrace_test.go"],
}
@ -85,6 +104,7 @@ blueprint_go_binary {
deps: [
"compliance-module",
"blueprint-deptools",
"soong-response",
],
testSrcs: ["cmd/textnotice/textnotice_test.go"],
}
@ -95,6 +115,7 @@ blueprint_go_binary {
deps: [
"compliance-module",
"blueprint-deptools",
"soong-response",
],
testSrcs: ["cmd/xmlnotice/xmlnotice_test.go"],
}

View file

@ -24,13 +24,11 @@ import (
"path/filepath"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
)
var (
outputFile = flag.String("o", "-", "Where to write the bill of materials. (default stdout)")
stripPrefix = newMultiString("strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
failNoLicenses = fmt.Errorf("No licenses found")
)
@ -55,22 +53,10 @@ func (ctx context) strip(installPath string) string {
return installPath
}
func init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs a bill of materials. i.e. the list of installed paths.
Options:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
}
}
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(name, usage string) *multiString {
func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
var f multiString
flag.Var(&f, name, usage)
flags.Var(&f, name, usage)
return &f
}
@ -81,16 +67,52 @@ func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
flag.Parse()
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs a bill of materials. i.e. the list of installed paths.
Options:
`, filepath.Base(os.Args[0]))
flags.PrintDefaults()
}
outputFile := flags.String("o", "-", "Where to write the bill of materials. (default stdout)")
stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
if len(*outputFile) == 0 {
flag.Usage()
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
@ -118,10 +140,10 @@ func main() {
ctx := &context{ofile, os.Stderr, compliance.FS, *stripPrefix}
err := billOfMaterials(ctx, flag.Args()...)
err := billOfMaterials(ctx, flags.Args()...)
if err != nil {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)

View file

@ -15,6 +15,7 @@
package main
import (
"bytes"
"flag"
"fmt"
"io"
@ -22,31 +23,12 @@ import (
"os"
"path/filepath"
"sort"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
)
func init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s file.meta_lic {file.meta_lic...}
Reports on stderr any targets where policy says that the source both
must and must not be shared. The error report indicates the target, the
license condition that has a source privacy policy, and the license
condition that has a source sharing policy.
Any given target may appear multiple times with different combinations
of conflicting license conditions.
If all the source code that policy says must be shared may be shared,
outputs "PASS" to stdout and exits with status 0.
If policy says any source must both be shared and not be shared,
outputs "FAIL" to stdout and exits with status 1.
`, filepath.Base(os.Args[0]))
}
}
var (
failConflicts = fmt.Errorf("conflicts")
failNoneRequested = fmt.Errorf("\nNo metadata files requested")
@ -61,24 +43,105 @@ func (l byError) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l byError) Less(i, j int) bool { return l[i].Error() < l[j].Error() }
func main() {
flag.Parse()
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {-o outfile} file.meta_lic {file.meta_lic...}
Reports on stderr any targets where policy says that the source both
must and must not be shared. The error report indicates the target, the
license condition that has a source privacy policy, and the license
condition that has a source sharing policy.
Any given target may appear multiple times with different combinations
of conflicting license conditions.
If all the source code that policy says must be shared may be shared,
outputs "PASS" to stdout and exits with status 0.
If policy says any source must both be shared and not be shared,
outputs "FAIL" to stdout and exits with status 1.
`, filepath.Base(os.Args[0]))
flags.PrintDefaults()
}
outputFile := flags.String("o", "-", "Where to write the output. (default stdout)")
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
err := checkShare(os.Stdout, os.Stderr, compliance.FS, flag.Args()...)
if len(*outputFile) == 0 {
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
dir, err := filepath.Abs(filepath.Dir(*outputFile))
if err != nil {
fmt.Fprintf(os.Stderr, "cannot determine path to %q: %s\n", *outputFile, err)
os.Exit(1)
}
fi, err := os.Stat(dir)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %s\n", dir, *outputFile, err)
os.Exit(1)
}
if !fi.IsDir() {
fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile)
os.Exit(1)
}
}
var ofile io.Writer
ofile = os.Stdout
var obuf *bytes.Buffer
if *outputFile != "-" {
obuf = &bytes.Buffer{}
ofile = obuf
}
err := checkShare(ofile, os.Stderr, compliance.FS, flags.Args()...)
if err != nil {
if err != failConflicts {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
}
os.Exit(1)
}
if *outputFile != "-" {
err := os.WriteFile(*outputFile, obuf.Bytes(), 0666)
if err != nil {
fmt.Fprintf(os.Stderr, "could not write output to %q from %q: %s\n", *outputFile, os.Getenv("PWD"), err)
os.Exit(1)
}
}
os.Exit(0)
}
@ -92,7 +155,7 @@ func checkShare(stdout, stderr io.Writer, rootFS fs.FS, files ...string) error {
// Read the license graph from the license metadata files (*.meta_lic).
licenseGraph, err := compliance.ReadLicenseGraph(rootFS, stderr, files)
if err != nil {
return fmt.Errorf("Unable to read license metadata file(s) %q: %w\n", files, err)
return fmt.Errorf("Unable to read license metadata file(s) %q from %q: %w\n", files, os.Getenv("PWD"), err)
}
if licenseGraph == nil {
return failNoLicenses

View file

@ -15,6 +15,7 @@
package main
import (
"bytes"
"flag"
"fmt"
"io"
@ -24,14 +25,11 @@ import (
"sort"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
)
var (
graphViz = flag.Bool("dot", false, "Whether to output graphviz (i.e. dot) format.")
labelConditions = flag.Bool("label_conditions", false, "Whether to label target nodes with conditions.")
stripPrefix = newMultiString("strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
failNoLicenses = fmt.Errorf("No licenses found")
)
@ -55,8 +53,44 @@ func (ctx context) strip(installPath string) string {
return installPath
}
func init() {
flag.Usage = func() {
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
var f multiString
flags.Var(&f, name, usage)
return &f
}
// multiString implements the flag `Value` interface for multiple strings.
type multiString []string
func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs space-separated Target Dependency Annotations tuples for each
@ -70,42 +104,68 @@ target:condition1:condition2 etc.
Options:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
flags.PrintDefaults()
}
}
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(name, usage string) *multiString {
var f multiString
flag.Var(&f, name, usage)
return &f
}
graphViz := flags.Bool("dot", false, "Whether to output graphviz (i.e. dot) format.")
labelConditions := flags.Bool("label_conditions", false, "Whether to label target nodes with conditions.")
outputFile := flags.String("o", "-", "Where to write the output. (default stdout)")
stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
// multiString implements the flag `Value` interface for multiple strings.
type multiString []string
func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
flag.Parse()
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
if len(*outputFile) == 0 {
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
dir, err := filepath.Abs(filepath.Dir(*outputFile))
if err != nil {
fmt.Fprintf(os.Stderr, "cannot determine path to %q: %s\n", *outputFile, err)
os.Exit(1)
}
fi, err := os.Stat(dir)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %s\n", dir, *outputFile, err)
os.Exit(1)
}
if !fi.IsDir() {
fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile)
os.Exit(1)
}
}
var ofile io.Writer
ofile = os.Stdout
var obuf *bytes.Buffer
if *outputFile != "-" {
obuf = &bytes.Buffer{}
ofile = obuf
}
ctx := &context{*graphViz, *labelConditions, *stripPrefix}
err := dumpGraph(ctx, os.Stdout, os.Stderr, compliance.FS, flag.Args()...)
err := dumpGraph(ctx, ofile, os.Stderr, compliance.FS, flags.Args()...)
if err != nil {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)
}
if *outputFile != "-" {
err := os.WriteFile(*outputFile, obuf.Bytes(), 0666)
if err != nil {
fmt.Fprintf(os.Stderr, "could not write output to %q from %q: %s\n", *outputFile, os.Getenv("PWD"), err)
os.Exit(1)
}
}
os.Exit(0)
}

View file

@ -15,6 +15,7 @@
package main
import (
"bytes"
"flag"
"fmt"
"io"
@ -24,15 +25,11 @@ import (
"sort"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
)
var (
conditions = newMultiString("c", "License condition to resolve. (may be given multiple times)")
graphViz = flag.Bool("dot", false, "Whether to output graphviz (i.e. dot) format.")
labelConditions = flag.Bool("label_conditions", false, "Whether to label target nodes with conditions.")
stripPrefix = newMultiString("strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
failNoLicenses = fmt.Errorf("No licenses found")
)
@ -57,8 +54,44 @@ func (ctx context) strip(installPath string) string {
return installPath
}
func init() {
flag.Usage = func() {
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
var f multiString
flags.Var(&f, name, usage)
return &f
}
// multiString implements the flag `Value` interface for multiple strings.
type multiString []string
func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs a space-separated Target ActsOn Origin Condition tuple for each
@ -75,32 +108,52 @@ i.e. target:condition1:condition2 etc.
Options:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
flags.PrintDefaults()
}
}
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(name, usage string) *multiString {
var f multiString
flag.Var(&f, name, usage)
return &f
}
conditions := newMultiString(flags, "c", "License condition to resolve. (may be given multiple times)")
graphViz := flags.Bool("dot", false, "Whether to output graphviz (i.e. dot) format.")
labelConditions := flags.Bool("label_conditions", false, "Whether to label target nodes with conditions.")
outputFile := flags.String("o", "-", "Where to write the output. (default stdout)")
stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
// multiString implements the flag `Value` interface for multiple strings.
type multiString []string
func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
flag.Parse()
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
if len(*outputFile) == 0 {
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
dir, err := filepath.Abs(filepath.Dir(*outputFile))
if err != nil {
fmt.Fprintf(os.Stderr, "cannot determine path to %q: %s\n", *outputFile, err)
os.Exit(1)
}
fi, err := os.Stat(dir)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %s\n", dir, *outputFile, err)
os.Exit(1)
}
if !fi.IsDir() {
fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile)
os.Exit(1)
}
}
var ofile io.Writer
ofile = os.Stdout
var obuf *bytes.Buffer
if *outputFile != "-" {
obuf = &bytes.Buffer{}
ofile = obuf
}
lcs := make([]compliance.LicenseCondition, 0, len(*conditions))
for _, name := range *conditions {
lcs = append(lcs, compliance.RecognizedConditionNames[name])
@ -111,14 +164,21 @@ func main() {
labelConditions: *labelConditions,
stripPrefix: *stripPrefix,
}
_, err := dumpResolutions(ctx, os.Stdout, os.Stderr, compliance.FS, flag.Args()...)
_, err := dumpResolutions(ctx, ofile, os.Stderr, compliance.FS, flags.Args()...)
if err != nil {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)
}
if *outputFile != "-" {
err := os.WriteFile(*outputFile, obuf.Bytes(), 0666)
if err != nil {
fmt.Fprintf(os.Stderr, "could not write output to %q from %q: %s\n", *outputFile, os.Getenv("PWD"), err)
os.Exit(1)
}
}
os.Exit(0)
}

View file

@ -26,19 +26,13 @@ import (
"path/filepath"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
"github.com/google/blueprint/deptools"
)
var (
outputFile = flag.String("o", "-", "Where to write the NOTICE text file. (default stdout)")
depsFile = flag.String("d", "", "Where to write the deps file")
includeTOC = flag.Bool("toc", true, "Whether to include a table of contents.")
product = flag.String("product", "", "The name of the product for which the notice is generated.")
stripPrefix = newMultiString("strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
title = flag.String("title", "", "The title of the notice file.")
failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
failNoLicenses = fmt.Errorf("No licenses found")
)
@ -70,23 +64,10 @@ func (ctx context) strip(installPath string) string {
return installPath
}
func init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs an html NOTICE.html or gzipped NOTICE.html.gz file if the -o filename
ends with ".gz".
Options:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
}
}
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(name, usage string) *multiString {
func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
var f multiString
flag.Var(&f, name, usage)
flags.Var(&f, name, usage)
return &f
}
@ -97,16 +78,57 @@ func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
flag.Parse()
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs an html NOTICE.html or gzipped NOTICE.html.gz file if the -o filename
ends with ".gz".
Options:
`, filepath.Base(os.Args[0]))
flags.PrintDefaults()
}
outputFile := flags.String("o", "-", "Where to write the NOTICE text file. (default stdout)")
depsFile := flags.String("d", "", "Where to write the deps file")
includeTOC := flags.Bool("toc", true, "Whether to include a table of contents.")
product := flags.String("product", "", "The name of the product for which the notice is generated.")
stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
title := flags.String("title", "", "The title of the notice file.")
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
if len(*outputFile) == 0 {
flag.Usage()
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
@ -143,10 +165,10 @@ func main() {
ctx := &context{ofile, os.Stderr, compliance.FS, *includeTOC, *product, *stripPrefix, *title, &deps}
err := htmlNotice(ctx, flag.Args()...)
err := htmlNotice(ctx, flags.Args()...)
if err != nil {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)

View file

@ -15,6 +15,7 @@
package main
import (
"bytes"
"flag"
"fmt"
"io"
@ -24,12 +25,41 @@ import (
"sort"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
)
func init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s file.meta_lic {file.meta_lic...}
var (
failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
failNoLicenses = fmt.Errorf("No licenses found")
)
func main() {
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {-o outfile} 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.
@ -39,30 +69,61 @@ 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")
)
outputFile := flags.String("o", "-", "Where to write the list of projects to share. (default stdout)")
func main() {
flag.Parse()
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
err := listShare(os.Stdout, os.Stderr, compliance.FS, flag.Args()...)
if len(*outputFile) == 0 {
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
dir, err := filepath.Abs(filepath.Dir(*outputFile))
if err != nil {
fmt.Fprintf(os.Stderr, "cannot determine path to %q: %s\n", *outputFile, err)
os.Exit(1)
}
fi, err := os.Stat(dir)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %s\n", dir, *outputFile, err)
os.Exit(1)
}
if !fi.IsDir() {
fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile)
os.Exit(1)
}
}
var ofile io.Writer
ofile = os.Stdout
var obuf *bytes.Buffer
if *outputFile != "-" {
obuf = &bytes.Buffer{}
ofile = obuf
}
err := listShare(ofile, os.Stderr, compliance.FS, flags.Args()...)
if err != nil {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)
}
if *outputFile != "-" {
err := os.WriteFile(*outputFile, obuf.Bytes(), 0666)
if err != nil {
fmt.Fprintf(os.Stderr, "could not write output to %q from %q: %s\n", *outputFile, os.Getenv("PWD"), err)
os.Exit(1)
}
}
os.Exit(0)
}
@ -76,7 +137,7 @@ func listShare(stdout, stderr io.Writer, rootFS fs.FS, files ...string) error {
// Read the license graph from the license metadata files (*.meta_lic).
licenseGraph, err := compliance.ReadLicenseGraph(rootFS, stderr, files)
if err != nil {
return fmt.Errorf("Unable to read license metadata file(s) %q: %v\n", files, err)
return fmt.Errorf("Unable to read license metadata file(s) %q from %q: %v\n", files, os.Getenv("PWD"), err)
}
if licenseGraph == nil {
return failNoLicenses

View file

@ -15,6 +15,7 @@
package main
import (
"bytes"
"flag"
"fmt"
"io"
@ -24,21 +25,19 @@ import (
"sort"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
)
var (
sources = newMultiString("rtrace", "Projects or metadata files to trace back from. (required; multiple allowed)")
stripPrefix = newMultiString("strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
failNoSources = fmt.Errorf("\nNo projects or metadata files to trace back from")
failNoLicenses = fmt.Errorf("No licenses found")
)
type context struct {
sources []string
stripPrefix []string
sources []string
stripPrefix []string
}
func (ctx context) strip(installPath string) string {
@ -54,8 +53,44 @@ func (ctx context) strip(installPath string) string {
return installPath
}
func init() {
flag.Usage = func() {
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
var f multiString
flags.Var(&f, name, usage)
return &f
}
// multiString implements the flag `Value` interface for multiple strings.
type multiString []string
func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs a space-separated Target ActsOn Origin Condition tuple for each
@ -72,50 +107,75 @@ i.e. target:condition1:condition2 etc.
Options:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
flags.PrintDefaults()
}
}
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(name, usage string) *multiString {
var f multiString
flag.Var(&f, name, usage)
return &f
}
outputFile := flags.String("o", "-", "Where to write the output. (default stdout)")
sources := newMultiString(flags, "rtrace", "Projects or metadata files to trace back from. (required; multiple allowed)")
stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
// multiString implements the flag `Value` interface for multiple strings.
type multiString []string
func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
flag.Parse()
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
if len(*sources) == 0 {
flag.Usage()
flags.Usage()
fmt.Fprintf(os.Stderr, "\nMust specify at least 1 --rtrace source.\n")
os.Exit(2)
}
ctx := &context{
sources: *sources,
stripPrefix: *stripPrefix,
if len(*outputFile) == 0 {
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
dir, err := filepath.Abs(filepath.Dir(*outputFile))
if err != nil {
fmt.Fprintf(os.Stderr, "cannot determine path to %q: %s\n", *outputFile, err)
os.Exit(1)
}
fi, err := os.Stat(dir)
if err != nil {
fmt.Fprintf(os.Stderr, "cannot read directory %q of %q: %s\n", dir, *outputFile, err)
os.Exit(1)
}
if !fi.IsDir() {
fmt.Fprintf(os.Stderr, "parent %q of %q is not a directory\n", dir, *outputFile)
os.Exit(1)
}
}
_, err := traceRestricted(ctx, os.Stdout, os.Stderr, compliance.FS, flag.Args()...)
var ofile io.Writer
ofile = os.Stdout
var obuf *bytes.Buffer
if *outputFile != "-" {
obuf = &bytes.Buffer{}
ofile = obuf
}
ctx := &context{
sources: *sources,
stripPrefix: *stripPrefix,
}
_, err := traceRestricted(ctx, ofile, os.Stderr, compliance.FS, flags.Args()...)
if err != nil {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)
}
if *outputFile != "-" {
err := os.WriteFile(*outputFile, obuf.Bytes(), 0666)
if err != nil {
fmt.Fprintf(os.Stderr, "could not write output to %q from %q: %s\n", *outputFile, os.Getenv("PWD"), err)
os.Exit(1)
}
}
os.Exit(0)
}

View file

@ -39,9 +39,6 @@ type context struct {
rootFS fs.FS
}
func init() {
}
func main() {
var expandedArgs []string
for _, arg := range os.Args[1:] {

View file

@ -25,18 +25,13 @@ import (
"path/filepath"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
"github.com/google/blueprint/deptools"
)
var (
outputFile = flag.String("o", "-", "Where to write the NOTICE text file. (default stdout)")
depsFile = flag.String("d", "", "Where to write the deps file")
product = flag.String("product", "", "The name of the product for which the notice is generated.")
stripPrefix = newMultiString("strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
title = flag.String("title", "", "The title of the notice file.")
failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
failNoLicenses = fmt.Errorf("No licenses found")
)
@ -67,22 +62,10 @@ func (ctx context) strip(installPath string) string {
return installPath
}
func init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs a text NOTICE file.
Options:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
}
}
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(name, usage string) *multiString {
func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
var f multiString
flag.Var(&f, name, usage)
flags.Var(&f, name, usage)
return &f
}
@ -93,16 +76,55 @@ func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
flag.Parse()
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs a text NOTICE file.
Options:
`, filepath.Base(os.Args[0]))
flags.PrintDefaults()
}
outputFile := flags.String("o", "-", "Where to write the NOTICE text file. (default stdout)")
depsFile := flags.String("d", "", "Where to write the deps file")
product := flags.String("product", "", "The name of the product for which the notice is generated.")
stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
title := flags.String("title", "", "The title of the notice file.")
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
if len(*outputFile) == 0 {
flag.Usage()
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
@ -139,10 +161,10 @@ func main() {
ctx := &context{ofile, os.Stderr, compliance.FS, *product, *stripPrefix, *title, &deps}
err := textNotice(ctx, flag.Args()...)
err := textNotice(ctx, flags.Args()...)
if err != nil {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)

View file

@ -26,18 +26,13 @@ import (
"path/filepath"
"strings"
"android/soong/response"
"android/soong/tools/compliance"
"github.com/google/blueprint/deptools"
)
var (
outputFile = flag.String("o", "-", "Where to write the NOTICE xml or xml.gz file. (default stdout)")
depsFile = flag.String("d", "", "Where to write the deps file")
product = flag.String("product", "", "The name of the product for which the notice is generated.")
stripPrefix = newMultiString("strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
title = flag.String("title", "", "The title of the notice file.")
failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
failNoLicenses = fmt.Errorf("No licenses found")
)
@ -68,23 +63,10 @@ func (ctx context) strip(installPath string) string {
return installPath
}
func init() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs an xml NOTICE.xml or gzipped NOTICE.xml.gz file if the -o filename ends
with ".gz".
Options:
`, filepath.Base(os.Args[0]))
flag.PrintDefaults()
}
}
// newMultiString creates a flag that allows multiple values in an array.
func newMultiString(name, usage string) *multiString {
func newMultiString(flags *flag.FlagSet, name, usage string) *multiString {
var f multiString
flag.Var(&f, name, usage)
flags.Var(&f, name, usage)
return &f
}
@ -95,16 +77,56 @@ func (ms *multiString) String() string { return strings.Join(*ms, ", ") }
func (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }
func main() {
flag.Parse()
var expandedArgs []string
for _, arg := range os.Args[1:] {
if strings.HasPrefix(arg, "@") {
f, err := os.Open(strings.TrimPrefix(arg, "@"))
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
respArgs, err := response.ReadRspFile(f)
f.Close()
if err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
expandedArgs = append(expandedArgs, respArgs...)
} else {
expandedArgs = append(expandedArgs, arg)
}
}
flags := flag.NewFlagSet("flags", flag.ExitOnError)
flags.Usage = func() {
fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}
Outputs an xml NOTICE.xml or gzipped NOTICE.xml.gz file if the -o filename ends
with ".gz".
Options:
`, filepath.Base(os.Args[0]))
flags.PrintDefaults()
}
outputFile := flags.String("o", "-", "Where to write the NOTICE xml or xml.gz file. (default stdout)")
depsFile := flags.String("d", "", "Where to write the deps file")
product := flags.String("product", "", "The name of the product for which the notice is generated.")
stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
title := flags.String("title", "", "The title of the notice file.")
flags.Parse(expandedArgs)
// Must specify at least one root target.
if flag.NArg() == 0 {
flag.Usage()
if flags.NArg() == 0 {
flags.Usage()
os.Exit(2)
}
if len(*outputFile) == 0 {
flag.Usage()
flags.Usage()
fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
os.Exit(2)
} else {
@ -141,10 +163,10 @@ func main() {
ctx := &context{ofile, os.Stderr, compliance.FS, *product, *stripPrefix, *title, &deps}
err := xmlNotice(ctx, flag.Args()...)
err := xmlNotice(ctx, flags.Args()...)
if err != nil {
if err == failNoneRequested {
flag.Usage()
flags.Usage()
}
fmt.Fprintf(os.Stderr, "%s\n", err.Error())
os.Exit(1)