Add gen_notice module.
Refactor notices to support notices for multiple modules.
Enforce visibility and handle missing dependencies.
Bug: 213388645
Change-Id: Id6a81987f087419ad37d0cce57a71e8a7c4cd6e0
diff --git a/android/gen_notice.go b/android/gen_notice.go
new file mode 100644
index 0000000..f514975
--- /dev/null
+++ b/android/gen_notice.go
@@ -0,0 +1,207 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// 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 android
+
+import (
+ "fmt"
+ "strings"
+
+ "github.com/google/blueprint/proptools"
+)
+
+func init() {
+ RegisterGenNoticeBuildComponents(InitRegistrationContext)
+}
+
+// Register the gen_notice module type.
+func RegisterGenNoticeBuildComponents(ctx RegistrationContext) {
+ ctx.RegisterSingletonType("gen_notice_build_rules", GenNoticeBuildRulesFactory)
+ ctx.RegisterModuleType("gen_notice", GenNoticeFactory)
+}
+
+type genNoticeBuildRules struct{}
+
+func (s *genNoticeBuildRules) GenerateBuildActions(ctx SingletonContext) {
+ ctx.VisitAllModules(func(m Module) {
+ gm, ok := m.(*genNoticeModule)
+ if !ok {
+ return
+ }
+ if len(gm.missing) > 0 {
+ missingReferencesRule(ctx, gm)
+ return
+ }
+ out := BuildNoticeTextOutputFromLicenseMetadata
+ if proptools.Bool(gm.properties.Xml) {
+ out = BuildNoticeXmlOutputFromLicenseMetadata
+ } else if proptools.Bool(gm.properties.Html) {
+ out = BuildNoticeHtmlOutputFromLicenseMetadata
+ }
+ defaultName := ""
+ if len(gm.properties.For) > 0 {
+ defaultName = gm.properties.For[0]
+ }
+
+ modules := make([]Module, 0)
+ for _, name := range gm.properties.For {
+ mods := ctx.ModuleVariantsFromName(gm, name)
+ for _, mod := range mods {
+ if mod == nil {
+ continue
+ }
+ modules = append(modules, mod)
+ }
+ }
+ if ctx.Failed() {
+ return
+ }
+ out(ctx, gm.output, proptools.StringDefault(gm.properties.ArtifactName, defaultName), "", modules...)
+ })
+}
+
+func GenNoticeBuildRulesFactory() Singleton {
+ return &genNoticeBuildRules{}
+}
+
+type genNoticeProperties struct {
+ // For specifies the modules for which to generate a notice file.
+ For []string
+ // ArtifactName specifies the internal name to use for the notice file.
+ // It appears in the "used by:" list for targets whose entire name is stripped by --strip_prefix.
+ ArtifactName *string
+ // Stem specifies the base name of the output file.
+ Stem *string `android:"arch_variant"`
+ // Html indicates an html-format file is needed. The default is text. Can be Html or Xml but not both.
+ Html *bool
+ // Xml indicates an xml-format file is needed. The default is text. Can be Html or Xml but not both.
+ Xml *bool
+ // Gzipped indicates the output file must be compressed with gzip. Will append .gz to suffix if not there.
+ Gzipped *bool
+ // Suffix specifies the file extension to use. Defaults to .html for html, .xml for xml, or no extension for text.
+ Suffix *string
+ // Visibility specifies where this license can be used
+ Visibility []string
+}
+
+type genNoticeModule struct {
+ ModuleBase
+ DefaultableModuleBase
+
+ properties genNoticeProperties
+
+ output OutputPath
+ missing []string
+}
+
+func (m *genNoticeModule) DepsMutator(ctx BottomUpMutatorContext) {
+ if proptools.Bool(m.properties.Html) && proptools.Bool(m.properties.Xml) {
+ ctx.ModuleErrorf("can be html or xml but not both")
+ }
+ if !ctx.Config().AllowMissingDependencies() {
+ var missing []string
+ // Verify the modules for which to generate notices exist.
+ for _, otherMod := range m.properties.For {
+ if !ctx.OtherModuleExists(otherMod) {
+ missing = append(missing, otherMod)
+ }
+ }
+ if len(missing) == 1 {
+ ctx.PropertyErrorf("for", "no %q module exists", missing[0])
+ } else if len(missing) > 1 {
+ ctx.PropertyErrorf("for", "modules \"%s\" do not exist", strings.Join(missing, "\", \""))
+ }
+ }
+}
+
+func (m *genNoticeModule) getStem() string {
+ stem := m.base().BaseModuleName()
+ if m.properties.Stem != nil {
+ stem = proptools.String(m.properties.Stem)
+ }
+ return stem
+}
+
+func (m *genNoticeModule) getSuffix() string {
+ suffix := ""
+ if m.properties.Suffix == nil {
+ if proptools.Bool(m.properties.Html) {
+ suffix = ".html"
+ } else if proptools.Bool(m.properties.Xml) {
+ suffix = ".xml"
+ }
+ } else {
+ suffix = proptools.String(m.properties.Suffix)
+ }
+ if proptools.Bool(m.properties.Gzipped) && !strings.HasSuffix(suffix, ".gz") {
+ suffix += ".gz"
+ }
+ return suffix
+}
+
+func (m *genNoticeModule) GenerateAndroidBuildActions(ctx ModuleContext) {
+ if ctx.Config().AllowMissingDependencies() {
+ // Verify the modules for which to generate notices exist.
+ for _, otherMod := range m.properties.For {
+ if !ctx.OtherModuleExists(otherMod) {
+ m.missing = append(m.missing, otherMod)
+ }
+ }
+ m.missing = append(m.missing, ctx.GetMissingDependencies()...)
+ m.missing = FirstUniqueStrings(m.missing)
+ }
+ out := m.getStem() + m.getSuffix()
+ m.output = PathForModuleOut(ctx, out).OutputPath
+}
+
+func GenNoticeFactory() Module {
+ module := &genNoticeModule{}
+
+ base := module.base()
+ module.AddProperties(&base.nameProperties, &module.properties)
+
+ // The visibility property needs to be checked and parsed by the visibility module.
+ setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
+
+ initAndroidModuleBase(module)
+ InitDefaultableModule(module)
+
+ return module
+}
+
+var _ OutputFileProducer = (*genNoticeModule)(nil)
+
+// Implements OutputFileProducer
+func (m *genNoticeModule) OutputFiles(tag string) (Paths, error) {
+ if tag == "" {
+ return Paths{m.output}, nil
+ }
+ return nil, fmt.Errorf("unrecognized tag %q", tag)
+}
+
+// missingReferencesRule emits an ErrorRule for missing module references.
+func missingReferencesRule(ctx BuilderContext, m *genNoticeModule) {
+ if len(m.missing) < 1 {
+ panic(fmt.Errorf("missing references rule requested with no missing references"))
+ }
+
+ ctx.Build(pctx, BuildParams{
+ Rule: ErrorRule,
+ Output: m.output,
+ Description: "notice for " + proptools.StringDefault(m.properties.ArtifactName, "container"),
+ Args: map[string]string{
+ "error": m.Name() + " references missing module(s): " + strings.Join(m.missing, ", "),
+ },
+ })
+}