Skip to content

Commit

Permalink
Merge pull request #17 from sergei-lapin/ignore-plugin-order
Browse files Browse the repository at this point in the history
Ignore plugin order
  • Loading branch information
sergei-lapin authored Nov 15, 2022
2 parents 3f84fc2 + effc6e6 commit f9e296a
Show file tree
Hide file tree
Showing 37 changed files with 245 additions and 150 deletions.
15 changes: 15 additions & 0 deletions plugins/gradle/src/main/java/com/slapin/napt/ConfigurationUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.slapin.napt

import org.gradle.api.Project

private const val CompilerPlugin = "io.github.sergei-lapin.napt:javac:1.2"
private const val AnnotationProcessor = "annotationProcessor"

internal fun Project.configureCompilerPluginDependency() {
val compilerPluginDependency = dependencies.create(CompilerPlugin)
configurations.all { configuration ->
if (configuration.name.contains(AnnotationProcessor, ignoreCase = true)) {
configuration.dependencies.add(compilerPluginDependency)
}
}
}
22 changes: 22 additions & 0 deletions plugins/gradle/src/main/java/com/slapin/napt/IdeaUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.slapin.napt

import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.provider.Provider
import org.gradle.plugins.ide.idea.GenerateIdeaModule
import org.gradle.plugins.ide.idea.model.IdeaModel

internal fun Project.registerTriggerDirInIdea(
triggerDir: Provider<Directory>,
) {
plugins.withId("idea") {
val triggerDirFile = triggerDir.get().asFile
extensions.findByType(IdeaModel::class.java)?.module?.let { module ->
module.sourceDirs.plusAssign(triggerDirFile)
module.generatedSourceDirs.plusAssign(triggerDirFile)
}
tasks.withType(GenerateIdeaModule::class.java).forEach { task ->
task.doFirst { triggerDirFile.mkdirs() }
}
}
}
55 changes: 55 additions & 0 deletions plugins/gradle/src/main/java/com/slapin/napt/JavaCompileUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package com.slapin.napt

import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.process.CommandLineArgumentProvider
import java.io.File

internal fun Project.configureJavaCompileTasks(
kotlinClassesDir: Provider<Directory>,
extension: NaptGradleExtension,
) {
val rootDir = rootDir
tasks.withType(JavaCompile::class.java).configureEach { javaCompile ->
javaCompile.options.compilerArgumentProviders.add(
NaptCompilerArgumentsProvider(
kotlinClassesDirPath = kotlinClassesDir.map { it.asFile.relativeTo(rootDir).toString() },
)
)
javaCompile.options.isFork = true
@Suppress("UnstableApiUsage")
javaCompile.options.forkOptions.jvmArgumentProviders.add(
NaptForkOptionsJvmArgumentsProvider(
forkJvmArgs = extension.forkJvmArgs,
jvmArgsStrongEncapsulation =
objects.listProperty(String::class.java).convention(JvmArgsStrongEncapsulation),
)
)
}
}

private class NaptCompilerArgumentsProvider(
@get:Input val kotlinClassesDirPath: Provider<String>,
) : CommandLineArgumentProvider {

override fun asArguments(): Iterable<String> {
return listOf(
"-Xplugin:Napt",
"-XDKotlinClassesDir=${File(kotlinClassesDirPath.get())}",
)
}
}

private class NaptForkOptionsJvmArgumentsProvider(
@get:Input val forkJvmArgs: ListProperty<String>,
@get:Input val jvmArgsStrongEncapsulation: ListProperty<String>,
) : CommandLineArgumentProvider {

override fun asArguments(): Iterable<String> {
return (forkJvmArgs.get() + jvmArgsStrongEncapsulation.get()).toSet()
}
}
185 changes: 37 additions & 148 deletions plugins/gradle/src/main/java/com/slapin/napt/NaptGradlePlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,175 +3,64 @@ package com.slapin.napt
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.internal.TaskManager
import com.slapin.napt.task.CreateNaptTrigger
import java.io.File
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.plugins.ide.idea.GenerateIdeaModule
import org.gradle.plugins.ide.idea.model.IdeaModel
import org.gradle.process.CommandLineArgumentProvider
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

private const val CompilerPlugin = "io.github.sergei-lapin.napt:javac:1.2"
private const val AnnotationProcessor = "annotationProcessor"
private const val MainSourceSet = "main"
import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension

