• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// 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	"path/filepath"
20	"strings"
21
22	"github.com/google/blueprint"
23	"github.com/google/blueprint/proptools"
24)
25
26func init() {
27	RegisterGenNoticeBuildComponents(InitRegistrationContext)
28}
29
30// Register the gen_notice module type.
31func RegisterGenNoticeBuildComponents(ctx RegistrationContext) {
32	ctx.RegisterParallelSingletonType("gen_notice_build_rules", GenNoticeBuildRulesFactory)
33	ctx.RegisterModuleType("gen_notice", GenNoticeFactory)
34}
35
36type genNoticeBuildRules struct{}
37
38func (s *genNoticeBuildRules) GenerateBuildActions(ctx SingletonContext) {
39	ctx.VisitAllModuleProxies(func(m ModuleProxy) {
40		gm, ok := OtherModuleProvider(ctx, m, GenNoticeInfoProvider)
41		if !ok {
42			return
43		}
44		if len(gm.Missing) > 0 {
45			missingReferencesRule(ctx, m, &gm)
46			return
47		}
48		out := BuildNoticeTextOutputFromLicenseMetadata
49		if gm.Xml {
50			out = BuildNoticeXmlOutputFromLicenseMetadata
51		} else if gm.Html {
52			out = BuildNoticeHtmlOutputFromLicenseMetadata
53		}
54		defaultName := ""
55		if len(gm.For) > 0 {
56			defaultName = gm.For[0]
57		}
58
59		modules := make([]ModuleProxy, 0)
60		for _, name := range gm.For {
61			mods := ctx.ModuleVariantsFromName(m, name)
62			for _, mod := range mods {
63				if !OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider).Enabled { // don't depend on variants without build rules
64					continue
65				}
66				modules = append(modules, mod)
67			}
68		}
69		if ctx.Failed() {
70			return
71		}
72		out(ctx, gm.Output, ctx.ModuleName(m),
73			proptools.StringDefault(gm.ArtifactName, defaultName),
74			[]string{
75				filepath.Join(ctx.Config().OutDir(), "target", "product", ctx.Config().DeviceName()) + "/",
76				ctx.Config().OutDir() + "/",
77				ctx.Config().SoongOutDir() + "/",
78			}, modules...)
79	})
80}
81
82func GenNoticeBuildRulesFactory() Singleton {
83	return &genNoticeBuildRules{}
84}
85
86type genNoticeProperties struct {
87	// For specifies the modules for which to generate a notice file.
88	For []string
89	// ArtifactName specifies the internal name to use for the notice file.
90	// It appears in the "used by:" list for targets whose entire name is stripped by --strip_prefix.
91	ArtifactName *string
92	// Stem specifies the base name of the output file.
93	Stem *string `android:"arch_variant"`
94	// Html indicates an html-format file is needed. The default is text. Can be Html or Xml but not both.
95	Html *bool
96	// Xml indicates an xml-format file is needed. The default is text. Can be Html or Xml but not both.
97	Xml *bool
98	// Gzipped indicates the output file must be compressed with gzip. Will append .gz to suffix if not there.
99	Gzipped *bool
100	// Suffix specifies the file extension to use. Defaults to .html for html, .xml for xml, or no extension for text.
101	Suffix *string
102	// Visibility specifies where this license can be used
103	Visibility []string
104}
105
106type genNoticeModule struct {
107	ModuleBase
108	DefaultableModuleBase
109
110	properties genNoticeProperties
111
112	output  OutputPath
113	missing []string
114}
115
116type GenNoticeInfo struct {
117	// For specifies the modules for which to generate a notice file.
118	For []string
119	// ArtifactName specifies the internal name to use for the notice file.
120	// It appears in the "used by:" list for targets whose entire name is stripped by --strip_prefix.
121	ArtifactName *string
122	// Html indicates an html-format file is needed. The default is text. Can be Html or Xml but not both.
123	Html bool
124	// Xml indicates an xml-format file is needed. The default is text. Can be Html or Xml but not both.
125	Xml     bool
126	Output  OutputPath
127	Missing []string
128}
129
130var GenNoticeInfoProvider = blueprint.NewProvider[GenNoticeInfo]()
131
132func (m *genNoticeModule) DepsMutator(ctx BottomUpMutatorContext) {
133	if ctx.ContainsProperty("licenses") {
134		ctx.PropertyErrorf("licenses", "not supported on \"gen_notice\" modules")
135	}
136	if proptools.Bool(m.properties.Html) && proptools.Bool(m.properties.Xml) {
137		ctx.ModuleErrorf("can be html or xml but not both")
138	}
139	if !ctx.Config().AllowMissingDependencies() {
140		var missing []string
141		// Verify the modules for which to generate notices exist.
142		for _, otherMod := range m.properties.For {
143			if !ctx.OtherModuleExists(otherMod) {
144				missing = append(missing, otherMod)
145			}
146		}
147		if len(missing) == 1 {
148			ctx.PropertyErrorf("for", "no %q module exists", missing[0])
149		} else if len(missing) > 1 {
150			ctx.PropertyErrorf("for", "modules \"%s\" do not exist", strings.Join(missing, "\", \""))
151		}
152	}
153}
154
155func (m *genNoticeModule) getStem() string {
156	stem := m.base().BaseModuleName()
157	if m.properties.Stem != nil {
158		stem = proptools.String(m.properties.Stem)
159	}
160	return stem
161}
162
163func (m *genNoticeModule) getSuffix() string {
164	suffix := ""
165	if m.properties.Suffix == nil {
166		if proptools.Bool(m.properties.Html) {
167			suffix = ".html"
168		} else if proptools.Bool(m.properties.Xml) {
169			suffix = ".xml"
170		}
171	} else {
172		suffix = proptools.String(m.properties.Suffix)
173	}
174	if proptools.Bool(m.properties.Gzipped) && !strings.HasSuffix(suffix, ".gz") {
175		suffix += ".gz"
176	}
177	return suffix
178}
179
180func (m *genNoticeModule) GenerateAndroidBuildActions(ctx ModuleContext) {
181	if ctx.Config().AllowMissingDependencies() {
182		// Verify the modules for which to generate notices exist.
183		for _, otherMod := range m.properties.For {
184			if !ctx.OtherModuleExists(otherMod) {
185				m.missing = append(m.missing, otherMod)
186			}
187		}
188		m.missing = append(m.missing, ctx.GetMissingDependencies()...)
189		m.missing = FirstUniqueStrings(m.missing)
190	}
191	out := m.getStem() + m.getSuffix()
192	m.output = PathForModuleOut(ctx, out).OutputPath
193
194	SetProvider(ctx, GenNoticeInfoProvider, GenNoticeInfo{
195		For:          m.properties.For,
196		ArtifactName: m.properties.ArtifactName,
197		Xml:          proptools.Bool(m.properties.Xml),
198		Html:         proptools.Bool(m.properties.Html),
199		Output:       m.output,
200		Missing:      m.missing,
201	})
202	ctx.SetOutputFiles(Paths{m.output}, "")
203}
204
205func GenNoticeFactory() Module {
206	module := &genNoticeModule{}
207
208	base := module.base()
209	module.AddProperties(&base.nameProperties, &module.properties)
210
211	// The visibility property needs to be checked and parsed by the visibility module.
212	setPrimaryVisibilityProperty(module, "visibility", &module.properties.Visibility)
213
214	InitAndroidArchModule(module, DeviceSupported, MultilibCommon)
215	InitDefaultableModule(module)
216
217	return module
218}
219
220var _ AndroidMkEntriesProvider = (*genNoticeModule)(nil)
221
222// Implements AndroidMkEntriesProvider
223func (m *genNoticeModule) AndroidMkEntries() []AndroidMkEntries {
224	return []AndroidMkEntries{AndroidMkEntries{
225		Class:      "ETC",
226		OutputFile: OptionalPathForPath(m.output),
227	}}
228}
229
230// missingReferencesRule emits an ErrorRule for missing module references.
231func missingReferencesRule(ctx BuilderContext, m ModuleProxy, genInfo *GenNoticeInfo) {
232	if len(genInfo.Missing) < 1 {
233		panic(fmt.Errorf("missing references rule requested with no missing references"))
234	}
235
236	ctx.Build(pctx, BuildParams{
237		Rule:        ErrorRule,
238		Output:      genInfo.Output,
239		Description: "notice for " + proptools.StringDefault(genInfo.ArtifactName, "container"),
240		Args: map[string]string{
241			"error": m.Name() + " references missing module(s): " + strings.Join(genInfo.Missing, ", "),
242		},
243	})
244}
245