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