blob: ecdd11113776ec68be3c4859b64fd54647d09e91 [file] [log] [blame]
/*
* Copyright (C) 2017 The Android Open Source Project
*
* 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 com.android.build.gradle
import com.android.build.gradle.internal.TaskManager
import com.android.build.gradle.internal.dsl.DslVariableFactory
import com.android.build.gradle.internal.dsl.LintOptions
import com.android.build.gradle.internal.errors.DeprecationReporterImpl
import com.android.build.gradle.internal.errors.SyncIssueReporterImpl
import com.android.build.gradle.internal.plugins.BasePlugin
import com.android.build.gradle.internal.services.DslServicesImpl
import com.android.build.gradle.internal.services.LintClassLoaderBuildService
import com.android.build.gradle.internal.services.ProjectServices
import com.android.build.gradle.internal.tasks.LintStandaloneTask
import com.android.build.gradle.options.ProjectOptions
import com.android.build.gradle.options.SyncOptions
import org.gradle.api.Action
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.TaskProvider
/**
* Plugin for running lint **without** the Android Gradle plugin, such as in a pure Kotlin
* project.
*/
open class LintPlugin : Plugin<Project> {
private lateinit var project: Project
private lateinit var projectServices: ProjectServices
private lateinit var syncIssueReporter: SyncIssueReporterImpl
private var dslServices: DslServicesImpl? = null
private var lintOptions: LintOptions? = null
override fun apply(project: Project) {
// We run by default in headless mode, so the JVM doesn't steal focus.
System.setProperty("java.awt.headless", "true")
this.project = project
createProjectServices(project)
dslServices = DslServicesImpl(
projectServices, DslVariableFactory(syncIssueReporter),
project.providers.provider { null }
)
createExtension(project)
BasePlugin.createLintClasspathConfiguration(project)
withJavaPlugin(
Action {
getJavaPluginConvention()?.let { javaConvention ->
val customLintChecksConfig = TaskManager.createCustomLintChecksConfig(project)
val projectName = project.name
val task = registerTask(
"lint",
"Run Android Lint analysis on project `$projectName`",
project,
javaConvention,
customLintChecksConfig
)
// Make the check task depend on the lint
project.tasks.named(JavaBasePlugin.CHECK_TASK_NAME)
.configure { t: Task -> t.dependsOn(task) }
val lintVital = registerTask(
"lintVital",
"Runs lint on just the fatal issues in the project `$projectName`",
project,
javaConvention,
customLintChecksConfig
)
lintVital.configure { it.fatalOnly = true }
registerTask(
"lintFix",
"Runs lint on `$projectName` and applies any safe suggestions to " +
"the source code.",
project,
javaConvention,
customLintChecksConfig
).configure {
it.autoFix = true
it.group = "cleanup"
}
}
})
}
private fun createExtension(project: Project) {
lintOptions = project.extensions.create("lintOptions", LintOptions::class.java, dslServices)
}
private fun withJavaPlugin(action: Action<Plugin<*>>) {
project.plugins.withType(JavaBasePlugin::class.java, action)
}
private fun registerTask(
taskName: String,
description: String,
project: Project,
javaConvention: JavaPluginConvention,
customLintChecksConfig: Configuration
): TaskProvider<LintStandaloneTask> {
return project.tasks.register(taskName, LintStandaloneTask::class.java) { task ->
task.group = JavaBasePlugin.VERIFICATION_GROUP
task.description = description
task.reportDir = javaConvention.testResultsDir
task.lintOptions = lintOptions
task.lintChecks = customLintChecksConfig
task.outputs.upToDateWhen { false }
task.lintClassLoader.set(LintClassLoaderBuildService.RegistrationAction(project).execute())
}
}
private fun getJavaPluginConvention(): JavaPluginConvention? {
val convention = project.convention
val javaConvention = convention.findPlugin(JavaPluginConvention::class.java)
if (javaConvention == null) {
project.logger.warn("Cannot apply lint if the java or kotlin Gradle plugins " +
"have also been applied")
return null
}
return javaConvention
}
// Copied from BasePlugin
private fun createProjectServices(project: Project) {
val objectFactory = project.objects
val logger = project.logger
val projectPath = project.path
val projectOptions = ProjectOptions(project)
val syncIssueReporter =
SyncIssueReporterImpl(SyncOptions.getModelQueryMode(projectOptions), logger)
this.syncIssueReporter = syncIssueReporter
val deprecationReporter =
DeprecationReporterImpl(syncIssueReporter, projectOptions, projectPath)
projectServices = ProjectServices(
syncIssueReporter, deprecationReporter, objectFactory, project.logger,
project.providers, project.layout, projectOptions, project.gradle.sharedServices,
maxWorkerCount = project.gradle.startParameter.maxWorkerCount
) { o: Any -> project.file(o) }
}
}