Skip to content

Commit

Permalink
[gradle-plugin] Use registerJavaGeneratingTask (#6149)
Browse files Browse the repository at this point in the history
* use connectToAllAndroidVariants()

* Only connect to main variants
  • Loading branch information
martinbonnin authored Sep 16, 2024
1 parent 2d1d25f commit f8b28a0
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 91 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -871,8 +871,12 @@ interface Service {
fun connectToAndroidSourceSet(name: String)

/**
* Connects the generated sources to all the Android variants
* Throws if the Android plugin is not applied
* Connects the generated sources to the main Android variants.
* Note: despite the name, this method does not connect to the test variants as the main
* classpath is accessible from the tests and adding the sources twice causes issues.
* See https://issuetracker.google.com/u/1/issues/268218176
*
* @throws Exception if the Android plugin is not applied
*/
fun connectToAllAndroidVariants()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
* TODO: Figure out a way to make it work with the new AGP 8.0.0 variant APIs.
* See https://issuetracker.google.com/issues/327399383
*
* When doing so it might interesting to refactor this code so that classes referencing possibly absent symbols are not loaded if not needed
* When doing so it might interesting to refactor this code so that classes referencing possibly absent symbols are not loaded if not needed.
*
* For an example, the IJ plugin calls AndroidProjectKt.androidExtension whose return type is a `BaseExtension?`. I'm not sure how come
* AndroidProjectKt links given BaseExtension is not always in the classpath.
* See https://chromium.googlesource.com/chromium/src/+/HEAD/build/android/docs/class_verification_failures.md for an Android link that does
* not apply here but gives a good description of the potential issue.
*/
Expand All @@ -13,21 +16,15 @@ package com.apollographql.apollo.gradle.internal
import com.android.build.gradle.AppExtension
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.TestedExtension
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.TestVariant
import com.android.build.gradle.api.UnitTestVariant
import com.apollographql.apollo.compiler.capitalizeFirstLetter
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.Directory
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import java.lang.reflect.Method
import java.lang.reflect.ParameterizedType

private fun Project.getVariants(): NamedDomainObjectContainer<BaseVariant> {
private fun Project.getMainVariants(): NamedDomainObjectContainer<BaseVariant> {
val container = project.container(BaseVariant::class.java)

val extension: BaseExtension = project.androidExtensionOrThrow
Expand All @@ -47,15 +44,6 @@ private fun Project.getVariants(): NamedDomainObjectContainer<BaseVariant> {
else -> error("Unsupported extension: $extension")
}

@Suppress("USELESS_IS_CHECK", "KotlinRedundantDiagnosticSuppress")
if (extension is TestedExtension) {
extension.testVariants.configureEach { variant ->
container.add(variant)
}
extension.unitTestVariants.configureEach { variant ->
container.add(variant)
}
}
return container
}

Expand All @@ -70,7 +58,7 @@ fun connectToAndroidSourceSet(
kotlinSourceSet.srcDir(outputDir)
}

project.getVariants().configureEach {
project.getMainVariants().configureEach {
if (it.sourceSets.any { it.name == sourceSetName }) {
if (kotlinSourceSet == null) {
it.registerJavaGeneratingTask(taskProvider, outputDir.get().asFile)
Expand All @@ -85,81 +73,17 @@ fun connectToAndroidSourceSet(
}
}

/**
* This uses https://cs.android.com/android-studio/platform/tools/base/+/mirror-goog-studio-main:build-system/gradle-core/src/main/java/com/android/build/gradle/api/BaseVariant.java;l=539;drc=5ac687029454dec1e7bd50697dabbc24d5a9943c
*
* There's a newer API in 7.3 where AGP decides where the sources are put but we're not using that just yet
* https://github.com/android/gradle-recipes/blob/agp-7.3/Kotlin/addJavaSourceFromTask/app/build.gradle.kts
*/
private val lazyRegisterJavaGeneratingTask: Method? = BaseVariant::class.java.declaredMethods.singleOrNull {
if (it.name != "registerJavaGeneratingTask") {
return@singleOrNull false
}

if (it.parameters.size != 2) {
return@singleOrNull false
}
val parameter0Type = it.parameters[0].parameterizedType
if (parameter0Type !is ParameterizedType) {
return@singleOrNull false
}
if (parameter0Type.rawType.typeName != "org.gradle.api.tasks.TaskProvider") {
return@singleOrNull false
}
val parameter1Type = it.parameters[1].parameterizedType
if (parameter1Type !is ParameterizedType) {
return@singleOrNull false
}
if (parameter1Type.rawType.typeName != "java.util.Collection") {
return@singleOrNull false
}
if (parameter1Type.actualTypeArguments.size != 1) {
return@singleOrNull false
}
if (parameter1Type.actualTypeArguments.single().typeName != "java.io.File") {
return@singleOrNull false
}

true
}

fun connectToAndroidVariant(project: Project, variant: Any, outputDir: Provider<Directory>, taskProvider: TaskProvider<out Task>) {
fun connectToAndroidVariant(variant: Any, outputDir: Provider<Directory>, taskProvider: TaskProvider<out Task>) {
check(variant is BaseVariant) {
"Apollo: variant must be an instance of com.android.build.gradle.api.BaseVariant (found $variant)"
}

if (lazyRegisterJavaGeneratingTask != null) {
lazyRegisterJavaGeneratingTask.invoke(variant, taskProvider, listOf(outputDir.get().asFile))
} else {
/**
* Heuristic to get the variant-specific sourceSet from the variant name
* demoDebugAndroidTest -> androidTestDemoDebug
* demoDebugUnitTest -> testDemoDebug
* demoDebug -> demoDebug
*/
val sourceSetName = when {
variant is TestVariant && variant.name.endsWith("AndroidTest") -> {
"androidTest${variant.name.removeSuffix("AndroidTest").capitalizeFirstLetter()}"
}

variant is UnitTestVariant && variant.name.endsWith("UnitTest") -> {
"test${variant.name.removeSuffix("UnitTest").capitalizeFirstLetter()}"
}

else -> variant.name
}

connectToAndroidSourceSet(project, sourceSetName, outputDir, taskProvider)
}
variant.registerJavaGeneratingTask(taskProvider, listOf(outputDir.get().asFile))
}

fun connectToAllAndroidVariants(project: Project, outputDir: Provider<Directory>, taskProvider: TaskProvider<out Task>) {
if (lazyRegisterJavaGeneratingTask != null) {
project.getVariants().configureEach {
lazyRegisterJavaGeneratingTask.invoke(it, taskProvider, listOf(outputDir.get().asFile))
}
} else {
connectToAndroidSourceSet(project, "main", outputDir, taskProvider)
project.getMainVariants().configureEach {
connectToAndroidVariant(it, outputDir, taskProvider)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -829,8 +829,7 @@ abstract class DefaultApolloExtension(
}

project.androidExtension != null -> {
// The default service is created from `afterEvaluate` and it looks like it's too late to register new sources
connection.connectToAndroidSourceSet("main")
connection.connectToAllAndroidVariants()
}

project.kotlinProjectExtension != null -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ internal class DefaultDirectoryConnection(
}

override fun connectToAndroidVariant(variant: Any) {
connectToAndroidVariant(project, variant, outputDir, task)
connectToAndroidVariant(variant, outputDir, task)
}

override fun connectToAndroidSourceSet(name: String) {
Expand Down

0 comments on commit f8b28a0

Please sign in to comment.