|  | // 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.RegisterParallelSingletonType("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, ", "), | 
|  | }, | 
|  | }) | 
|  | } |