2020-06-03 05:09:13 +02:00
|
|
|
// Copyright 2020 Google Inc. All rights reserved.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
|
|
|
|
package java
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"sort"
|
2020-07-17 02:32:17 +02:00
|
|
|
"strings"
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2021-02-15 16:41:33 +01:00
|
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
|
2020-06-03 05:09:13 +02:00
|
|
|
"android/soong/android"
|
2021-03-04 19:44:12 +01:00
|
|
|
"android/soong/java/config"
|
|
|
|
"android/soong/remoteexec"
|
2020-06-03 05:09:13 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
type LintProperties struct {
|
|
|
|
// Controls for running Android Lint on the module.
|
|
|
|
Lint struct {
|
|
|
|
|
|
|
|
// If true, run Android Lint on the module. Defaults to true.
|
|
|
|
Enabled *bool
|
|
|
|
|
|
|
|
// Flags to pass to the Android Lint tool.
|
|
|
|
Flags []string
|
|
|
|
|
|
|
|
// Checks that should be treated as fatal.
|
|
|
|
Fatal_checks []string
|
|
|
|
|
|
|
|
// Checks that should be treated as errors.
|
|
|
|
Error_checks []string
|
|
|
|
|
|
|
|
// Checks that should be treated as warnings.
|
|
|
|
Warning_checks []string
|
|
|
|
|
|
|
|
// Checks that should be skipped.
|
|
|
|
Disabled_checks []string
|
2020-06-19 00:56:48 +02:00
|
|
|
|
|
|
|
// Modules that provide extra lint checks
|
|
|
|
Extra_check_modules []string
|
2021-02-15 16:41:33 +01:00
|
|
|
|
|
|
|
// Name of the file that lint uses as the baseline. Defaults to "lint-baseline.xml".
|
|
|
|
Baseline_filename *string
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type linter struct {
|
|
|
|
name string
|
|
|
|
manifest android.Path
|
|
|
|
mergedManifest android.Path
|
|
|
|
srcs android.Paths
|
|
|
|
srcJars android.Paths
|
|
|
|
resources android.Paths
|
|
|
|
classpath android.Paths
|
|
|
|
classes android.Path
|
|
|
|
extraLintCheckJars android.Paths
|
|
|
|
test bool
|
|
|
|
library bool
|
|
|
|
minSdkVersion string
|
|
|
|
targetSdkVersion string
|
|
|
|
compileSdkVersion string
|
|
|
|
javaLanguageLevel string
|
|
|
|
kotlinLanguageLevel string
|
|
|
|
outputs lintOutputs
|
|
|
|
properties LintProperties
|
2020-07-03 20:56:24 +02:00
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
reports android.Paths
|
|
|
|
|
2020-07-03 20:56:24 +02:00
|
|
|
buildModuleReportZip bool
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
type lintOutputs struct {
|
2020-07-22 05:31:17 +02:00
|
|
|
html android.Path
|
|
|
|
text android.Path
|
|
|
|
xml android.Path
|
2020-07-03 20:56:24 +02:00
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
depSets LintDepSets
|
2020-07-03 20:56:24 +02:00
|
|
|
}
|
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
type lintOutputsIntf interface {
|
2020-07-03 20:56:24 +02:00
|
|
|
lintOutputs() *lintOutputs
|
|
|
|
}
|
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
type lintDepSetsIntf interface {
|
|
|
|
LintDepSets() LintDepSets
|
|
|
|
}
|
|
|
|
|
|
|
|
type LintDepSets struct {
|
|
|
|
HTML, Text, XML *android.DepSet
|
|
|
|
}
|
|
|
|
|
|
|
|
type LintDepSetsBuilder struct {
|
|
|
|
HTML, Text, XML *android.DepSetBuilder
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewLintDepSetBuilder() LintDepSetsBuilder {
|
|
|
|
return LintDepSetsBuilder{
|
|
|
|
HTML: android.NewDepSetBuilder(android.POSTORDER),
|
|
|
|
Text: android.NewDepSetBuilder(android.POSTORDER),
|
|
|
|
XML: android.NewDepSetBuilder(android.POSTORDER),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l LintDepSetsBuilder) Direct(html, text, xml android.Path) LintDepSetsBuilder {
|
|
|
|
l.HTML.Direct(html)
|
|
|
|
l.Text.Direct(text)
|
|
|
|
l.XML.Direct(xml)
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l LintDepSetsBuilder) Transitive(depSets LintDepSets) LintDepSetsBuilder {
|
|
|
|
if depSets.HTML != nil {
|
|
|
|
l.HTML.Transitive(depSets.HTML)
|
|
|
|
}
|
|
|
|
if depSets.Text != nil {
|
|
|
|
l.Text.Transitive(depSets.Text)
|
|
|
|
}
|
|
|
|
if depSets.XML != nil {
|
|
|
|
l.XML.Transitive(depSets.XML)
|
|
|
|
}
|
|
|
|
return l
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l LintDepSetsBuilder) Build() LintDepSets {
|
|
|
|
return LintDepSets{
|
|
|
|
HTML: l.HTML.Build(),
|
|
|
|
Text: l.Text.Build(),
|
|
|
|
XML: l.XML.Build(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *linter) LintDepSets() LintDepSets {
|
|
|
|
return l.outputs.depSets
|
|
|
|
}
|
|
|
|
|
|
|
|
var _ lintDepSetsIntf = (*linter)(nil)
|
|
|
|
|
|
|
|
var _ lintOutputsIntf = (*linter)(nil)
|
2020-07-03 20:56:24 +02:00
|
|
|
|
|
|
|
func (l *linter) lintOutputs() *lintOutputs {
|
|
|
|
return &l.outputs
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func (l *linter) enabled() bool {
|
|
|
|
return BoolDefault(l.properties.Lint.Enabled, true)
|
|
|
|
}
|
|
|
|
|
2020-06-19 00:56:48 +02:00
|
|
|
func (l *linter) deps(ctx android.BottomUpMutatorContext) {
|
|
|
|
if !l.enabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-07-17 02:32:17 +02:00
|
|
|
extraCheckModules := l.properties.Lint.Extra_check_modules
|
|
|
|
|
|
|
|
if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
|
|
|
|
if checkOnlyModules := ctx.Config().Getenv("ANDROID_LINT_CHECK_EXTRA_MODULES"); checkOnlyModules != "" {
|
|
|
|
extraCheckModules = strings.Split(checkOnlyModules, ",")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(),
|
|
|
|
extraLintCheckTag, extraCheckModules...)
|
2020-06-19 00:56:48 +02:00
|
|
|
}
|
|
|
|
|
2021-03-10 18:45:40 +01:00
|
|
|
// lintPaths contains the paths to lint's inputs and outputs to make it easier to pass them
|
|
|
|
// around.
|
2021-03-04 19:44:12 +01:00
|
|
|
type lintPaths struct {
|
|
|
|
projectXML android.WritablePath
|
|
|
|
configXML android.WritablePath
|
|
|
|
cacheDir android.WritablePath
|
|
|
|
homeDir android.WritablePath
|
|
|
|
srcjarDir android.WritablePath
|
|
|
|
|
|
|
|
deps android.Paths
|
|
|
|
|
|
|
|
remoteInputs android.Paths
|
|
|
|
remoteRSPInputs android.Paths
|
|
|
|
}
|
|
|
|
|
2021-03-10 19:40:58 +01:00
|
|
|
func lintRBEExecStrategy(ctx android.ModuleContext) string {
|
|
|
|
return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
|
|
|
|
}
|
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
|
|
|
|
var deps android.Paths
|
|
|
|
var remoteInputs android.Paths
|
|
|
|
var remoteRSPInputs android.Paths
|
|
|
|
|
|
|
|
// Paths passed to trackInputDependency will be added as dependencies of the rule that runs
|
|
|
|
// lint and passed as inputs to the remote execution proxy.
|
|
|
|
trackInputDependency := func(paths ...android.Path) {
|
|
|
|
deps = append(deps, paths...)
|
|
|
|
remoteInputs = append(remoteInputs, paths...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Paths passed to trackRSPDependency will be added as dependencies of the rule that runs
|
|
|
|
// lint, but the RSP file will be used by the remote execution proxy to find the files so that
|
|
|
|
// it doesn't overflow command line limits.
|
|
|
|
trackRSPDependency := func(paths android.Paths, rsp android.Path) {
|
|
|
|
deps = append(deps, paths...)
|
|
|
|
remoteRSPInputs = append(remoteRSPInputs, rsp)
|
|
|
|
}
|
2020-06-03 05:09:13 +02:00
|
|
|
|
|
|
|
var resourcesList android.WritablePath
|
|
|
|
if len(l.resources) > 0 {
|
|
|
|
// The list of resources may be too long to put on the command line, but
|
|
|
|
// we can't use the rsp file because it is already being used for srcs.
|
|
|
|
// Insert a second rule to write out the list of resources to a file.
|
|
|
|
resourcesList = android.PathForModuleOut(ctx, "lint", "resources.list")
|
2020-11-17 02:32:30 +01:00
|
|
|
resListRule := android.NewRuleBuilder(pctx, ctx)
|
2020-06-03 05:09:13 +02:00
|
|
|
resListRule.Command().Text("cp").FlagWithRspFileInputList("", l.resources).Output(resourcesList)
|
2020-11-17 02:32:30 +01:00
|
|
|
resListRule.Build("lint_resources_list", "lint resources list")
|
2021-03-04 19:44:12 +01:00
|
|
|
trackRSPDependency(l.resources, resourcesList)
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
projectXMLPath := android.PathForModuleOut(ctx, "lint", "project.xml")
|
2020-06-03 05:09:13 +02:00
|
|
|
// Lint looks for a lint.xml file next to the project.xml file, give it one.
|
2021-03-04 19:44:12 +01:00
|
|
|
configXMLPath := android.PathForModuleOut(ctx, "lint", "lint.xml")
|
|
|
|
cacheDir := android.PathForModuleOut(ctx, "lint", "cache")
|
|
|
|
homeDir := android.PathForModuleOut(ctx, "lint", "home")
|
2020-06-03 05:09:13 +02:00
|
|
|
|
|
|
|
srcJarDir := android.PathForModuleOut(ctx, "lint-srcjars")
|
|
|
|
srcJarList := zipSyncCmd(ctx, rule, srcJarDir, l.srcJars)
|
2021-03-04 19:44:12 +01:00
|
|
|
// TODO(ccross): this is a little fishy. The files extracted from the srcjars are referenced
|
|
|
|
// by the project.xml and used by the later lint rule, but the lint rule depends on the srcjars,
|
|
|
|
// not the extracted files.
|
|
|
|
trackRSPDependency(l.srcJars, srcJarList)
|
|
|
|
|
|
|
|
// TODO(ccross): some of the files in l.srcs are generated sources and should be passed to
|
|
|
|
// lint separately.
|
|
|
|
srcsList := android.PathForModuleOut(ctx, "lint", "srcs.list")
|
|
|
|
rule.Command().Text("cp").FlagWithRspFileInputList("", l.srcs).Output(srcsList)
|
|
|
|
trackRSPDependency(l.srcs, srcsList)
|
2020-06-03 05:09:13 +02:00
|
|
|
|
|
|
|
cmd := rule.Command().
|
2020-11-17 02:32:30 +01:00
|
|
|
BuiltTool("lint-project-xml").
|
2020-06-03 05:09:13 +02:00
|
|
|
FlagWithOutput("--project_out ", projectXMLPath).
|
|
|
|
FlagWithOutput("--config_out ", configXMLPath).
|
|
|
|
FlagWithArg("--name ", ctx.ModuleName())
|
|
|
|
|
|
|
|
if l.library {
|
|
|
|
cmd.Flag("--library")
|
|
|
|
}
|
|
|
|
if l.test {
|
|
|
|
cmd.Flag("--test")
|
|
|
|
}
|
|
|
|
if l.manifest != nil {
|
|
|
|
cmd.FlagWithArg("--manifest ", l.manifest.String())
|
2021-03-04 19:44:12 +01:00
|
|
|
trackInputDependency(l.manifest)
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
if l.mergedManifest != nil {
|
|
|
|
cmd.FlagWithArg("--merged_manifest ", l.mergedManifest.String())
|
2021-03-04 19:44:12 +01:00
|
|
|
trackInputDependency(l.mergedManifest)
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
cmd.FlagWithInput("--srcs ", srcsList)
|
2020-06-03 05:09:13 +02:00
|
|
|
|
|
|
|
cmd.FlagWithInput("--generated_srcs ", srcJarList)
|
|
|
|
|
|
|
|
if resourcesList != nil {
|
|
|
|
cmd.FlagWithInput("--resources ", resourcesList)
|
|
|
|
}
|
|
|
|
|
|
|
|
if l.classes != nil {
|
|
|
|
cmd.FlagWithArg("--classes ", l.classes.String())
|
2021-03-04 19:44:12 +01:00
|
|
|
trackInputDependency(l.classes)
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
cmd.FlagForEachArg("--classpath ", l.classpath.Strings())
|
2021-03-04 19:44:12 +01:00
|
|
|
trackInputDependency(l.classpath...)
|
2020-06-03 05:09:13 +02:00
|
|
|
|
|
|
|
cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings())
|
2021-03-04 19:44:12 +01:00
|
|
|
trackInputDependency(l.extraLintCheckJars...)
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2021-03-10 19:40:58 +01:00
|
|
|
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") &&
|
|
|
|
lintRBEExecStrategy(ctx) != remoteexec.LocalExecStrategy {
|
2021-03-04 19:44:12 +01:00
|
|
|
// TODO(b/181912787): remove these and use "." instead.
|
|
|
|
cmd.FlagWithArg("--root_dir ", "/b/f/w")
|
|
|
|
} else {
|
|
|
|
cmd.FlagWithArg("--root_dir ", "$PWD")
|
|
|
|
}
|
2020-06-23 19:25:26 +02:00
|
|
|
|
|
|
|
// The cache tag in project.xml is relative to the root dir, or the project.xml file if
|
|
|
|
// the root dir is not set.
|
|
|
|
cmd.FlagWithArg("--cache_dir ", cacheDir.String())
|
2020-06-03 05:09:13 +02:00
|
|
|
|
|
|
|
cmd.FlagWithInput("@",
|
|
|
|
android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
|
|
|
|
|
|
|
|
cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
|
|
|
|
cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
|
|
|
|
cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
|
|
|
|
cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
|
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
return lintPaths{
|
|
|
|
projectXML: projectXMLPath,
|
|
|
|
configXML: configXMLPath,
|
|
|
|
cacheDir: cacheDir,
|
|
|
|
homeDir: homeDir,
|
|
|
|
|
|
|
|
deps: deps,
|
|
|
|
|
|
|
|
remoteInputs: remoteInputs,
|
|
|
|
remoteRSPInputs: remoteRSPInputs,
|
|
|
|
}
|
|
|
|
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
2020-07-28 20:32:07 +02:00
|
|
|
// generateManifest adds a command to the rule to write a simple manifest that contains the
|
2020-06-03 05:09:13 +02:00
|
|
|
// minSdkVersion and targetSdkVersion for modules (like java_library) that don't have a manifest.
|
|
|
|
func (l *linter) generateManifest(ctx android.ModuleContext, rule *android.RuleBuilder) android.Path {
|
|
|
|
manifestPath := android.PathForModuleOut(ctx, "lint", "AndroidManifest.xml")
|
|
|
|
|
|
|
|
rule.Command().Text("(").
|
|
|
|
Text(`echo "<?xml version='1.0' encoding='utf-8'?>" &&`).
|
|
|
|
Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
|
|
|
|
Text(`echo " android:versionCode='1' android:versionName='1' >" &&`).
|
|
|
|
Textf(`echo " <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
|
|
|
|
l.minSdkVersion, l.targetSdkVersion).
|
|
|
|
Text(`echo "</manifest>"`).
|
|
|
|
Text(") >").Output(manifestPath)
|
|
|
|
|
|
|
|
return manifestPath
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *linter) lint(ctx android.ModuleContext) {
|
|
|
|
if !l.enabled() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-19 00:56:48 +02:00
|
|
|
extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag)
|
|
|
|
for _, extraLintCheckModule := range extraLintCheckModules {
|
2021-02-01 22:59:03 +01:00
|
|
|
if ctx.OtherModuleHasProvider(extraLintCheckModule, JavaInfoProvider) {
|
|
|
|
dep := ctx.OtherModuleProvider(extraLintCheckModule, JavaInfoProvider).(JavaInfo)
|
|
|
|
l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...)
|
2020-06-19 00:56:48 +02:00
|
|
|
} else {
|
|
|
|
ctx.PropertyErrorf("lint.extra_check_modules",
|
|
|
|
"%s is not a java module", ctx.OtherModuleName(extraLintCheckModule))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-17 02:32:30 +01:00
|
|
|
rule := android.NewRuleBuilder(pctx, ctx)
|
2020-06-03 05:09:13 +02:00
|
|
|
|
|
|
|
if l.manifest == nil {
|
|
|
|
manifest := l.generateManifest(ctx, rule)
|
|
|
|
l.manifest = manifest
|
|
|
|
}
|
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
lintPaths := l.writeLintProjectXML(ctx, rule)
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2020-07-03 20:56:24 +02:00
|
|
|
html := android.PathForModuleOut(ctx, "lint-report.html")
|
|
|
|
text := android.PathForModuleOut(ctx, "lint-report.txt")
|
|
|
|
xml := android.PathForModuleOut(ctx, "lint-report.xml")
|
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml)
|
2020-07-03 20:56:24 +02:00
|
|
|
|
|
|
|
ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) {
|
2020-07-22 05:31:17 +02:00
|
|
|
if depLint, ok := dep.(lintDepSetsIntf); ok {
|
|
|
|
depSetsBuilder.Transitive(depLint.LintDepSets())
|
2020-07-03 20:56:24 +02:00
|
|
|
}
|
|
|
|
})
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
|
|
|
|
rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
|
2021-03-04 19:01:34 +01:00
|
|
|
rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2020-07-06 20:45:51 +02:00
|
|
|
var annotationsZipPath, apiVersionsXMLPath android.Path
|
2020-07-07 18:09:23 +02:00
|
|
|
if ctx.Config().AlwaysUsePrebuiltSdks() {
|
2020-07-06 20:45:51 +02:00
|
|
|
annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
|
|
|
|
apiVersionsXMLPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/api-versions.xml")
|
|
|
|
} else {
|
|
|
|
annotationsZipPath = copiedAnnotationsZipPath(ctx)
|
|
|
|
apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx)
|
|
|
|
}
|
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
cmd := rule.Command()
|
|
|
|
|
|
|
|
cmd.Flag("JAVA_OPTS=-Xmx3072m").
|
|
|
|
FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()).
|
2020-07-06 20:45:51 +02:00
|
|
|
FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath).
|
2021-03-04 19:44:12 +01:00
|
|
|
FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath)
|
|
|
|
|
|
|
|
if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
|
|
|
|
pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
|
|
|
|
// TODO(b/181912787): this should be local fallback once the hack that passes /b/f/w in project.xml
|
|
|
|
// is removed.
|
2021-03-10 19:40:58 +01:00
|
|
|
execStrategy := lintRBEExecStrategy(ctx)
|
2021-03-04 19:44:12 +01:00
|
|
|
labels := map[string]string{"type": "tool", "name": "lint"}
|
|
|
|
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
|
|
|
|
remoteInputs := lintPaths.remoteInputs
|
|
|
|
remoteInputs = append(remoteInputs,
|
|
|
|
lintPaths.projectXML,
|
|
|
|
lintPaths.configXML,
|
|
|
|
lintPaths.homeDir,
|
|
|
|
lintPaths.cacheDir,
|
|
|
|
ctx.Config().HostJavaToolPath(ctx, "lint.jar"),
|
|
|
|
annotationsZipPath,
|
|
|
|
apiVersionsXMLPath,
|
|
|
|
)
|
|
|
|
|
|
|
|
cmd.Text((&remoteexec.REParams{
|
|
|
|
Labels: labels,
|
|
|
|
ExecStrategy: execStrategy,
|
|
|
|
ToolchainInputs: []string{config.JavaCmd(ctx).String()},
|
|
|
|
Inputs: remoteInputs.Strings(),
|
|
|
|
OutputFiles: android.Paths{html, text, xml}.Strings(),
|
|
|
|
RSPFile: strings.Join(lintPaths.remoteRSPInputs.Strings(), ","),
|
|
|
|
EnvironmentVariables: []string{
|
|
|
|
"JAVA_OPTS",
|
|
|
|
"ANDROID_SDK_HOME",
|
|
|
|
"SDK_ANNOTATIONS",
|
|
|
|
"LINT_OPTS",
|
2021-03-11 03:00:51 +01:00
|
|
|
"LANG",
|
2021-03-04 19:44:12 +01:00
|
|
|
},
|
|
|
|
Platform: map[string]string{remoteexec.PoolKey: pool},
|
|
|
|
}).NoVarTemplate(ctx.Config()))
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd.BuiltTool("lint").
|
2020-06-03 05:09:13 +02:00
|
|
|
Flag("--quiet").
|
2021-03-04 19:44:12 +01:00
|
|
|
FlagWithInput("--project ", lintPaths.projectXML).
|
|
|
|
FlagWithInput("--config ", lintPaths.configXML).
|
2020-07-03 20:56:24 +02:00
|
|
|
FlagWithOutput("--html ", html).
|
|
|
|
FlagWithOutput("--text ", text).
|
|
|
|
FlagWithOutput("--xml ", xml).
|
2020-06-03 05:09:13 +02:00
|
|
|
FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
|
|
|
|
FlagWithArg("--java-language-level ", l.javaLanguageLevel).
|
|
|
|
FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
|
|
|
|
FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
|
|
|
|
Flag("--exitcode").
|
|
|
|
Flags(l.properties.Lint.Flags).
|
2021-03-04 19:44:12 +01:00
|
|
|
Implicit(annotationsZipPath).
|
|
|
|
Implicit(apiVersionsXMLPath).
|
|
|
|
Implicits(lintPaths.deps)
|
2020-07-17 02:32:17 +02:00
|
|
|
|
|
|
|
if checkOnly := ctx.Config().Getenv("ANDROID_LINT_CHECK"); checkOnly != "" {
|
|
|
|
cmd.FlagWithArg("--check ", checkOnly)
|
|
|
|
}
|
|
|
|
|
2021-02-15 16:41:33 +01:00
|
|
|
if lintFilename := proptools.StringDefault(l.properties.Lint.Baseline_filename, "lint-baseline.xml"); lintFilename != "" {
|
|
|
|
var lintBaseline android.OptionalPath
|
|
|
|
if String(l.properties.Lint.Baseline_filename) != "" {
|
|
|
|
// if manually specified, we require the file to exist
|
|
|
|
lintBaseline = android.OptionalPathForPath(android.PathForModuleSrc(ctx, lintFilename))
|
|
|
|
} else {
|
|
|
|
lintBaseline = android.ExistentPathForSource(ctx, ctx.ModuleDir(), lintFilename)
|
|
|
|
}
|
|
|
|
if lintBaseline.Valid() {
|
|
|
|
cmd.FlagWithInput("--baseline ", lintBaseline.Path())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
cmd.Text("|| (").Text("if [ -e").Input(text).Text("]; then cat").Input(text).Text("; fi; exit 7)")
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2021-03-04 19:44:12 +01:00
|
|
|
rule.Command().Text("rm -rf").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2020-11-17 02:32:30 +01:00
|
|
|
rule.Build("lint", "lint")
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2020-07-03 20:56:24 +02:00
|
|
|
l.outputs = lintOutputs{
|
|
|
|
html: html,
|
|
|
|
text: text,
|
|
|
|
xml: xml,
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
depSets: depSetsBuilder.Build(),
|
2020-07-03 20:56:24 +02:00
|
|
|
}
|
2020-06-03 05:09:13 +02:00
|
|
|
|
2020-07-03 20:56:24 +02:00
|
|
|
if l.buildModuleReportZip {
|
2020-07-22 05:31:17 +02:00
|
|
|
l.reports = BuildModuleLintReportZips(ctx, l.LintDepSets())
|
|
|
|
}
|
|
|
|
}
|
2020-07-03 20:56:24 +02:00
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets) android.Paths {
|
|
|
|
htmlList := depSets.HTML.ToSortedList()
|
|
|
|
textList := depSets.Text.ToSortedList()
|
|
|
|
xmlList := depSets.XML.ToSortedList()
|
2020-07-03 20:56:24 +02:00
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
if len(htmlList) == 0 && len(textList) == 0 && len(xmlList) == 0 {
|
|
|
|
return nil
|
2020-07-03 20:56:24 +02:00
|
|
|
}
|
2020-07-22 05:31:17 +02:00
|
|
|
|
|
|
|
htmlZip := android.PathForModuleOut(ctx, "lint-report-html.zip")
|
|
|
|
lintZip(ctx, htmlList, htmlZip)
|
|
|
|
|
|
|
|
textZip := android.PathForModuleOut(ctx, "lint-report-text.zip")
|
|
|
|
lintZip(ctx, textList, textZip)
|
|
|
|
|
|
|
|
xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip")
|
|
|
|
lintZip(ctx, xmlList, xmlZip)
|
|
|
|
|
|
|
|
return android.Paths{htmlZip, textZip, xmlZip}
|
2020-07-03 20:56:24 +02:00
|
|
|
}
|
2020-06-03 05:09:13 +02:00
|
|
|
|
|
|
|
type lintSingleton struct {
|
|
|
|
htmlZip android.WritablePath
|
|
|
|
textZip android.WritablePath
|
|
|
|
xmlZip android.WritablePath
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *lintSingleton) GenerateBuildActions(ctx android.SingletonContext) {
|
|
|
|
l.generateLintReportZips(ctx)
|
|
|
|
l.copyLintDependencies(ctx)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *lintSingleton) copyLintDependencies(ctx android.SingletonContext) {
|
2020-07-07 18:09:23 +02:00
|
|
|
if ctx.Config().AlwaysUsePrebuiltSdks() {
|
2020-06-03 05:09:13 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var frameworkDocStubs android.Module
|
|
|
|
ctx.VisitAllModules(func(m android.Module) {
|
|
|
|
if ctx.ModuleName(m) == "framework-doc-stubs" {
|
|
|
|
if frameworkDocStubs == nil {
|
|
|
|
frameworkDocStubs = m
|
|
|
|
} else {
|
|
|
|
ctx.Errorf("lint: multiple framework-doc-stubs modules found: %s and %s",
|
|
|
|
ctx.ModuleSubDir(m), ctx.ModuleSubDir(frameworkDocStubs))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
if frameworkDocStubs == nil {
|
|
|
|
if !ctx.Config().AllowMissingDependencies() {
|
|
|
|
ctx.Errorf("lint: missing framework-doc-stubs")
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
ctx.Build(pctx, android.BuildParams{
|
2021-03-04 19:00:09 +01:00
|
|
|
Rule: android.CpIfChanged,
|
2020-06-03 05:09:13 +02:00
|
|
|
Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".annotations.zip"),
|
2020-07-06 20:45:51 +02:00
|
|
|
Output: copiedAnnotationsZipPath(ctx),
|
2020-06-03 05:09:13 +02:00
|
|
|
})
|
|
|
|
|
|
|
|
ctx.Build(pctx, android.BuildParams{
|
2021-03-04 19:00:09 +01:00
|
|
|
Rule: android.CpIfChanged,
|
2020-06-03 05:09:13 +02:00
|
|
|
Input: android.OutputFileForModule(ctx, frameworkDocStubs, ".api_versions.xml"),
|
2020-07-06 20:45:51 +02:00
|
|
|
Output: copiedAPIVersionsXmlPath(ctx),
|
2020-06-03 05:09:13 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-07-06 20:45:51 +02:00
|
|
|
func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
|
2020-06-03 05:09:13 +02:00
|
|
|
return android.PathForOutput(ctx, "lint", "annotations.zip")
|
|
|
|
}
|
|
|
|
|
2020-07-06 20:45:51 +02:00
|
|
|
func copiedAPIVersionsXmlPath(ctx android.PathContext) android.WritablePath {
|
2020-06-03 05:09:13 +02:00
|
|
|
return android.PathForOutput(ctx, "lint", "api_versions.xml")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) {
|
2020-07-06 20:45:51 +02:00
|
|
|
if ctx.Config().UnbundledBuild() {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-06-03 05:09:13 +02:00
|
|
|
var outputs []*lintOutputs
|
|
|
|
var dirs []string
|
|
|
|
ctx.VisitAllModules(func(m android.Module) {
|
2020-11-23 06:22:30 +01:00
|
|
|
if ctx.Config().KatiEnabled() && !m.ExportedToMake() {
|
2020-06-03 05:09:13 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2020-09-16 03:30:11 +02:00
|
|
|
if apex, ok := m.(android.ApexModule); ok && apex.NotAvailableForPlatform() {
|
|
|
|
apexInfo := ctx.ModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo)
|
|
|
|
if apexInfo.IsForPlatform() {
|
|
|
|
// There are stray platform variants of modules in apexes that are not available for
|
|
|
|
// the platform, and they sometimes can't be built. Don't depend on them.
|
|
|
|
return
|
|
|
|
}
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
2020-07-22 05:31:17 +02:00
|
|
|
if l, ok := m.(lintOutputsIntf); ok {
|
2020-06-03 05:09:13 +02:00
|
|
|
outputs = append(outputs, l.lintOutputs())
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
dirs = android.SortedUniqueStrings(dirs)
|
|
|
|
|
|
|
|
zip := func(outputPath android.WritablePath, get func(*lintOutputs) android.Path) {
|
|
|
|
var paths android.Paths
|
|
|
|
|
|
|
|
for _, output := range outputs {
|
2020-07-22 05:31:17 +02:00
|
|
|
if p := get(output); p != nil {
|
|
|
|
paths = append(paths, p)
|
|
|
|
}
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
2020-07-03 20:56:24 +02:00
|
|
|
lintZip(ctx, paths, outputPath)
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
l.htmlZip = android.PathForOutput(ctx, "lint-report-html.zip")
|
|
|
|
zip(l.htmlZip, func(l *lintOutputs) android.Path { return l.html })
|
|
|
|
|
|
|
|
l.textZip = android.PathForOutput(ctx, "lint-report-text.zip")
|
|
|
|
zip(l.textZip, func(l *lintOutputs) android.Path { return l.text })
|
|
|
|
|
|
|
|
l.xmlZip = android.PathForOutput(ctx, "lint-report-xml.zip")
|
|
|
|
zip(l.xmlZip, func(l *lintOutputs) android.Path { return l.xml })
|
|
|
|
|
|
|
|
ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) {
|
2020-07-06 20:45:51 +02:00
|
|
|
if !ctx.Config().UnbundledBuild() {
|
|
|
|
ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip)
|
|
|
|
}
|
2020-06-03 05:09:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil)
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
android.RegisterSingletonType("lint",
|
|
|
|
func() android.Singleton { return &lintSingleton{} })
|
|
|
|
}
|
2020-07-03 20:56:24 +02:00
|
|
|
|
|
|
|
func lintZip(ctx android.BuilderContext, paths android.Paths, outputPath android.WritablePath) {
|
|
|
|
paths = android.SortedUniquePaths(android.CopyOfPaths(paths))
|
|
|
|
|
|
|
|
sort.Slice(paths, func(i, j int) bool {
|
|
|
|
return paths[i].String() < paths[j].String()
|
|
|
|
})
|
|
|
|
|
2020-11-17 02:32:30 +01:00
|
|
|
rule := android.NewRuleBuilder(pctx, ctx)
|
2020-07-03 20:56:24 +02:00
|
|
|
|
2020-11-17 02:32:30 +01:00
|
|
|
rule.Command().BuiltTool("soong_zip").
|
2020-07-03 20:56:24 +02:00
|
|
|
FlagWithOutput("-o ", outputPath).
|
|
|
|
FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
|
2020-08-19 22:51:47 +02:00
|
|
|
FlagWithRspFileInputList("-r ", paths)
|
2020-07-03 20:56:24 +02:00
|
|
|
|
2020-11-17 02:32:30 +01:00
|
|
|
rule.Build(outputPath.Base(), outputPath.Base())
|
2020-07-03 20:56:24 +02:00
|
|
|
}
|