• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2021 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	"sort"
19	"strings"
20
21	"github.com/google/blueprint"
22	"github.com/google/blueprint/proptools"
23)
24
25var (
26	_ = pctx.HostBinToolVariable("licenseMetadataCmd", "build_license_metadata")
27
28	licenseMetadataRule = pctx.AndroidStaticRule("licenseMetadataRule", blueprint.RuleParams{
29		Command:        "${licenseMetadataCmd} -o $out @${out}.rsp",
30		CommandDeps:    []string{"${licenseMetadataCmd}"},
31		Rspfile:        "${out}.rsp",
32		RspfileContent: "${args}",
33	}, "args")
34)
35
36func buildLicenseMetadata(ctx ModuleContext, licenseMetadataFile WritablePath) {
37	base := ctx.Module().base()
38
39	if !base.Enabled() {
40		return
41	}
42
43	if exemptFromRequiredApplicableLicensesProperty(ctx.Module()) {
44		return
45	}
46
47	var outputFiles Paths
48	if outputFileProducer, ok := ctx.Module().(OutputFileProducer); ok {
49		outputFiles, _ = outputFileProducer.OutputFiles("")
50		outputFiles = PathsIfNonNil(outputFiles...)
51	}
52
53	isContainer := isContainerFromFileExtensions(base.installFiles, outputFiles)
54
55	var allDepMetadataFiles Paths
56	var allDepMetadataArgs []string
57	var allDepOutputFiles Paths
58	var allDepMetadataDepSets []*PathsDepSet
59
60	ctx.VisitDirectDepsBlueprint(func(bpdep blueprint.Module) {
61		dep, _ := bpdep.(Module)
62		if dep == nil {
63			return
64		}
65		if !dep.Enabled() {
66			return
67		}
68
69		// Defaults add properties and dependencies that get processed on their own.
70		if ctx.OtherModuleDependencyTag(dep) == DefaultsDepTag {
71			return
72		}
73
74		if ctx.OtherModuleHasProvider(dep, LicenseMetadataProvider) {
75			info := ctx.OtherModuleProvider(dep, LicenseMetadataProvider).(*LicenseMetadataInfo)
76			allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath)
77			if isContainer || isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) {
78				allDepMetadataDepSets = append(allDepMetadataDepSets, info.LicenseMetadataDepSet)
79			}
80
81			depAnnotations := licenseAnnotationsFromTag(ctx.OtherModuleDependencyTag(dep))
82
83			allDepMetadataArgs = append(allDepMetadataArgs, info.LicenseMetadataPath.String()+depAnnotations)
84
85			if depInstallFiles := dep.base().installFiles; len(depInstallFiles) > 0 {
86				allDepOutputFiles = append(allDepOutputFiles, depInstallFiles.Paths()...)
87			} else if depOutputFiles, err := outputFilesForModule(ctx, dep, ""); err == nil {
88				depOutputFiles = PathsIfNonNil(depOutputFiles...)
89				allDepOutputFiles = append(allDepOutputFiles, depOutputFiles...)
90			}
91		}
92	})
93
94	allDepMetadataFiles = SortedUniquePaths(allDepMetadataFiles)
95	sort.Strings(allDepMetadataArgs)
96	allDepOutputFiles = SortedUniquePaths(allDepOutputFiles)
97
98	var orderOnlyDeps Paths
99	var args []string
100
101	if n := ctx.ModuleName(); n != "" {
102		args = append(args,
103			"-mn "+proptools.NinjaAndShellEscape(n))
104	}
105
106	if t := ctx.ModuleType(); t != "" {
107		args = append(args,
108			"-mt "+proptools.NinjaAndShellEscape(t))
109	}
110
111	args = append(args,
112		"-r "+proptools.NinjaAndShellEscape(ctx.ModuleDir()),
113		"-mc UNKNOWN")
114
115	if p := base.commonProperties.Effective_package_name; p != nil {
116		args = append(args,
117			`-p `+proptools.NinjaAndShellEscapeIncludingSpaces(*p))
118	}
119
120	args = append(args,
121		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_kinds), "-k "))
122
123	args = append(args,
124		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_conditions), "-c "))
125
126	args = append(args,
127		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.commonProperties.Effective_license_text.Strings()), "-n "))
128
129	if isContainer {
130		transitiveDeps := newPathsDepSet(nil, allDepMetadataDepSets).ToList()
131		args = append(args,
132			JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(transitiveDeps.Strings()), "-d "))
133		orderOnlyDeps = append(orderOnlyDeps, transitiveDeps...)
134	} else {
135		args = append(args,
136			JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepMetadataArgs), "-d "))
137		orderOnlyDeps = append(orderOnlyDeps, allDepMetadataFiles...)
138	}
139
140	args = append(args,
141		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(allDepOutputFiles.Strings()), "-s "))
142
143	// Install map
144	args = append(args,
145		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.licenseInstallMap), "-m "))
146
147	// Built files
148	if len(outputFiles) > 0 {
149		args = append(args,
150			JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(outputFiles.Strings()), "-t "))
151	}
152
153	// Installed files
154	args = append(args,
155		JoinWithPrefix(proptools.NinjaAndShellEscapeListIncludingSpaces(base.installFiles.Strings()), "-i "))
156
157	if isContainer {
158		args = append(args, "--is_container")
159	}
160
161	ctx.Build(pctx, BuildParams{
162		Rule:        licenseMetadataRule,
163		Output:      licenseMetadataFile,
164		OrderOnly:   orderOnlyDeps,
165		Description: "license metadata",
166		Args: map[string]string{
167			"args": strings.Join(args, " "),
168		},
169	})
170
171	ctx.SetProvider(LicenseMetadataProvider, &LicenseMetadataInfo{
172		LicenseMetadataPath:   licenseMetadataFile,
173		LicenseMetadataDepSet: newPathsDepSet(Paths{licenseMetadataFile}, allDepMetadataDepSets),
174	})
175}
176
177func isContainerFromFileExtensions(installPaths InstallPaths, builtPaths Paths) bool {
178	var paths Paths
179	if len(installPaths) > 0 {
180		paths = installPaths.Paths()
181	} else {
182		paths = builtPaths
183	}
184
185	for _, path := range paths {
186		switch path.Ext() {
187		case ".zip", ".tar", ".tgz", ".tar.gz", ".img", ".srcszip", ".apex":
188			return true
189		}
190	}
191
192	return false
193}
194
195// LicenseMetadataProvider is used to propagate license metadata paths between modules.
196var LicenseMetadataProvider = blueprint.NewProvider(&LicenseMetadataInfo{})
197
198// LicenseMetadataInfo stores the license metadata path for a module.
199type LicenseMetadataInfo struct {
200	LicenseMetadataPath   Path
201	LicenseMetadataDepSet *PathsDepSet
202}
203
204// licenseAnnotationsFromTag returns the LicenseAnnotations for a tag (if any) converted into
205// a string, or an empty string if there are none.
206func licenseAnnotationsFromTag(tag blueprint.DependencyTag) string {
207	if annoTag, ok := tag.(LicenseAnnotationsDependencyTag); ok {
208		annos := annoTag.LicenseAnnotations()
209		if len(annos) > 0 {
210			annoStrings := make([]string, len(annos))
211			for i, s := range annos {
212				annoStrings[i] = string(s)
213			}
214			return ":" + strings.Join(annoStrings, ",")
215		}
216	}
217	return ""
218}
219
220// LicenseAnnotationsDependencyTag is implemented by dependency tags in order to provide a
221// list of license dependency annotations.
222type LicenseAnnotationsDependencyTag interface {
223	LicenseAnnotations() []LicenseAnnotation
224}
225
226// LicenseAnnotation is an enum of annotations that can be applied to dependencies for propagating
227// license information.
228type LicenseAnnotation string
229
230const (
231	// LicenseAnnotationSharedDependency should be returned by LicenseAnnotations implementations
232	// of dependency tags when the usage of the dependency is dynamic, for example a shared library
233	// linkage for native modules or as a classpath library for java modules.
234	//
235	// Dependency tags that need to always return LicenseAnnotationSharedDependency
236	// can embed LicenseAnnotationSharedDependencyTag to implement LicenseAnnotations.
237	LicenseAnnotationSharedDependency LicenseAnnotation = "dynamic"
238
239	// LicenseAnnotationToolchain should be returned by LicenseAnnotations implementations of
240	// dependency tags when the dependency is used as a toolchain.
241	//
242	// Dependency tags that need to always return LicenseAnnotationToolchain
243	// can embed LicenseAnnotationToolchainDependencyTag to implement LicenseAnnotations.
244	LicenseAnnotationToolchain LicenseAnnotation = "toolchain"
245)
246
247// LicenseAnnotationSharedDependencyTag can be embedded in a dependency tag to implement
248// LicenseAnnotations that always returns LicenseAnnotationSharedDependency.
249type LicenseAnnotationSharedDependencyTag struct{}
250
251func (LicenseAnnotationSharedDependencyTag) LicenseAnnotations() []LicenseAnnotation {
252	return []LicenseAnnotation{LicenseAnnotationSharedDependency}
253}
254
255// LicenseAnnotationToolchainDependencyTag can be embedded in a dependency tag to implement
256// LicenseAnnotations that always returns LicenseAnnotationToolchain.
257type LicenseAnnotationToolchainDependencyTag struct{}
258
259func (LicenseAnnotationToolchainDependencyTag) LicenseAnnotations() []LicenseAnnotation {
260	return []LicenseAnnotation{LicenseAnnotationToolchain}
261}
262