diff --git a/core/definitions.mk b/core/definitions.mk index 94e03a25cf..314ba0a261 100644 --- a/core/definitions.mk +++ b/core/definitions.mk @@ -874,6 +874,34 @@ reportmissinglicenses: endef + +########################################################### +# Returns the unique list of built license metadata files. +########################################################### +define all-license-metadata +$(sort \ + $(foreach t,$(ALL_NON_MODULES),$(if $(filter 0p,$(ALL_TARGETS.$(t).META_LIC)),, $(ALL_TARGETS.$(t).META_LIC))) \ + $(foreach m,$(ALL_MODULES), $(ALL_MODULES.$(m).META_LIC)) \ +) +endef + +########################################################### +# Declares the rule to report all library names used in any notice files. +########################################################### +define report-all-notice-library-names-rule +$(strip $(eval _all := $(call all-license-metadata))) + +.PHONY: reportallnoticelibrarynames +reportallnoticelibrarynames: PRIVATE_LIST_FILE := $(call license-metadata-dir)/filelist +reportallnoticelibrarynames: | $(COMPLIANCENOTICE_SHIPPEDLIBS) +reportallnoticelibrarynames: $(_all) + @echo Reporting notice library names for at least $$(words $(_all)) license metadata files + $(hide) rm -f $$(PRIVATE_LIST_FILE) + $(hide) mkdir -p $$(dir $$(PRIVATE_LIST_FILE)) + $(hide) find out -name '*meta_lic' -type f -printf '"%p"\n' >$$(PRIVATE_LIST_FILE) + $(COMPLIANCENOTICE_SHIPPEDLIBS) @$$(PRIVATE_LIST_FILE) +endef + ########################################################### ## Declares a license metadata build rule for ALL_MODULES ########################################################### @@ -888,7 +916,8 @@ $(strip \ ) \ $(foreach t,$(sort $(ALL_NON_MODULES)),$(eval $(call non-module-license-metadata-rule,$(t)))) \ $(foreach m,$(sort $(ALL_MODULES)),$(eval $(call license-metadata-rule,$(m)))) \ - $(eval $(call report-missing-licenses-rule))) + $(eval $(call report-missing-licenses-rule)) \ + $(eval $(call report-all-notice-library-names-rule))) endef ########################################################### diff --git a/core/notice_files.mk b/core/notice_files.mk index 4edbbb8ffc..4ebbe2eeef 100644 --- a/core/notice_files.mk +++ b/core/notice_files.mk @@ -11,10 +11,6 @@ endif ifneq (,$(strip $(LOCAL_LICENSE_PACKAGE_NAME))) license_package_name:=$(strip $(LOCAL_LICENSE_PACKAGE_NAME)) -else ifdef my_register_name -license_package_name:=$(my_register_name) -else -license_package_name:=$(strip $(LOCAL_MODULE)) endif ifneq (,$(strip $(LOCAL_LICENSE_INSTALL_MAP))) diff --git a/tools/compliance/Android.bp b/tools/compliance/Android.bp index d5965f8c82..ec0f2f9f5d 100644 --- a/tools/compliance/Android.bp +++ b/tools/compliance/Android.bp @@ -18,17 +18,27 @@ package { } blueprint_go_binary { - name: "bom", + name: "checkshare", + srcs: ["cmd/checkshare/checkshare.go"], + deps: ["compliance-module"], + testSrcs: ["cmd/checkshare/checkshare_test.go"], +} + +blueprint_go_binary { + name: "compliancenotice_bom", srcs: ["cmd/bom/bom.go"], deps: ["compliance-module"], testSrcs: ["cmd/bom/bom_test.go"], } blueprint_go_binary { - name: "checkshare", - srcs: ["cmd/checkshare/checkshare.go"], - deps: ["compliance-module"], - testSrcs: ["cmd/checkshare/checkshare_test.go"], + name: "compliancenotice_shippedlibs", + srcs: ["cmd/shippedlibs/shippedlibs.go"], + deps: [ + "compliance-module", + "soong-response", + ], + testSrcs: ["cmd/shippedlibs/shippedlibs_test.go"], } blueprint_go_binary { @@ -69,13 +79,6 @@ blueprint_go_binary { testSrcs: ["cmd/rtrace/rtrace_test.go"], } -blueprint_go_binary { - name: "shippedlibs", - srcs: ["cmd/shippedlibs/shippedlibs.go"], - deps: ["compliance-module"], - testSrcs: ["cmd/shippedlibs/shippedlibs_test.go"], -} - blueprint_go_binary { name: "textnotice", srcs: ["cmd/textnotice/textnotice.go"], diff --git a/tools/compliance/cmd/shippedlibs/shippedlibs.go b/tools/compliance/cmd/shippedlibs/shippedlibs.go index fddc4896ed..94b19f197e 100644 --- a/tools/compliance/cmd/shippedlibs/shippedlibs.go +++ b/tools/compliance/cmd/shippedlibs/shippedlibs.go @@ -22,13 +22,13 @@ import ( "io/fs" "os" "path/filepath" + "strings" + "android/soong/response" "android/soong/tools/compliance" ) var ( - outputFile = flag.String("o", "-", "Where to write the library list. (default stdout)") - failNoneRequested = fmt.Errorf("\nNo license metadata files requested") failNoLicenses = fmt.Errorf("No licenses found") ) @@ -40,28 +40,58 @@ type context struct { } func init() { - flag.Usage = func() { +} + +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) + + outputFile := flags.String("o", "-", "Where to write the library list. (default stdout)") + + flags.Usage = func() { fmt.Fprintf(os.Stderr, `Usage: %s {options} file.meta_lic {file.meta_lic...} Outputs a list of libraries used in the shipped images. Options: `, filepath.Base(os.Args[0])) - flag.PrintDefaults() + flags.PrintDefaults() } -} -func main() { - flag.Parse() + err := flags.Parse(expandedArgs) + if err != nil { + flags.Usage() + fmt.Fprintf(os.Stderr, "%v\n", err) + } // 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 { @@ -89,10 +119,10 @@ func main() { ctx := &context{ofile, os.Stderr, os.DirFS(".")} - err := shippedLibs(ctx, flag.Args()...) + err = shippedLibs(ctx, flags.Args()...) if err != nil { if err == failNoneRequested { - flag.Usage() + flags.Usage() } fmt.Fprintf(os.Stderr, "%s\n", err.Error()) os.Exit(1) diff --git a/tools/compliance/noticeindex.go b/tools/compliance/noticeindex.go index 904916c10e..f0823837d4 100644 --- a/tools/compliance/noticeindex.go +++ b/tools/compliance/noticeindex.go @@ -311,6 +311,13 @@ func (ni *NoticeIndex) HashText(h hash) []byte { func (ni *NoticeIndex) getLibName(noticeFor *TargetNode, h hash) string { for _, text := range noticeFor.LicenseTexts() { if !strings.Contains(text, ":") { + if ni.hash[text].key != h.key { + continue + } + ln := ni.checkMetadataForLicenseText(noticeFor, text) + if len(ln) > 0 { + return ln + } continue } @@ -342,6 +349,17 @@ func (ni *NoticeIndex) getLibName(noticeFor *TargetNode, h hash) string { if !strings.HasPrefix(licenseText, "prebuilts/") { continue } + if !strings.Contains(licenseText, ":") { + if ni.hash[licenseText].key != h.key { + continue + } + } else { + fields := strings.SplitN(licenseText, ":", 2) + fname := fields[0] + if ni.hash[fname].key != h.key { + continue + } + } for r, prefix := range SafePrebuiltPrefixes { match := r.FindString(licenseText) if len(match) == 0 { @@ -389,6 +407,10 @@ func (ni *NoticeIndex) getLibName(noticeFor *TargetNode, h hash) string { if li > 0 { n = n[li+1:] } + fi := strings.Index(n, "@") + if fi > 0 { + n = n[:fi] + } return n } @@ -401,67 +423,115 @@ func (ni *NoticeIndex) checkMetadata(noticeFor *TargetNode) string { } return name } - f, err := ni.rootFS.Open(filepath.Join(p, "METADATA")) + name, err := ni.checkMetadataFile(filepath.Join(p, "METADATA")) if err != nil { ni.projectName[p] = noProjectName continue } - name := "" - description := "" - version := "" - s := bufio.NewScanner(f) - for s.Scan() { - line := s.Text() - m := nameRegexp.FindStringSubmatch(line) - if m != nil { - if 1 < len(m) && m[1] != "" { - name = m[1] - } - if version != "" { - break - } - continue - } - m = versionRegexp.FindStringSubmatch(line) - if m != nil { - if 1 < len(m) && m[1] != "" { - version = m[1] - } - if name != "" { - break - } - continue - } - m = descRegexp.FindStringSubmatch(line) - if m != nil { - if 1 < len(m) && m[1] != "" { - description = m[1] - } - } + if len(name) == 0 { + ni.projectName[p] = noProjectName + continue } - _ = s.Err() - _ = f.Close() - if name != "" { - if version != "" { - if version[0] == 'v' || version[0] == 'V' { - ni.projectName[p] = name + "_" + version - } else { - ni.projectName[p] = name + "_v_" + version - } - } else { - ni.projectName[p] = name - } - return ni.projectName[p] - } - if description != "" { - ni.projectName[p] = description - return ni.projectName[p] - } - ni.projectName[p] = noProjectName + ni.projectName[p] = name + return name } return "" } +// checkMetadataForLicenseText +func (ni *NoticeIndex) checkMetadataForLicenseText(noticeFor *TargetNode, licenseText string) string { + p := "" + for _, proj := range noticeFor.Projects() { + if strings.HasPrefix(licenseText, proj) { + p = proj + } + } + if len(p) == 0 { + p = filepath.Dir(licenseText) + for { + fi, err := fs.Stat(ni.rootFS, filepath.Join(p, ".git")) + if err == nil && fi.IsDir() { + break + } + if strings.Contains(p, "/") && p != "/" { + p = filepath.Dir(p) + continue + } + return "" + } + } + if name, ok := ni.projectName[p]; ok { + if name == noProjectName { + return "" + } + return name + } + name, err := ni.checkMetadataFile(filepath.Join(p, "METADATA")) + if err == nil && len(name) > 0 { + ni.projectName[p] = name + return name + } + ni.projectName[p] = noProjectName + return "" +} + +// checkMetadataFile tries to look up a library name from a METADATA file at `path`. +func (ni *NoticeIndex) checkMetadataFile(path string) (string, error) { + f, err := ni.rootFS.Open(path) + if err != nil { + return "", err + } + name := "" + description := "" + version := "" + s := bufio.NewScanner(f) + for s.Scan() { + line := s.Text() + m := nameRegexp.FindStringSubmatch(line) + if m != nil { + if 1 < len(m) && m[1] != "" { + name = m[1] + } + if version != "" { + break + } + continue + } + m = versionRegexp.FindStringSubmatch(line) + if m != nil { + if 1 < len(m) && m[1] != "" { + version = m[1] + } + if name != "" { + break + } + continue + } + m = descRegexp.FindStringSubmatch(line) + if m != nil { + if 1 < len(m) && m[1] != "" { + description = m[1] + } + } + } + _ = s.Err() + _ = f.Close() + if name != "" { + if version != "" { + if version[0] == 'v' || version[0] == 'V' { + return name + "_" + version, nil + } else { + return name + "_v_" + version, nil + } + } + return name, nil + } + if description != "" { + return description, nil + } + return "", nil +} + // addText reads and indexes the content of a license text file. func (ni *NoticeIndex) addText(file string) error { f, err := ni.rootFS.Open(filepath.Clean(file))