Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 90959e03 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Improve flags for compliance tools." into tm-dev am: 99b87147 am: bcaafa07

parents 0c466127 bcaafa07
Loading
Loading
Loading
Loading
+27 −6
Original line number Original line Diff line number Diff line
@@ -20,14 +20,20 @@ package {
blueprint_go_binary {
blueprint_go_binary {
    name: "compliance_checkshare",
    name: "compliance_checkshare",
    srcs: ["cmd/checkshare/checkshare.go"],
    srcs: ["cmd/checkshare/checkshare.go"],
    deps: ["compliance-module"],
    deps: [
        "compliance-module",
        "soong-response",
    ],
    testSrcs: ["cmd/checkshare/checkshare_test.go"],
    testSrcs: ["cmd/checkshare/checkshare_test.go"],
}
}


blueprint_go_binary {
blueprint_go_binary {
    name: "compliancenotice_bom",
    name: "compliancenotice_bom",
    srcs: ["cmd/bom/bom.go"],
    srcs: ["cmd/bom/bom.go"],
    deps: ["compliance-module"],
    deps: [
        "compliance-module",
        "soong-response",
    ],
    testSrcs: ["cmd/bom/bom_test.go"],
    testSrcs: ["cmd/bom/bom_test.go"],
}
}


@@ -44,21 +50,30 @@ blueprint_go_binary {
blueprint_go_binary {
blueprint_go_binary {
    name: "compliance_listshare",
    name: "compliance_listshare",
    srcs: ["cmd/listshare/listshare.go"],
    srcs: ["cmd/listshare/listshare.go"],
    deps: ["compliance-module"],
    deps: [
        "compliance-module",
        "soong-response",
    ],
    testSrcs: ["cmd/listshare/listshare_test.go"],
    testSrcs: ["cmd/listshare/listshare_test.go"],
}
}


blueprint_go_binary {
blueprint_go_binary {
    name: "compliance_dumpgraph",
    name: "compliance_dumpgraph",
    srcs: ["cmd/dumpgraph/dumpgraph.go"],
    srcs: ["cmd/dumpgraph/dumpgraph.go"],
    deps: ["compliance-module"],
    deps: [
        "compliance-module",
        "soong-response",
    ],
    testSrcs: ["cmd/dumpgraph/dumpgraph_test.go"],
    testSrcs: ["cmd/dumpgraph/dumpgraph_test.go"],
}
}


blueprint_go_binary {
blueprint_go_binary {
    name: "compliance_dumpresolutions",
    name: "compliance_dumpresolutions",
    srcs: ["cmd/dumpresolutions/dumpresolutions.go"],
    srcs: ["cmd/dumpresolutions/dumpresolutions.go"],
    deps: ["compliance-module"],
    deps: [
        "compliance-module",
        "soong-response",
    ],
    testSrcs: ["cmd/dumpresolutions/dumpresolutions_test.go"],
    testSrcs: ["cmd/dumpresolutions/dumpresolutions_test.go"],
}
}


@@ -68,6 +83,7 @@ blueprint_go_binary {
    deps: [
    deps: [
        "compliance-module",
        "compliance-module",
        "blueprint-deptools",
        "blueprint-deptools",
        "soong-response",
    ],
    ],
    testSrcs: ["cmd/htmlnotice/htmlnotice_test.go"],
    testSrcs: ["cmd/htmlnotice/htmlnotice_test.go"],
}
}
@@ -75,7 +91,10 @@ blueprint_go_binary {
blueprint_go_binary {
blueprint_go_binary {
    name: "compliance_rtrace",
    name: "compliance_rtrace",
    srcs: ["cmd/rtrace/rtrace.go"],
    srcs: ["cmd/rtrace/rtrace.go"],
    deps: ["compliance-module"],
    deps: [
        "compliance-module",
        "soong-response",
    ],
    testSrcs: ["cmd/rtrace/rtrace_test.go"],
    testSrcs: ["cmd/rtrace/rtrace_test.go"],
}
}


@@ -85,6 +104,7 @@ blueprint_go_binary {
    deps: [
    deps: [
        "compliance-module",
        "compliance-module",
        "blueprint-deptools",
        "blueprint-deptools",
        "soong-response",
    ],
    ],
    testSrcs: ["cmd/textnotice/textnotice_test.go"],
    testSrcs: ["cmd/textnotice/textnotice_test.go"],
}
}
@@ -95,6 +115,7 @@ blueprint_go_binary {
    deps: [
    deps: [
        "compliance-module",
        "compliance-module",
        "blueprint-deptools",
        "blueprint-deptools",
        "soong-response",
    ],
    ],
    testSrcs: ["cmd/xmlnotice/xmlnotice_test.go"],
    testSrcs: ["cmd/xmlnotice/xmlnotice_test.go"],
}
}
+45 −23
Original line number Original line Diff line number Diff line
@@ -24,13 +24,11 @@ import (
	"path/filepath"
	"path/filepath"
	"strings"
	"strings"


	"android/soong/response"
	"android/soong/tools/compliance"
	"android/soong/tools/compliance"
)
)


