Skip to content

Commit a124f22

Browse files
authored
Merge pull request #44 from square/ralf/android-requirement
Allow the plugin to be used in pure JVM modules
2 parents 0883a08 + e422e30 commit a124f22

File tree

4 files changed

+47
-78
lines changed

4 files changed

+47
-78
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Next Version
44

55
* Add the annotation artifact as an `implementation` dependency instead of `api` #40.
6+
* Remove the strong dependency on the Android Gradle Plugin and allow Anvil to be used in pure JVM modules #39.
67

78
## 1.0.5-1.4-M3 (2020-07-24)
89

gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilPlugin.kt

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import org.gradle.api.Plugin
1212
import org.gradle.api.Project
1313
import org.gradle.api.plugins.AppliedPlugin
1414
import org.gradle.api.plugins.PluginManager
15+
import org.gradle.api.provider.Provider
1516
import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask
1617
import org.jetbrains.kotlin.gradle.plugin.KaptExtension
1718
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginWrapper
@@ -115,26 +116,24 @@ open class AnvilPlugin : Plugin<Project> {
115116
// compile task. If the plugin classpath changed, then DisableIncrementalCompilationTask sets
116117
// the signal to false.
117118
@Suppress("UnstableApiUsage")
118-
val incrementalSignalServiceKey = registerIncrementalSignalBuildService(project)
119-
119+
val incrementalSignal = IncrementalSignal.registerIfAbsent(project)
120120
if (isAndroidProject) {
121121
project.androidVariantsConfigure { variant ->
122122
val compileTaskName = "compile${variant.name.capitalize(US)}Kotlin"
123-
disableIncrementalCompilationAction(project, incrementalSignalServiceKey, compileTaskName)
123+
disableIncrementalCompilationAction(project, incrementalSignal, compileTaskName)
124124
}
125125
} else {
126126
// The Java plugin has two Kotlin tasks we care about: compileKotlin and compileTestKotlin.
127-
disableIncrementalCompilationAction(project, incrementalSignalServiceKey, "compileKotlin")
128-
disableIncrementalCompilationAction(project, incrementalSignalServiceKey, "compileTestKotlin")
127+
disableIncrementalCompilationAction(project, incrementalSignal, "compileKotlin")
128+
disableIncrementalCompilationAction(project, incrementalSignal, "compileTestKotlin")
129129
}
130130
}
131131

