Skip to content

Commit

Permalink
Switch options to properties for lazy configuration
Browse files Browse the repository at this point in the history
…except for checks and checkOptions as they are maps.
  • Loading branch information
tbroyer committed Mar 30, 2019
1 parent 677054c commit 74ef06a
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 102 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ tasks.withType(JavaCompile).configureEach {
import net.ltgt.gradle.errorprone.*

tasks.withType<JavaCompile>().configureEach {
options.errorprone.disableWarningsInGeneratedCode = true
options.errorprone.disableWarningsInGeneratedCode.set(true)
}
```

Expand All @@ -70,7 +70,7 @@ tasks.named("compileTestJava").configure {

```kotlin
tasks.named("compileTestJava", JavaCompile::class) {
options.errorprone.isEnabled = false
options.errorprone.isEnabled.set(false)
}
```

Expand Down Expand Up @@ -113,9 +113,9 @@ tasks.register<JavaCompile>("compileCustom") {
// Error Prone must be available in the annotation processor path
options.annotationProcessorPath = configurations["errorprone"]
// Enable Error Prone
options.errorprone.isEnabled = true
options.errorprone.isEnabled.set(true)
// It can then be configured for the task
options.errorprone.disableWarningsInGeneratedCode = true
options.errorprone.disableWarningsInGeneratedCode.set(true)
}
```

Expand All @@ -136,7 +136,7 @@ afterEvaluate {
```kotlin
afterEvaluate {
tasks.withType<JavaCompile>().configureEach {
options.errorprone.disableWarningsInGeneratedCode = true
options.errorprone.disableWarningsInGeneratedCode.set(true)
}
}
```
Expand Down
50 changes: 30 additions & 20 deletions src/main/kotlin/net/ltgt/gradle/errorprone/ErrorProneOptions.kt
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
package net.ltgt.gradle.errorprone

import org.gradle.api.InvalidUserDataException
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Nested
import org.gradle.api.tasks.Optional
import org.gradle.api.tasks.compile.CompileOptions
import org.gradle.kotlin.dsl.* // ktlint-disable no-wildcard-imports
import org.gradle.process.CommandLineArgumentProvider

open class ErrorProneOptions {
@get:Input var isEnabled: Boolean = false
@get:Input var disableAllChecks: Boolean = false
@get:Input var allErrorsAsWarnings: Boolean = false
@get:Input var allDisabledChecksAsWarnings: Boolean = false
@get:Input var disableWarningsInGeneratedCode: Boolean = false
@get:Input var ignoreUnknownCheckNames: Boolean = false
@get:Input var ignoreSuppressionAnnotations: Boolean = false
@get:Input var isCompilingTestOnlyCode: Boolean = false
@get:Input @get:Optional var excludedPaths: String? = null
open class ErrorProneOptions constructor(
objectFactory: ObjectFactory
) {
@get:Input val isEnabled = objectFactory.property<Boolean>().byConvention(false)
@get:Input val disableAllChecks = objectFactory.property<Boolean>().byConvention(false)
@get:Input val allErrorsAsWarnings = objectFactory.property<Boolean>().byConvention(false)
@get:Input val allDisabledChecksAsWarnings = objectFactory.property<Boolean>().byConvention(false)
@get:Input val disableWarningsInGeneratedCode = objectFactory.property<Boolean>().byConvention(false)
@get:Input val ignoreUnknownCheckNames = objectFactory.property<Boolean>().byConvention(false)
@get:Input val ignoreSuppressionAnnotations = objectFactory.property<Boolean>().byConvention(false)
@get:Input val isCompilingTestOnlyCode = objectFactory.property<Boolean>().byConvention(false)
@get:Input @get:Optional val excludedPaths = objectFactory.property<String>()
@get:Input var checks: MutableMap<String, CheckSeverity> = linkedMapOf()
@get:Input var checkOptions: MutableMap<String, String> = linkedMapOf()
@get:Input var errorproneArgs: MutableList<String> = arrayListOf()
@get:Input val errorproneArgs = objectFactory.listProperty<String>().setEmpty()
@get:Nested val errorproneArgumentProviders: MutableList<CommandLineArgumentProvider> = arrayListOf()

companion object {
Expand Down Expand Up @@ -52,22 +56,28 @@ open class ErrorProneOptions {
override fun toString(): String {
return (
sequenceOf(
"-XepDisableAllChecks".takeIf { disableAllChecks },
"-XepAllErrorsAsWarnings".takeIf { allErrorsAsWarnings },
"-XepAllDisabledChecksAsWarnings".takeIf { allDisabledChecksAsWarnings },
"-XepDisableWarningsInGeneratedCode".takeIf { disableWarningsInGeneratedCode },
"-XepIgnoreUnknownCheckNames".takeIf { ignoreUnknownCheckNames },
"-XepIgnoreSuppressionAnnotations".takeIf { ignoreSuppressionAnnotations },
"-XepCompilingTestOnlyCode".takeIf { isCompilingTestOnlyCode },
"-XepExcludedPaths:$excludedPaths".takeUnless { excludedPaths.isNullOrEmpty() }
booleanOption("-XepDisableAllChecks", disableAllChecks),
booleanOption("-XepAllErrorsAsWarnings", allErrorsAsWarnings),
booleanOption("-XepAllDisabledChecksAsWarnings", allDisabledChecksAsWarnings),
booleanOption("-XepDisableWarningsInGeneratedCode", disableWarningsInGeneratedCode),
booleanOption("-XepIgnoreUnknownCheckNames", ignoreUnknownCheckNames),
booleanOption("-XepIgnoreSuppressionAnnotations", ignoreSuppressionAnnotations),
booleanOption("-XepCompilingTestOnlyCode", isCompilingTestOnlyCode),
stringOption("-XepExcludedPaths", excludedPaths)
).filterNotNull() +
checks.asSequence().onEach(::validateName).map { (name, severity) -> "-Xep:$name${severity.asArg}" } +
checkOptions.asSequence().map { (name, value) -> "-XepOpt:$name=$value" } +
errorproneArgs +
errorproneArgs.getOrElse(emptyList()) +
errorproneArgumentProviders.asSequence().flatMap { it.asArguments().asSequence() }
).onEach(::validate)
.joinToString(separator = " ")
}

private fun booleanOption(name: String, value: Provider<Boolean>): String? =
name.takeIf { value.getOrElse(false) }

private fun stringOption(name: String, value: Provider<String>): String? =
value.orNull?.let { "$name:$it" }
}

enum class CheckSeverity {
Expand Down
46 changes: 12 additions & 34 deletions src/main/kotlin/net/ltgt/gradle/errorprone/ErrorPronePlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.TestVariant
import com.android.build.gradle.api.UnitTestVariant
import java.util.concurrent.atomic.AtomicBoolean
import org.gradle.api.DomainObjectCollection
import org.gradle.api.JavaVersion
import org.gradle.api.Named
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.logging.Logging
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.plugins.JavaBasePlugin
Expand All @@ -39,12 +37,6 @@ class ErrorPronePlugin : Plugin<Project> {

const val JAVAC_CONFIGURATION_NAME = "errorproneJavac"

private val MIN_GRADLE_VERSION_WITH_LAZY_TASKS = GradleVersion.version("4.9")

internal fun supportsLazyTasks(version: GradleVersion) = version >= MIN_GRADLE_VERSION_WITH_LAZY_TASKS

private val SUPPORTS_LAZY_TASKS = supportsLazyTasks(GradleVersion.current())

private val LOGGER = Logging.getLogger(ErrorPronePlugin::class.java)

internal const val NO_JAVAC_DEPENDENCY_WARNING_MESSAGE =
Expand Down Expand Up @@ -81,7 +73,8 @@ Add a dependency to com.google.errorprone:javac with the appropriate version cor
val noJavacDependencyNotified = AtomicBoolean()
project.tasks.withType<JavaCompile>().configureElement {
val errorproneOptions =
(options as ExtensionAware).extensions.create(ErrorProneOptions.NAME, ErrorProneOptions::class.java)
// XXX: service injection was added in Gradle 5.2, remove project.objects argument when changing min version
(options as ExtensionAware).extensions.create(ErrorProneOptions.NAME, ErrorProneOptions::class.java, project.objects)
options
.compilerArgumentProviders
.add(ErrorProneCompilerArgumentProvider(errorproneOptions))
Expand All @@ -92,7 +85,7 @@ Add a dependency to com.google.errorprone:javac with the appropriate version cor
// but chances are really high that this will be the case, so configure task inputs anyway.
inputs.files(javacConfiguration).withPropertyName(JAVAC_CONFIGURATION_NAME).withNormalizer(ClasspathNormalizer::class)
doFirst("configure errorprone in bootclasspath") {
if (options.errorprone.isEnabled &&
if (options.errorprone.isEnabled.getOrElse(false) &&
(!options.isFork || (options.forkOptions.javaHome == null && options.forkOptions.executable == null))) {
// We now know that we need the Error Prone javac
if (!options.isFork) {
Expand All @@ -118,14 +111,14 @@ Add a dependency to com.google.errorprone:javac with the appropriate version cor
java.sourceSets.configureElement {
project.configurations[annotationProcessorConfigurationName].extendsFrom(errorproneConfiguration)
project.configureTask<JavaCompile>(compileJavaTaskName) {
options.errorprone.isEnabled = true
options.errorprone.isEnabled.byConvention(true)
}
}
}

project.plugins.withType<JavaPlugin> {
project.configureTask<JavaCompile>(JavaPlugin.COMPILE_TEST_JAVA_TASK_NAME) {
options.errorprone.isCompilingTestOnlyCode = true
options.errorprone.isCompilingTestOnlyCode.byConvention(true)
}
}

Expand All @@ -135,9 +128,9 @@ Add a dependency to com.google.errorprone:javac with the appropriate version cor
annotationProcessorConfiguration.extendsFrom(errorproneConfiguration)
javaCompileProvider.configure {
options.errorprone {
isEnabled = true
isEnabled.byConvention(true)
if (this@configure is TestVariant || this@configure is UnitTestVariant) {
isCompilingTestOnlyCode = true
isCompilingTestOnlyCode.byConvention(true)
}
}
}
Expand All @@ -155,39 +148,24 @@ Add a dependency to com.google.errorprone:javac with the appropriate version cor
}
}
}

private inline fun <reified T : Task> Project.configureTask(taskName: String, noinline action: T.() -> Unit) {
if (SUPPORTS_LAZY_TASKS) {
tasks.withType(T::class.java).named(taskName).configure(action)
} else {
tasks.withType(T::class.java).getByName(taskName, action)
}
}

private fun <T> DomainObjectCollection<out T>.configureElement(action: T.() -> Unit) {
if (SUPPORTS_LAZY_TASKS) {
this.configureEach(action)
} else {
this.all(action)
}
}
}

internal class ErrorProneCompilerArgumentProvider(private val errorproneOptions: ErrorProneOptions) :
CommandLineArgumentProvider, Named {
internal class ErrorProneCompilerArgumentProvider(
private val errorproneOptions: ErrorProneOptions
) : CommandLineArgumentProvider, Named {

override fun getName(): String = "errorprone"

@Suppress("unused")
@Nested
@Optional
fun getErrorproneOptions(): ErrorProneOptions? {
return errorproneOptions.takeIf { it.isEnabled }
return errorproneOptions.takeIf { it.isEnabled.getOrElse(false) }
}

override fun asArguments(): Iterable<String> {
return when {
errorproneOptions.isEnabled -> listOf("-Xplugin:ErrorProne $errorproneOptions", "-XDcompilePolicy=simple")
errorproneOptions.isEnabled.getOrElse(false) -> listOf("-Xplugin:ErrorProne $errorproneOptions", "-XDcompilePolicy=simple")
else -> emptyList()
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package net.ltgt.gradle.errorprone

import org.gradle.api.DomainObjectCollection
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.util.GradleVersion

private val MIN_GRADLE_VERSION_WITH_LAZY_TASKS = GradleVersion.version("4.9")

internal fun supportsLazyTasks(version: GradleVersion) = version >= MIN_GRADLE_VERSION_WITH_LAZY_TASKS

private val SUPPORTS_LAZY_TASKS = supportsLazyTasks(GradleVersion.current())
private val SUPPORTS_LIST_PROPERTY_EMPTY = GradleVersion.current() >= GradleVersion.version("5.0")
private val SUPPORTS_PROPERTY_CONVENTION = GradleVersion.current() >= GradleVersion.version("5.1")

internal inline fun <reified T : Task> Project.configureTask(taskName: String, noinline action: T.() -> Unit) {
if (SUPPORTS_LAZY_TASKS) {
tasks.withType(T::class.java).named(taskName).configure(action)
} else {
tasks.withType(T::class.java).getByName(taskName, action)
}
}

internal fun <T> DomainObjectCollection<out T>.configureElement(action: T.() -> Unit) {
if (SUPPORTS_LAZY_TASKS) {
this.configureEach(action)
} else {
this.all(action)
}
}

internal fun <T> Property<T>.byConvention(value: T) =
if (SUPPORTS_PROPERTY_CONVENTION) {
convention(value)
} else {
apply { set(value) }
}

internal fun <T> ListProperty<T>.setEmpty() =
if (SUPPORTS_LIST_PROPERTY_EMPTY) {
empty()
} else {
// this is default behavior in Gradle 4.x
this
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ abstract class AbstractPluginIntegrationTest {
internal val errorproneVersion = System.getProperty("errorprone.version")!!
internal val errorproneJavacVersion = System.getProperty("errorprone-javac.version")!!

internal val supportsLazyTasks = ErrorPronePlugin.supportsLazyTasks(GradleVersion.version(testGradleVersion))
internal val supportsLazyTasks = supportsLazyTasks(GradleVersion.version(testGradleVersion))
internal val configureEachIfSupported = ".configureEach".takeIf { supportsLazyTasks }.orEmpty()

internal const val FAILURE_SOURCE_COMPILATION_ERROR = "Failure.java:6: error: [ArrayEquals]"
Expand Down Expand Up @@ -126,5 +126,6 @@ abstract class AbstractPluginIntegrationTest {
.withGradleVersion(testGradleVersion)
.withProjectDir(testProjectDir.root)
.withArguments(*tasks)
.forwardOutput()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ class AndroidIntegrationTest : AbstractPluginIntegrationTest() {
afterEvaluate {
tasks.withType<JavaCompile>()$configureEachIfSupported {
options.errorprone.isEnabled = false
options.errorprone.isEnabled.set(false)
}
}
""".trimIndent())
Expand Down
Loading

0 comments on commit 74ef06a

Please sign in to comment.