blob: 3a210cc0b0d5c8dcb26c5b7627509eb62d0a1dec [file] [log] [blame]
Colin Cross014489c2020-06-02 20:09:13 -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 java
16
17import (
18 "fmt"
19 "sort"
Colin Cross988dfcc2020-07-16 17:32:17 -070020 "strings"
Colin Cross014489c2020-06-02 20:09:13 -070021
22 "android/soong/android"
23)
24
25type LintProperties struct {
26 // Controls for running Android Lint on the module.
27 Lint struct {
28
29 // If true, run Android Lint on the module. Defaults to true.
30 Enabled *bool
31
32 // Flags to pass to the Android Lint tool.
33 Flags []string
34
35 // Checks that should be treated as fatal.
36 Fatal_checks []string
37
38 // Checks that should be treated as errors.
39 Error_checks []string
40
41 // Checks that should be treated as warnings.
42 Warning_checks []string
43
44 // Checks that should be skipped.
45 Disabled_checks []string
Colin Cross92e4b462020-06-18 15:56:48 -070046
47 // Modules that provide extra lint checks
48 Extra_check_modules []string
Colin Cross014489c2020-06-02 20:09:13 -070049 }
50}
51
52type linter struct {
53 name string
54 manifest android.Path
55 mergedManifest android.Path
56 srcs android.Paths
57 srcJars android.Paths
58 resources android.Paths
59 classpath android.Paths
60 classes android.Path
61 extraLintCheckJars android.Paths
62 test bool
63 library bool
64 minSdkVersion string
65 targetSdkVersion string
66 compileSdkVersion string
67 javaLanguageLevel string
68 kotlinLanguageLevel string
69 outputs lintOutputs
70 properties LintProperties
Colin Crossc0efd1d2020-07-03 11:56:24 -070071
Colin Cross08dca382020-07-21 20:31:17 -070072 reports android.Paths
73
Colin Crossc0efd1d2020-07-03 11:56:24 -070074 buildModuleReportZip bool
Colin Cross014489c2020-06-02 20:09:13 -070075}
76
77type lintOutputs struct {
Colin Cross08dca382020-07-21 20:31:17 -070078 html android.Path
79 text android.Path
80 xml android.Path
Colin Crossc0efd1d2020-07-03 11:56:24 -070081
Colin Cross08dca382020-07-21 20:31:17 -070082 depSets LintDepSets
Colin Crossc0efd1d2020-07-03 11:56:24 -070083}
84
Colin Cross08dca382020-07-21 20:31:17 -070085type lintOutputsIntf interface {
Colin Crossc0efd1d2020-07-03 11:56:24 -070086 lintOutputs() *lintOutputs
87}
88
Colin Cross08dca382020-07-21 20:31:17 -070089type lintDepSetsIntf interface {
90 LintDepSets() LintDepSets
91}
92
93type LintDepSets struct {
94 HTML, Text, XML *android.DepSet
95}
96
97type LintDepSetsBuilder struct {
98 HTML, Text, XML *android.DepSetBuilder
99}
100
101func NewLintDepSetBuilder() LintDepSetsBuilder {
102 return LintDepSetsBuilder{
103 HTML: android.NewDepSetBuilder(android.POSTORDER),
104 Text: android.NewDepSetBuilder(android.POSTORDER),
105 XML: android.NewDepSetBuilder(android.POSTORDER),
106 }
107}
108
109func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
110 l.HTML.Direct(html)
111 l.Text.Direct(text)
112 l.XML.Direct(xml)
113 return l
114}
115
116func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
117 if depSets.HTML != nil {
118 l.HTML.Transitive(depSets.HTML)
119 }
120 if depSets.Text != nil {
121 l.Text.Transitive(depSets.Text)
122 }
123 if depSets.XML != nil {
124 l.XML.Transitive(depSets.XML)
125 }
126 return l
127}
128
129func (l LintDepSetsBuilder) Build() LintDepSets {
130 return LintDepSets{
131 HTML: l.HTML.Build(),
132 Text: l.Text.Build(),
133 XML: l.XML.Build(),
134 }
135}
136
137func (l *linter) LintDepSets() LintDepSets {
138 return l.outputs.depSets
139}
140
141var _ lintDepSetsIntf = (*linter)(nil)
142
143var _ lintOutputsIntf = (*linter)(nil)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700144
145func (l *linter) lintOutputs() *lintOutputs {
146 return &l.outputs
Colin Cross014489c2020-06-02 20:09:13 -0700147}
148
149func (l *linter) enabled() bool {
150 return BoolDefault(l.properties.Lint.Enabled, true)
151}
152
Colin Cross92e4b462020-06-18 15:56:48 -0700153func (l *linter) deps(ctx android.BottomUpMutatorContext) {
154 if !l.enabled() {
155 return
156 }
157
Colin Cross988dfcc2020-07-16 17:32:17 -0700158 extraCheckModules := l.properties.Lint.Extra_check_modules
159
160 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
161 if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
162 extraCheckModules = strings.Split(checkOnlyModules, ",")
163 }
164 }
165
166 ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
167 extraLintCheckTag, extraCheckModules...)
Colin Cross92e4b462020-06-18 15:56:48 -0700168}
169
Colin Cross014489c2020-06-02 20:09:13 -0700170func (l *linter) writeLintProjectXML(ctx android.ModuleContext,
Colin Cross977b6a82020-06-23 10:22:49 -0700171 rule *android.RuleBuilder) (projectXMLPath, configXMLPath, cacheDir, homeDir android.WritablePath, deps android.Paths) {
Colin Cross014489c2020-06-02 20:09:13 -0700172
173 var resourcesList android.WritablePath
174 if len(l.resources) > 0 {
175 // The list of resources may be too long to put on the command line, but
176 // we can't use the rsp file because it is already being used for srcs.
177 // Insert a second rule to write out the list of resources to a file.
178 resourcesList = android.PathForModuleOut(ctx, "lint", "resources.list")
179 resListRule := android.NewRuleBuilder()
180 resListRule.Command().Text("cp").FlagWithRspFileInputList("", l.resources).Output(resourcesList)
181 resListRule.Build(pctx, ctx, "lint_resources_list", "lint resources list")
182 deps = append(deps, l.resources...)
183 }
184
185 projectXMLPath = android.PathForModuleOut(ctx, "lint", "project.xml")
186 // Lint looks for a lint.xml file next to the project.xml file, give it one.
187 configXMLPath = android.PathForModuleOut(ctx, "lint", "lint.xml")
188 cacheDir = android.PathForModuleOut(ctx, "lint", "cache")
Colin Cross977b6a82020-06-23 10:22:49 -0700189 homeDir = android.PathForModuleOut(ctx, "lint", "home")
Colin Cross014489c2020-06-02 20:09:13 -0700190
191 srcJarDir := android.PathForModuleOut(ctx, "lint-srcjars")
192 srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
193
194 cmd := rule.Command().
195 BuiltTool(ctx, "lint-project-xml").
196 FlagWithOutput("--project_out ", projectXMLPath).
197 FlagWithOutput("--config_out ", configXMLPath).
198 FlagWithArg("--name ", ctx.ModuleName())
199
200 if l.library {
201 cmd.Flag("--library")
202 }
203 if l.test {
204 cmd.Flag("--test")
205 }
206 if l.manifest != nil {
207 deps = append(deps, l.manifest)
208 cmd.FlagWithArg("--manifest ", l.manifest.String())
209 }
210 if l.mergedManifest != nil {
211 deps = append(deps, l.mergedManifest)
212 cmd.FlagWithArg("--merged_manifest ", l.mergedManifest.String())
213 }
214
215 // TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
216 // lint separately.
217 cmd.FlagWithRspFileInputList("--srcs ", l.srcs)
218 deps = append(deps, l.srcs...)
219
220 cmd.FlagWithInput("--generated_srcs ", srcJarList)
221 deps = append(deps, l.srcJars...)
222
223 if resourcesList != nil {
224 cmd.FlagWithInput("--resources ", resourcesList)
225 }
226
227 if l.classes != nil {
228 deps = append(deps, l.classes)
229 cmd.FlagWithArg("--classes ", l.classes.String())
230 }
231
232 cmd.FlagForEachArg("--classpath ", l.classpath.Strings())
233 deps = append(deps, l.classpath...)
234
235 cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings())
236 deps = append(deps, l.extraLintCheckJars...)
237
Colin Crossc31efeb2020-06-23 10:25:26 -0700238 cmd.FlagWithArg("--root_dir ", "$PWD")
239
240 // The cache tag in project.xml is relative to the root dir, or the project.xml file if
241 // the root dir is not set.
242 cmd.FlagWithArg("--cache_dir ", cacheDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700243
244 cmd.FlagWithInput("@",
245 android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
246
247 cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
248 cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
249 cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
250 cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
251
Colin Cross977b6a82020-06-23 10:22:49 -0700252 return projectXMLPath, configXMLPath, cacheDir, homeDir, deps
Colin Cross014489c2020-06-02 20:09:13 -0700253}
254
Liz Kammer20ebfb42020-07-28 11:32:07 -0700255// generateManifest adds a command to the rule to write a simple manifest that contains the
Colin Cross014489c2020-06-02 20:09:13 -0700256// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
257func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path {
258 manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
259
260 rule.Command().Text("(").
261 Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
262 Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
263 Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
264 Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
265 l.minSdkVersion, l.targetSdkVersion).
266 Text(`echo "</manifest>"`).
267 Text(") >").Output(manifestPath)
268
269 return manifestPath
270}
271
272func (l *linter) lint(ctx android.ModuleContext) {
273 if !l.enabled() {
274 return
275 }
276
Colin Cross92e4b462020-06-18 15:56:48 -0700277 extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
278 for _, extraLintCheckModule := range extraLintCheckModules {
279 if dep, ok := extraLintCheckModule.(Dependency); ok {
280 l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars()...)
281 } else {
282 ctx.PropertyErrorf("lint.extra_check_modules",
283 "%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
284 }
285 }
286
Colin Cross014489c2020-06-02 20:09:13 -0700287 rule := android.NewRuleBuilder()
288
289 if l.manifest == nil {
290 manifest := l.generateManifest(ctx, rule)
291 l.manifest = manifest
292 }
293
Colin Cross977b6a82020-06-23 10:22:49 -0700294 projectXML, lintXML, cacheDir, homeDir, deps := l.writeLintProjectXML(ctx, rule)
Colin Cross014489c2020-06-02 20:09:13 -0700295
Colin Crossc0efd1d2020-07-03 11:56:24 -0700296 html := android.PathForModuleOut(ctx, "lint-report.html")
297 text := android.PathForModuleOut(ctx, "lint-report.txt")
298 xml := android.PathForModuleOut(ctx, "lint-report.xml")
299
Colin Cross08dca382020-07-21 20:31:17 -0700300 depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700301
302 ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
Colin Cross08dca382020-07-21 20:31:17 -0700303 if depLint, ok := dep.(lintDepSetsIntf); ok {
304 depSetsBuilder.Transitive(depLint.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700305 }
306 })
Colin Cross014489c2020-06-02 20:09:13 -0700307
Colin Cross977b6a82020-06-23 10:22:49 -0700308 rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
309 rule.Command().Text("mkdir -p").Flag(cacheDir.String()).Flag(homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700310
Colin Cross8a6ed372020-07-06 11:45:51 -0700311 var annotationsZipPath, apiVersionsXMLPath android.Path
Jeongik Cha816a23a2020-07-08 01:09:23 +0900312 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross8a6ed372020-07-06 11:45:51 -0700313 annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
314 apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
315 } else {
316 annotationsZipPath = copiedAnnotationsZipPath(ctx)
317 apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
318 }
319
Colin Cross988dfcc2020-07-16 17:32:17 -0700320 cmd := rule.Command().
Colin Cross014489c2020-06-02 20:09:13 -0700321 Text("(").
Colin Crosse2221792020-07-13 13:23:00 -0700322 Flag("JAVA_OPTS=-Xmx3072m").
Colin Cross977b6a82020-06-23 10:22:49 -0700323 FlagWithArg("ANDROID_SDK_HOME=", homeDir.String()).
Colin Cross8a6ed372020-07-06 11:45:51 -0700324 FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
325 FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath).
Colin Cross014489c2020-06-02 20:09:13 -0700326 Tool(android.PathForSource(ctx, "prebuilts/cmdline-tools/tools/bin/lint")).
327 Implicit(android.PathForSource(ctx, "prebuilts/cmdline-tools/tools/lib/lint-classpath.jar")).
328 Flag("--quiet").
329 FlagWithInput("--project ", projectXML).
330 FlagWithInput("--config ", lintXML).
Colin Crossc0efd1d2020-07-03 11:56:24 -0700331 FlagWithOutput("--html ", html).
332 FlagWithOutput("--text ", text).
333 FlagWithOutput("--xml ", xml).
Colin Cross014489c2020-06-02 20:09:13 -0700334 FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
335 FlagWithArg("--java-language-level ", l.javaLanguageLevel).
336 FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
337 FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
338 Flag("--exitcode").
339 Flags(l.properties.Lint.Flags).
Colin Cross988dfcc2020-07-16 17:32:17 -0700340 Implicits(deps)
341
342 if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
343 cmd.FlagWithArg("--check ", checkOnly)
344 }
345
346 cmd.Text("|| (").Text("cat").Input(text).Text("; exit 7)").Text(")")
Colin Cross014489c2020-06-02 20:09:13 -0700347
Colin Cross977b6a82020-06-23 10:22:49 -0700348 rule.Command().Text("rm -rf").Flag(cacheDir.String()).Flag(homeDir.String())
Colin Cross014489c2020-06-02 20:09:13 -0700349
350 rule.Build(pctx, ctx, "lint", "lint")
Colin Cross014489c2020-06-02 20:09:13 -0700351
Colin Crossc0efd1d2020-07-03 11:56:24 -0700352 l.outputs = lintOutputs{
353 html: html,
354 text: text,
355 xml: xml,
Colin Cross014489c2020-06-02 20:09:13 -0700356
Colin Cross08dca382020-07-21 20:31:17 -0700357 depSets: depSetsBuilder.Build(),
Colin Crossc0efd1d2020-07-03 11:56:24 -0700358 }
Colin Cross014489c2020-06-02 20:09:13 -0700359
Colin Crossc0efd1d2020-07-03 11:56:24 -0700360 if l.buildModuleReportZip {
Colin Cross08dca382020-07-21 20:31:17 -0700361 l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
Colin Crossc0efd1d2020-07-03 11:56:24 -0700362 }
363}
Colin Cross014489c2020-06-02 20:09:13 -0700364
Colin Cross08dca382020-07-21 20:31:17 -0700365func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
366 htmlList := depSets.HTML.ToSortedList()
367 textList := depSets.Text.ToSortedList()
368 xmlList := depSets.XML.ToSortedList()
369
370 if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
371 return nil
372 }
373
374 htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
375 lintZip(ctx, htmlList, htmlZip)
376
377 textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
378 lintZip(ctx, textList, textZip)
379
380 xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
381 lintZip(ctx, xmlList, xmlZip)
382
383 return android.Paths{htmlZip, textZip, xmlZip}
384}
385
Colin Cross014489c2020-06-02 20:09:13 -0700386type lintSingleton struct {
387 htmlZip android.WritablePath
388 textZip android.WritablePath
389 xmlZip android.WritablePath
390}
391
392func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
393 l.generateLintReportZips(ctx)
394 l.copyLintDependencies(ctx)
395}
396
397func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
Jeongik Cha816a23a2020-07-08 01:09:23 +0900398 if ctx.Config().AlwaysUsePrebuiltSdks() {
Colin Cross014489c2020-06-02 20:09:13 -0700399 return
400 }
401
402 var frameworkDocStubs android.Module
403 ctx.VisitAllModules(func(m android.Module) {
404 if ctx.ModuleName(m) == "framework-doc-stubs" {
405 if frameworkDocStubs == nil {
406 frameworkDocStubs = m
407 } else {
408 ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
409 ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
410 }
411 }
412 })
413
414 if frameworkDocStubs == nil {
415 if !ctx.Config().AllowMissingDependencies() {
416 ctx.Errorf("lint: missing framework-doc-stubs")
417 }
418 return
419 }
420
421 ctx.Build(pctx, android.BuildParams{
422 Rule: android.Cp,
423 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700424 Output: copiedAnnotationsZipPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700425 })
426
427 ctx.Build(pctx, android.BuildParams{
428 Rule: android.Cp,
429 Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
Colin Cross8a6ed372020-07-06 11:45:51 -0700430 Output: copiedAPIVersionsXmlPath(ctx),
Colin Cross014489c2020-06-02 20:09:13 -0700431 })
432}
433
Colin Cross8a6ed372020-07-06 11:45:51 -0700434func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700435 return android.PathForOutput(ctx, "lint", "annotations.zip")
436}
437
Colin Cross8a6ed372020-07-06 11:45:51 -0700438func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
Colin Cross014489c2020-06-02 20:09:13 -0700439 return android.PathForOutput(ctx, "lint", "api_versions.xml")
440}
441
442func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700443 if ctx.Config().UnbundledBuild() {
444 return
445 }
446
Colin Cross014489c2020-06-02 20:09:13 -0700447 var outputs []*lintOutputs
448 var dirs []string
449 ctx.VisitAllModules(func(m android.Module) {
450 if ctx.Config().EmbeddedInMake() && !m.ExportedToMake() {
451 return
452 }
453
454 if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() && apex.IsForPlatform() {
455 // There are stray platform variants of modules in apexes that are not available for
456 // the platform, and they sometimes can't be built. Don't depend on them.
457 return
458 }
459
Colin Cross08dca382020-07-21 20:31:17 -0700460 if l, ok := m.(lintOutputsIntf); ok {
Colin Cross014489c2020-06-02 20:09:13 -0700461 outputs = append(outputs, l.lintOutputs())
462 }
463 })
464
465 dirs = android.SortedUniqueStrings(dirs)
466
467 zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
468 var paths android.Paths
469
470 for _, output := range outputs {
Colin Cross08dca382020-07-21 20:31:17 -0700471 if p := get(output); p != nil {
472 paths = append(paths, p)
473 }
Colin Cross014489c2020-06-02 20:09:13 -0700474 }
475
Colin Crossc0efd1d2020-07-03 11:56:24 -0700476 lintZip(ctx, paths, outputPath)
Colin Cross014489c2020-06-02 20:09:13 -0700477 }
478
479 l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
480 zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
481
482 l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
483 zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
484
485 l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
486 zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
487
488 ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
489}
490
491func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
Colin Cross8a6ed372020-07-06 11:45:51 -0700492 if !ctx.Config().UnbundledBuild() {
493 ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
494 }
Colin Cross014489c2020-06-02 20:09:13 -0700495}
496
497var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
498
499func init() {
500 android.RegisterSingletonType("lint",
501 func() android.Singleton { return &lintSingleton{} })
502}
Colin Crossc0efd1d2020-07-03 11:56:24 -0700503
504func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
505 paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
506
507 sort.Slice(paths, func(i, j int) bool {
508 return paths[i].String() < paths[j].String()
509 })
510
511 rule := android.NewRuleBuilder()
512
513 rule.Command().BuiltTool(ctx, "soong_zip").
514 FlagWithOutput("-o ", outputPath).
515 FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
Colin Cross053fca12020-08-19 13:51:47 -0700516 FlagWithRspFileInputList("-r ", paths)
Colin Crossc0efd1d2020-07-03 11:56:24 -0700517
518 rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base())
519}