132132
fun disableIncrementalCompilationAction(
133133
project: Project,
134-
incrementalSignalServiceKey: IncrementalSignalServiceKey,
134+
incrementalSignal: Provider<IncrementalSignal>,
135135
compileTaskName: String
136136
) {
137-
138137
// Disable incremental compilation, if the compiler plugin dependency isn't up-to-date.
139138
// This will trigger a full compilation of a module using Anvil even though its
140139
// source files might not have changed. This workaround is necessary, otherwise
@@ -146,12 +145,16 @@ open class AnvilPlugin : Plugin<Project> {
146145
task.pluginClasspath.from(
147146
project.configurations.getByName(PLUGIN_CLASSPATH_CONFIGURATION_NAME)
148147
)
148+
task.incrementalSignal.set(incrementalSignal)
149149
}
150150

151151
project.tasks.named(compileTaskName, KotlinCompile::class.java) { compileTask ->
152152
compileTask.dependsOn(disableIncrementalCompilationTaskProvider)
153153
}
154154

155+
// We avoid a reference to the project in the doFirst.
156+
val projectPath = project.path
157+
155158
// If we merge the block below and the block above, it looks like
156159
// the kotlin compiler is generating byte code for
157160
// disableIncrementalCompilationTaskProvider to be visible from the doFirst block
@@ -160,7 +163,7 @@ open class AnvilPlugin : Plugin<Project> {
160163
compileTask.doFirst {
161164
// If the signal is set, then the plugin classpath changed. Apply the setting that
162165
// DisableIncrementalCompilationTask requested.
163-
val incremental = getIncrementalSignalService(incrementalSignalServiceKey).incremental
166+
val incremental = incrementalSignal.get().isIncremental(projectPath)
164167
if (incremental != null) {
165168
compileTask.incremental = incremental
166169
}

gradle-plugin/src/main/java/com/squareup/anvil/plugin/DisableIncrementalCompilationTask.kt

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ package com.squareup.anvil.plugin
44

55
import org.gradle.api.DefaultTask
66
import org.gradle.api.file.ConfigurableFileCollection
7+
import org.gradle.api.provider.Property
78
import org.gradle.api.tasks.Classpath
89
import org.gradle.api.tasks.InputFiles
10+
import org.gradle.api.tasks.Internal
911
import org.gradle.api.tasks.Optional
1012
import org.gradle.api.tasks.OutputFile
1113
import org.gradle.api.tasks.TaskAction
@@ -23,13 +25,14 @@ abstract class DisableIncrementalCompilationTask : DefaultTask() {
2325
@get:OutputFile @get:Optional
2426
val someFile = File(project.buildDir, "not-existing-file-because-gradle-needs-an-output")
2527

26-
private val serviceKey: IncrementalSignalServiceKey = IncrementalSignalServiceKey(project.path)
28+
@get:Internal
29+
abstract val incrementalSignal: Property<IncrementalSignal>
30+
31+
private val projectPath = project.path
2732

2833
@TaskAction fun toggleFlag() {
2934
// Disable incremental compilation if something in the classpath changed. If nothing has changed
3035
// in the classpath, then this task wouldn't run at all and be skipped.
31-
useIncrementalSignalService(serviceKey) {
32-
it.incremental = false
33-
}
36+
incrementalSignal.get().setIncremental(projectPath, false)
3437
}
3538
}
Lines changed: 28 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,80 +1,42 @@
1-
@file:Suppress("UnstableApiUsage")
2-
31
package com.squareup.anvil.plugin
42

5-
import com.android.build.gradle.internal.workeractions.WorkerActionServiceRegistry
6-
import com.android.ide.common.process.ProcessException
7-
import com.google.common.io.Closer
83
import org.gradle.api.Project
4+
import org.gradle.api.provider.Provider
95
import org.gradle.api.services.BuildService
106
import org.gradle.api.services.BuildServiceParameters.None
11-
import java.io.IOException
12-
import java.util.UUID
13-
14-
/** Used to get unique build service name. Each class loader will initialize it's onw version. */
15-
private val ANVIL_INCREMENTAL_SIGNAL_BUILD_SERVICE_NAME =
16-
"anvil-incremental-signal-build-service" + UUID.randomUUID()
17-
18-
/**
19-
* Registers incremental signal build service and returns a service key that can be used to access
20-
* the service later.
7+
import kotlin.random.Random
8+
9+
/*
10+
* The key is important. Gradle uses different class loaders for different modules when the plugin
11+
* is applied through the new plugins { } syntax. If we'd use the same key, then the
12+
* IncrementalSignal class would be different for the same entry and Gradle would throw an error.
13+
*
14+
* By using a random key per class loader we avoid this issue. Since this service isn't shared
15+
* across modules and only within a module it's not causing any problems tasks only use the service
16+
* for their project.
17+
*
18+
* We could also create one service per module, but that seems wasteful. When the Gradle plugin is
19+
* added to classpath of the root project, then the key is always the same and all modules share
20+
* a single build service and a single cache.
2121
*/
22-
fun registerIncrementalSignalBuildService(project: Project): IncrementalSignalServiceKey {
23-
val buildServiceProvider = project.gradle.sharedServices.registerIfAbsent(
24-
ANVIL_INCREMENTAL_SIGNAL_BUILD_SERVICE_NAME,
25-
IncrementalSignalBuildService::class.java
26-
) {}
27-
return buildServiceProvider.get()
28-
.registerIncrementalSignalService(project.path)
29-
}
30-
31-
/**
32-
* Service registry used to store IncrementalSignal services so they are accessible from the worker
33-
* actions.
34-
*/
35-
var incrementalSignalServiceRegistry: WorkerActionServiceRegistry = WorkerActionServiceRegistry()
36-
37-
/** Intended for use from worker actions. */
38-
@Throws(ProcessException::class, IOException::class)
39-
fun useIncrementalSignalService(
40-
incrementalSignalServiceKey: IncrementalSignalServiceKey,
41-
serviceRegistry: WorkerActionServiceRegistry = incrementalSignalServiceRegistry,
42-
block: (IncrementalSignalService) -> Unit
43-
) = serviceRegistry.getService(incrementalSignalServiceKey).service.let(block)
44-
45-
fun getIncrementalSignalService(
46-
incrementalSignalServiceKey: IncrementalSignalServiceKey,
47-
serviceRegistry: WorkerActionServiceRegistry = incrementalSignalServiceRegistry
48-
): IncrementalSignalService = serviceRegistry.getService(incrementalSignalServiceKey).service
49-
50-
data class IncrementalSignalServiceKey(
51-
val projectPath: String
52-
) : WorkerActionServiceRegistry.ServiceKey<IncrementalSignalService> {
53-
override val type: Class<IncrementalSignalService> get() = IncrementalSignalService::class.java
54-
}
55-
56-
data class IncrementalSignalService(var incremental: Boolean? = null)
22+
private val KEY = "incrementalSignal-" + Random.nextLong()
5723

5824
/** This signal is used to share state between the task above and Kotlin compile tasks. */
59-
abstract class IncrementalSignalBuildService : BuildService<None>, AutoCloseable {
60-
private val registeredServices = mutableSetOf<IncrementalSignalServiceKey>()
61-
private val closer = Closer.create()
25+
@Suppress("UnstableApiUsage")
26+
abstract class IncrementalSignal : BuildService<None> {
27+
private val incremental = mutableMapOf<String, Boolean?>()
6228

63-
@Synchronized
64-
fun registerIncrementalSignalService(
29+
@Synchronized fun setIncremental(
6530
projectPath: String,
66-
serviceRegistry: WorkerActionServiceRegistry = incrementalSignalServiceRegistry
67-
): IncrementalSignalServiceKey {
68-
val key = IncrementalSignalServiceKey(projectPath)
69-
70-
if (registeredServices.add(key)) {
71-
closer.register(serviceRegistry.registerServiceAsCloseable(key, IncrementalSignalService()))
72-
}
73-
74-
return key
31+
incremental: Boolean
32+
) {
33+
this.incremental[projectPath] = incremental
7534
}
7635

77-
override fun close() {
78-
closer.close()
36+
@Synchronized fun isIncremental(projectPath: String): Boolean? = incremental[projectPath]
37+
38+
companion object {
39+
fun registerIfAbsent(project: Project): Provider<IncrementalSignal> =
40+
project.gradle.sharedServices.registerIfAbsent(KEY, IncrementalSignal::class.java) { }
7941
}
8042
}

0 commit comments

Comments
 (0)