var (
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")
	failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
	failNoLicenses    = fmt.Errorf("No licenses found")
	failNoLicenses    = fmt.Errorf("No licenses found")
)
)
@@ -55,22 +53,10 @@ func (ctx context) strip(installPath string) string {
	return installPath
	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.
// 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
	var f multiString
	flag.Var(&f, name, usage)
	flags.Var(&f, name, usage)
	return &f
	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 (ms *multiString) Set(s string) error { *ms = append(*ms, s); return nil }


func main() {
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.
	// Must specify at least one root target.
	if flag.NArg() == 0 {
	if flags.NArg() == 0 {
		flag.Usage()
		flags.Usage()
		os.Exit(2)
		os.Exit(2)
	}
	}


	if len(*outputFile) == 0 {
	if len(*outputFile) == 0 {
		flag.Usage()
		flags.Usage()
		fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
		fmt.Fprintf(os.Stderr, "must specify file for -o; use - for stdout\n")
		os.Exit(2)
		os.Exit(2)
	} else {
	} else {
@@ -118,10 +140,10 @@ func main() {


	ctx := &context{ofile, os.Stderr, compliance.FS, *stripPrefix}
	ctx := &context{ofile, os.Stderr, compliance.FS, *stripPrefix}


	err := billOfMaterials(ctx, flag.Args()...)
	err := billOfMaterials(ctx, flags.Args()...)
	if err != nil {
	if err != nil {
		if err == failNoneRequested {
		if err == failNoneRequested {
			flag.Usage()
			flags.Usage()
		}
		}
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
		os.Exit(1)
+86 −23
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
package main
package main


import (
import (
	"bytes"
	"flag"
	"flag"
	"fmt"
	"fmt"
	"io"
	"io"
@@ -22,13 +23,51 @@ import (
	"os"
	"os"
	"path/filepath"
	"path/filepath"
	"sort"
	"sort"
	"strings"


	"android/soong/response"
	"android/soong/tools/compliance"
	"android/soong/tools/compliance"
)
)


func init() {
var (
	flag.Usage = func() {
	failConflicts     = fmt.Errorf("conflicts")
		fmt.Fprintf(os.Stderr, `Usage: %s file.meta_lic {file.meta_lic...}
	failNoneRequested = fmt.Errorf("\nNo metadata files requested")
	failNoLicenses    = fmt.Errorf("No licenses")
)

// byError orders conflicts by error string
type byError []compliance.SourceSharePrivacyConflict

func (l byError) Len() int           { return len(l) }
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() {
	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
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
must and must not be shared. The error report indicates the target, the
@@ -44,41 +83,65 @@ outputs "PASS" to stdout and exits with status 0.
If policy says any source must both be shared and not be shared,
If policy says any source must both be shared and not be shared,
outputs "FAIL" to stdout and exits with status 1.
outputs "FAIL" to stdout and exits with status 1.
`, filepath.Base(os.Args[0]))
`, filepath.Base(os.Args[0]))
		flags.PrintDefaults()
	}
	}
}

var (
	failConflicts     = fmt.Errorf("conflicts")
	failNoneRequested = fmt.Errorf("\nNo metadata files requested")
	failNoLicenses    = fmt.Errorf("No licenses")
)

// byError orders conflicts by error string
type byError []compliance.SourceSharePrivacyConflict


func (l byError) Len() int           { return len(l) }
	outputFile := flags.String("o", "-", "Where to write the output. (default stdout)")
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() {
	flags.Parse(expandedArgs)
	flag.Parse()


	// Must specify at least one root target.
	// Must specify at least one root target.
	if flag.NArg() == 0 {
	if flags.NArg() == 0 {
		flag.Usage()
		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)
		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(os.Stdout, os.Stderr, compliance.FS, flag.Args()...)
	err := checkShare(ofile, os.Stderr, compliance.FS, flags.Args()...)
	if err != nil {
	if err != nil {
		if err != failConflicts {
		if err != failConflicts {
			if err == failNoneRequested {
			if err == failNoneRequested {
				flag.Usage()
				flags.Usage()
			}
			}
			fmt.Fprintf(os.Stderr, "%s\n", err.Error())
			fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		}
		}
		os.Exit(1)
		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)
	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).
	// Read the license graph from the license metadata files (*.meta_lic).
	licenseGraph, err := compliance.ReadLicenseGraph(rootFS, stderr, files)
	licenseGraph, err := compliance.ReadLicenseGraph(rootFS, stderr, files)
	if err != nil {
	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 {
	if licenseGraph == nil {
		return failNoLicenses
		return failNoLicenses
+86 −26
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
package main
package main


import (
import (
	"bytes"
	"flag"
	"flag"
	"fmt"
	"fmt"
	"io"
	"io"
@@ -24,14 +25,11 @@ import (
	"sort"
	"sort"
	"strings"
	"strings"


	"android/soong/response"
	"android/soong/tools/compliance"
	"android/soong/tools/compliance"
)
)


var (
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")
	failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
	failNoLicenses    = fmt.Errorf("No licenses found")
	failNoLicenses    = fmt.Errorf("No licenses found")
)
)
@@ -55,8 +53,44 @@ func (ctx context) strip(installPath string) string {
	return installPath
	return installPath
}
}


func init() {
// newMultiString creates a flag that allows multiple values in an array.
	flag.Usage = func() {
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...}
		fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}


Outputs space-separated Target Dependency Annotations tuples for each
Outputs space-separated Target Dependency Annotations tuples for each
@@ -70,42 +104,68 @@ target:condition1:condition2 etc.


Options:
Options:
`, filepath.Base(os.Args[0]))
`, filepath.Base(os.Args[0]))
		flag.PrintDefaults()
		flags.PrintDefaults()
	}
	}
	}


// newMultiString creates a flag that allows multiple values in an array.
	graphViz := flags.Bool("dot", false, "Whether to output graphviz (i.e. dot) format.")
func newMultiString(name, usage string) *multiString {
	labelConditions := flags.Bool("label_conditions", false, "Whether to label target nodes with conditions.")
	var f multiString
	outputFile := flags.String("o", "-", "Where to write the output. (default stdout)")
	flag.Var(&f, name, usage)
	stripPrefix := newMultiString(flags, "strip_prefix", "Prefix to remove from paths. i.e. path to root (multiple allowed)")
	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() {
	flags.Parse(expandedArgs)
	flag.Parse()


	// Must specify at least one root target.
	// Must specify at least one root target.
	if flag.NArg() == 0 {
	if flags.NArg() == 0 {
		flag.Usage()
		flags.Usage()
		os.Exit(2)
		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}
	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 != nil {
		if err == failNoneRequested {
		if err == failNoneRequested {
			flag.Usage()
			flags.Usage()
		}
		}
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
		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)
	os.Exit(0)
}
}


+87 −27
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
package main
package main


import (
import (
	"bytes"
	"flag"
	"flag"
	"fmt"
	"fmt"
	"io"
	"io"
@@ -24,15 +25,11 @@ import (
	"sort"
	"sort"
	"strings"
	"strings"


	"android/soong/response"
	"android/soong/tools/compliance"
	"android/soong/tools/compliance"
)
)


var (
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")
	failNoneRequested = fmt.Errorf("\nNo license metadata files requested")
	failNoLicenses    = fmt.Errorf("No licenses found")
	failNoLicenses    = fmt.Errorf("No licenses found")
)
)
@@ -57,8 +54,44 @@ func (ctx context) strip(installPath string) string {
	return installPath
	return installPath
}
}


func init() {
// newMultiString creates a flag that allows multiple values in an array.
	flag.Usage = func() {
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...}
		fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...}


Outputs a space-separated Target ActsOn Origin Condition tuple for each
Outputs a space-separated Target ActsOn Origin Condition tuple for each
@@ -75,32 +108,52 @@ i.e. target:condition1:condition2 etc.


Options:
Options:
`, filepath.Base(os.Args[0]))
`, filepath.Base(os.Args[0]))
		flag.PrintDefaults()
		flags.PrintDefaults()
	}
	}
	}


// newMultiString creates a flag that allows multiple values in an array.
	conditions := newMultiString(flags, "c", "License condition to resolve. (may be given multiple times)")
func newMultiString(name, usage string) *multiString {
	graphViz := flags.Bool("dot", false, "Whether to output graphviz (i.e. dot) format.")
	var f multiString
	labelConditions := flags.Bool("label_conditions", false, "Whether to label target nodes with conditions.")
	flag.Var(&f, name, usage)
	outputFile := flags.String("o", "-", "Where to write the output. (default stdout)")
	return &f
	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() {
	flags.Parse(expandedArgs)
	flag.Parse()


	// Must specify at least one root target.
	// Must specify at least one root target.
	if flag.NArg() == 0 {
	if flags.NArg() == 0 {
		flag.Usage()
		flags.Usage()
		os.Exit(2)
		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))
	lcs := make([]compliance.LicenseCondition, 0, len(*conditions))
	for _, name := range *conditions {
	for _, name := range *conditions {
		lcs = append(lcs, compliance.RecognizedConditionNames[name])
		lcs = append(lcs, compliance.RecognizedConditionNames[name])
@@ -111,14 +164,21 @@ func main() {
		labelConditions: *labelConditions,
		labelConditions: *labelConditions,
		stripPrefix:     *stripPrefix,
		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 != nil {
		if err == failNoneRequested {
		if err == failNoneRequested {
			flag.Usage()
			flags.Usage()
		}
		}
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		fmt.Fprintf(os.Stderr, "%s\n", err.Error())
		os.Exit(1)
		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)
	os.Exit(0)
}
}


Loading