blob: fda91ac945deee24f56e864ef560f8236bd06334 [file] [log] [blame]
Bob Badoureef4c1c2022-05-16 12:20:04 -07001// Copyright 2020 Google Inc. All rights reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package android
16
17import (
18 "fmt"
19 "strings"
20
21 "github.com/google/blueprint/proptools"
22)
23
24func init() {
25 RegisterGenNoticeBuildComponents(InitRegistrationContext)
26}
27
28// Register the gen_notice module type.
29func RegisterGenNoticeBuildComponents(ctx RegistrationContext) {
30 ctx.RegisterSingletonType("gen_notice_build_rules", GenNoticeBuildRulesFactory)
31 ctx.RegisterModuleType("gen_notice", GenNoticeFactory)
32}
33
34type genNoticeBuildRules struct{}
35
36func (s *genNoticeBuildRules) GenerateBuildActions(ctx SingletonContext) {
37 ctx.VisitAllModules(func(m Module) {
38 gm, ok := m.(*genNoticeModule)
39 if !ok {
40 return
41 }
42 if len(gm.missing) > 0 {
43 missingReferencesRule(ctx, gm)
44 return
45 }
46 out := BuildNoticeTextOutputFromLicenseMetadata
47 if proptools.Bool(gm.properties.Xml) {
48 out = BuildNoticeXmlOutputFromLicenseMetadata
49 } else if proptools.Bool(gm.properties.Html) {
50 out = BuildNoticeHtmlOutputFromLicenseMetadata
51 }
52 defaultName := ""
53 if len(gm.properties.For) > 0 {
54 defaultName = gm.properties.For[0]
55 }
56
57 modules := make([]Module, 0)
58 for _, name := range gm.properties.For {
59 mods := ctx.ModuleVariantsFromName(gm, name)
60 for _, mod := range mods {
61 if mod == nil {
62 continue
63 }
64 modules = append(modules, mod)
65 }
66 }
67 if ctx.Failed() {
68 return
69 }
Bob Badoura5ea2472022-05-20 16:37:26 -070070 out(ctx, gm.output, ctx.ModuleName(gm), proptools.StringDefault(gm.properties.ArtifactName, defaultName), "", modules...)
Bob Badoureef4c1c2022-05-16 12:20:04 -070071 })
72}
73
74func GenNoticeBuildRulesFactory() Singleton {
75 return &genNoticeBuildRules{}
76}
77
78type genNoticeProperties struct {
79 // For specifies the modules for which to generate a notice file.
80 For []string
81 // ArtifactName specifies the internal name to use for the notice file.
82 // It appears in the "used by:" list for targets whose entire name is stripped by --strip_prefix.
83 ArtifactName *string
84 // Stem specifies the base name of the output file.
85 Stem *string `android:"arch_variant"`
86 // Html indicates an html-format file is needed. The default is text. Can be Html or Xml but not both.
87 Html *bool
88 // Xml indicates an xml-format file is needed. The default is text. Can be Html or Xml but not both.
89 Xml *bool
90 // Gzipped indicates the output file must be compressed with gzip. Will append .gz to suffix if not there.
91 Gzipped *bool
92 // Suffix specifies the file extension to use. Defaults to .html for html, .xml for xml, or no extension for text.
93 Suffix *string
94 // Visibility specifies where this license can be used
95 Visibility []string
96}
97
98type genNoticeModule struct {
99 ModuleBase
100 DefaultableModuleBase
101
102 properties genNoticeProperties
103
104 output OutputPath
105 missing []string
106}
107
108func (m *genNoticeModule) DepsMutator(ctx BottomUpMutatorContext) {
109 if proptools.Bool(m.properties.Html) && proptools.Bool(m.properties.Xml) {
110 ctx.ModuleErrorf("can be html or xml but not both")
111 }
112 if !ctx.Config().AllowMissingDependencies() {
113 var missing []string
114 // Verify the modules for which to generate notices exist.
115 for _, otherMod := range m.properties.For {
116 if !ctx.OtherModuleExists(otherMod) {
117 missing = append(missing, otherMod)
118 }
119 }
120 if len(missing) == 1 {
121 ctx.PropertyErrorf("for", "no %q module exists", missing[0])
122 } else if len(missing) > 1 {
123 ctx.PropertyErrorf("for", "modules \"%s\" do not exist", strings.Join(missing, "\", \""))
124 }
125 }
126}
127
128func (m *genNoticeModule) getStem() string {
129 stem := m.base().BaseModuleName()
130 if m.properties.Stem != nil {
131 stem = proptools.String(m.properties.Stem)
132 }
133 return stem
134}
135
136func (m *genNoticeModule) getSuffix() string {
137 suffix := ""
138 if m.properties.Suffix == nil {
139 if proptools.Bool(m.properties.Html) {
140 suffix = ".html"
141 } else if proptools.Bool(m.properties.Xml) {
142 suffix = ".xml"
143 }
144 } else {
145 suffix = proptools.String(m.properties.Suffix)
146 }
147 if proptools.Bool(m.properties.Gzipped) && !strings.HasSuffix(suffix, ".gz") {
148 suffix += ".gz"
149 }
150 return suffix
151}
152
153func (m *genNoticeModule) GenerateAndroidBuildActions(ctx ModuleContext) {
154 if ctx.Config().AllowMissingDependencies() {
155 // Verify the modules for which to generate notices exist.
156 for _, otherMod := range m.properties.For {
157 if !ctx.OtherModuleExists(otherMod) {
158 m.missing = append(m.missing, otherMod)
159 }
160 }
161 m.missing = append(m.missing, ctx.GetMissingDependencies()...)
162 m.missing = FirstUniqueStrings(m.missing)
163 }
164 out := m.getStem() + m.getSuffix()
165 m.output = PathForModuleOut(ctx, out).OutputPath
166}
167
168func GenNoticeFactory() Module {
169 module := &genNoticeModule{}
170
171 base := module.base()
172 module.AddProperties(&base.nameProperties, &module.properties)
173
174 // The visibility property needs to be checked and parsed by the visibility module.
175 setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
176
177 initAndroidModuleBase(module)
178 InitDefaultableModule(module)
179
180 return module
181}
182
183var _ OutputFileProducer = (*genNoticeModule)(nil)
184
185// Implements OutputFileProducer
186func (m *genNoticeModule) OutputFiles(tag string) (Paths, error) {
187 if tag == "" {
188 return Paths{m.output}, nil
189 }
190 return nil, fmt.Errorf("unrecognized tag %q", tag)
191}
192
193// missingReferencesRule emits an ErrorRule for missing module references.
194func missingReferencesRule(ctx BuilderContext, m *genNoticeModule) {
195 if len(m.missing) < 1 {
196 panic(fmt.Errorf("missing references rule requested with no missing references"))
197 }
198
199 ctx.Build(pctx, BuildParams{
200 Rule: ErrorRule,
201 Output: m.output,
202 Description: "notice for " + proptools.StringDefault(m.properties.ArtifactName, "container"),
203 Args: map[string]string{
204 "error": m.Name() + " references missing module(s): " + strings.Join(m.missing, ", "),
205 },
206 })
207}