class NaptGradlePlugin : Plugin<Project> {

override fun apply(target: Project) {
with(target) {
val extension = extensions.create("napt", NaptGradleExtension::class.java, objects)
insertCompilerPluginDependency()
notifyJavaCompilerAboutPlugin(extension)
bindTriggerCreation(extension)
}
}

private fun Project.insertCompilerPluginDependency() {
val compilerPluginDependency = dependencies.create(CompilerPlugin)
configurations.all { configuration ->
if (configuration.name.contains(AnnotationProcessor, ignoreCase = true)) {
configuration.dependencies.add(compilerPluginDependency)
}
plugins.withId("kotlin") { applyNaptToJvmProject(extension) }
plugins.withId("kotlin-android") { applyNaptToAndroidProject(extension) }
}
}

private fun Project.bindTriggerCreation(extension: NaptGradleExtension) {
extensions.findByType(BaseExtension::class.java)?.sourceSets?.configureEach { sourceSet ->
val triggerDir = naptTriggerDirForSourceSet(sourceSet.name)
val createTrigger =
registerCreateTriggerTaskForSourceSet(
sourceSetName = sourceSet.name,
triggerDir = triggerDir,
extension = extension,
)
registerTriggerDirInIdea(triggerDir.get().asFile)
sourceSet.java.srcDirs(createTrigger.flatMap(CreateNaptTrigger::triggerDir))
// setting srcDirs on AndroidSourceDirectorySet doesn't act the same way as with
// java SourceSet (task action is not performed during provider resolving somehow)
// so, we have to manually wire trigger generation to some early build stage
tasks.named(TaskManager.MAIN_PREBUILD).configure { preBuild ->
preBuild.dependsOn(createTrigger)
}
}
extensions.findByType(SourceSetContainer::class.java)?.configureEach { sourceSet ->
val triggerDir = naptTriggerDirForSourceSet(sourceSet.name)
private fun Project.applyNaptToJvmProject(extension: NaptGradleExtension) {
extensions.getByType(KotlinProjectExtension::class.java).sourceSets.all { kotlinSourceSet ->
val javaSourceSet =
extensions.getByType(SourceSetContainer::class.java).maybeCreate(kotlinSourceSet.name)
val createTrigger =
registerCreateTriggerTaskForSourceSet(
sourceSetName = sourceSet.name,
triggerDir = triggerDir,
configureNaptForSourceSet(
sourceSetName = javaSourceSet.name,
extension = extension,
)
registerTriggerDirInIdea(triggerDir.get().asFile)
sourceSet.java.srcDir(createTrigger.flatMap(CreateNaptTrigger::triggerDir))
javaSourceSet.java.srcDir(createTrigger.flatMap(CreateNaptTrigger::triggerDir))
}
configureJavaCompileTasks(
kotlinClassesDir = layout.buildDirectory.dir("classes/kotlin"),
extension = extension,
)
configureCompilerPluginDependency()
}

private fun Project.naptTriggerDirForSourceSet(sourceSetName: String): Provider<Directory> =
layout.buildDirectory.dir("generated/source/napt_trigger/$sourceSetName")

private fun Project.registerCreateTriggerTaskForSourceSet(
sourceSetName: String,
triggerDir: Provider<Directory>,
extension: NaptGradleExtension,
): TaskProvider<CreateNaptTrigger> =
tasks.register(
"createNaptTrigger${sourceSetName.replaceFirstChar(Char::uppercaseChar)}",
CreateNaptTrigger::class.java,
) { task ->
task.triggerDir.set(triggerDir)
task.projectName.set(name)
task.packagePrefix.set(
extension.naptTriggerPackagePrefix.orElse("").map { packagePrefix ->
buildString {
if (packagePrefix.isNotBlank()) {
append(packagePrefix)
append('.')
}
append(sourceSetName)
}
private fun Project.applyNaptToAndroidProject(extension: NaptGradleExtension) {
fun Project.applyNaptForAndroid() {
extensions.findByType(BaseExtension::class.java)?.sourceSets?.all { androidSourceSet ->
val createTrigger =
configureNaptForSourceSet(
sourceSetName = androidSourceSet.name,
extension = extension,
)
androidSourceSet.java.srcDirs(createTrigger.flatMap(CreateNaptTrigger::triggerDir))
// setting srcDirs on AndroidSourceDirectorySet doesn't act the same way as with
// java SourceSet (task action is not performed during provider resolving somehow)
// so, we have to manually wire trigger generation to some early build stage
tasks.named(TaskManager.MAIN_PREBUILD).configure { preBuild ->
preBuild.dependsOn(createTrigger)
}
)
task.onlyIf {
isNaptTriggerGenerationRequired(sourceSetName, extension) &&
extension.generateNaptTrigger.get()
}
task.group = "napt"
task.description =
"Creates NaptTrigger.java for $sourceSetName source set in order to trigger java compilation"
}

private fun Project.registerTriggerDirInIdea(
triggerDir: File,
) {
project.plugins.withId("idea") {
project.extensions.findByType(IdeaModel::class.java)?.module?.let { module ->
module.sourceDirs = module.sourceDirs + triggerDir
module.generatedSourceDirs = module.generatedSourceDirs + triggerDir
}
project.tasks.withType(GenerateIdeaModule::class.java).configureEach { task ->
task.doFirst { triggerDir.mkdirs() }
}
}
}

private fun isNaptTriggerGenerationRequired(
sourceSetName: String,
extension: NaptGradleExtension,
): Boolean =
sourceSetName == MainSourceSet ||
sourceSetName in extension.additionalSourceSetsForTriggerGeneration.get()

private fun Project.notifyJavaCompilerAboutPlugin(extension: NaptGradleExtension) {
val rootProjectDir = rootDir
tasks.withType(JavaCompile::class.java).configureEach { javaCompile ->
javaCompile.options.compilerArgumentProviders.add(
NaptCompilerArgumentsProvider(
kotlinClassesDirPath =
tasks
.withType(KotlinCompile::class.java)
.named(javaCompile.name.replace("JavaWithJavac", "Kotlin").replace("Java", "Kotlin"))
.flatMap(KotlinCompile::destinationDirectory)
.map { directory -> directory.asFile.relativeTo(rootProjectDir).path }
)
)
javaCompile.options.compilerArgs.add("-Xplugin:Napt")
javaCompile.options.isFork = true
@Suppress("UnstableApiUsage")
javaCompile.options.forkOptions.jvmArgumentProviders.add(
NaptForkOptionsJvmArgumentsProvider(
forkJvmArgs = extension.forkJvmArgs,
jvmArgsStrongEncapsulation =
objects.listProperty(String::class.java).convention(JvmArgsStrongEncapsulation),
)
configureJavaCompileTasks(
kotlinClassesDir = layout.buildDirectory.dir("tmp/kotlin-classes"),
extension = extension,
)
}
}
}

private class NaptCompilerArgumentsProvider(
@get:Input val kotlinClassesDirPath: Provider<String>,
) : CommandLineArgumentProvider {

override fun asArguments(): Iterable<String> {
return listOf(
"-Xplugin:Napt",
"-XDKotlinClassesDir=${File(kotlinClassesDirPath.get())}",
)
}
}

private class NaptForkOptionsJvmArgumentsProvider(
@get:Input val forkJvmArgs: ListProperty<String>,
@get:Input val jvmArgsStrongEncapsulation: ListProperty<String>,
) : CommandLineArgumentProvider {
override fun asArguments(): Iterable<String> {
return (forkJvmArgs.get() + jvmArgsStrongEncapsulation.get()).toSet()
plugins.withId("com.android.application") { applyNaptForAndroid() }
plugins.withId("com.android.library") { applyNaptForAndroid() }
plugins.withId("com.android.test") { applyNaptForAndroid() }
plugins.withId("com.android.dynamic-feature") { applyNaptForAndroid() }
configureCompilerPluginDependency()
}
}
65 changes: 65 additions & 0 deletions plugins/gradle/src/main/java/com/slapin/napt/SourceSetUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.slapin.napt

import com.slapin.napt.task.CreateNaptTrigger
import org.gradle.api.Project
import org.gradle.api.file.Directory
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider

private const val MainSourceSet = "main"

internal fun Project.configureNaptForSourceSet(
sourceSetName: String,
extension: NaptGradleExtension,
): TaskProvider<CreateNaptTrigger> {
val triggerDir = getNaptTriggerDirForSourceSet(sourceSetName)
val createTrigger =
registerCreateTriggerTaskForSourceSet(
sourceSetName = sourceSetName,
triggerDir = triggerDir,
extension = extension,
)
afterEvaluate { registerTriggerDirInIdea(triggerDir) }
return createTrigger
}

private fun Project.getNaptTriggerDirForSourceSet(sourceSetName: String): Provider<Directory> =
layout.buildDirectory.dir("generated/source/napt_trigger/$sourceSetName/java")

private fun Project.registerCreateTriggerTaskForSourceSet(
sourceSetName: String,
triggerDir: Provider<Directory>,
extension: NaptGradleExtension,
): TaskProvider<CreateNaptTrigger> =
tasks.register(
"createNaptTrigger${sourceSetName.replaceFirstChar(Char::uppercaseChar)}",
CreateNaptTrigger::class.java,
) { task ->
task.triggerDir.set(triggerDir)
task.projectName.set(name)
task.packagePrefix.set(
extension.naptTriggerPackagePrefix.orElse("").map { packagePrefix ->
buildString {
if (packagePrefix.isNotBlank()) {
append(packagePrefix)
append('.')
}
append(sourceSetName)
}
}
)
task.onlyIf {
shouldGenerateNaptTriggerForSourceSet(sourceSetName, extension) &&
extension.generateNaptTrigger.get()
}
task.group = "napt"
task.description =
"Creates NaptTrigger.java for '$sourceSetName' source set in order to trigger java compilation"
}

private fun shouldGenerateNaptTriggerForSourceSet(
sourceSetName: String,
extension: NaptGradleExtension,
): Boolean =
sourceSetName == MainSourceSet ||
sourceSetName in extension.additionalSourceSetsForTriggerGeneration.get()
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ android {
androidComponents { beforeVariants { builder -> builder.enable = builder.name == "debug" } }

dependencies {
implementation(project(":sample-kotlin-lib"))

implementation(libs.androidXCoreKtx)
implementation(libs.androidXAppcompat)
implementation(libs.androidXConstraintlayout)
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package com.slapin.napt.sample.dagger

import com.slapin.napt.sample.LongProviderModule
import dagger.BindsInstance
import dagger.Component

@Component
@Component(modules = [LongProviderModule::class])
interface MainActivityComponent {

val int: Int
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit f9e296a

Please sign in to comment.