Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[gradle-plugin] Use registerJavaGeneratingTask #6149

Merged
merged 2 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading