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