// 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" "path/filepath" "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 } if !mod.Enabled() { // don't depend on variants without build rules continue } modules = append(modules, mod) } } if ctx.Failed() { return } out(ctx, gm.output, ctx.ModuleName(gm), proptools.StringDefault(gm.properties.ArtifactName, defaultName), []string{ filepath.Join(ctx.Config().OutDir(), "target", "product", ctx.Config().DeviceName()) + "/", ctx.Config().OutDir() + "/", ctx.Config().SoongOutDir() + "/", }, 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 ctx.ContainsProperty("licenses") { ctx.PropertyErrorf("licenses", "not supported on \"gen_notice\" modules") } 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) InitAndroidArchModule(module, DeviceSupported, MultilibCommon) 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) } var _ AndroidMkEntriesProvider = (*genNoticeModule)(nil) // Implements AndroidMkEntriesProvider func (m *genNoticeModule) AndroidMkEntries() []AndroidMkEntries { return []AndroidMkEntries{AndroidMkEntries{ Class: "ETC", OutputFile: OptionalPathForPath(m.output), }} } // 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, ", "), }, }) }