xref: /aosp_15_r20/external/robolectric/buildSrc/src/main/java/org/robolectric/gradle/AarDepsPlugin.kt (revision e6ba16074e6af37d123cb567d575f496bf0a58ee)

<lambda>null1 package org.robolectric.gradle
2 
3 import com.android.SdkConstants.DOT_JAR
4 import com.android.SdkConstants.EXT_AAR
5 import com.android.SdkConstants.EXT_JAR
6 import com.android.SdkConstants.FD_JARS
7 import com.android.SdkConstants.FN_CLASSES_JAR
8 import java.io.File
9 import java.util.concurrent.atomic.AtomicReference
10 import javax.inject.Inject
11 import org.gradle.api.Plugin
12 import org.gradle.api.Project
13 import org.gradle.api.artifacts.transform.TransformOutputs
14 import org.gradle.api.artifacts.type.ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE
15 import org.gradle.api.file.FileCollection
16 import org.gradle.api.tasks.compile.JavaCompile
17 import org.gradle.kotlin.dsl.registerTransform
18 import org.gradle.kotlin.dsl.withType
19 import org.robolectric.gradle.agp.ExtractAarTransform
20 
21 /** Resolve AAR dependencies into jars for non-Android projects. */
22 @Suppress("unused")
23 class AarDepsPlugin : Plugin<Project> {
24   override fun apply(project: Project) {
25     project.dependencies.registerTransform(ClassesJarExtractor::class) {
26       parameters.projectName.set(project.name)
27       from.attribute(ARTIFACT_TYPE_ATTRIBUTE, EXT_AAR)
28       to.attribute(ARTIFACT_TYPE_ATTRIBUTE, EXT_JAR)
29     }
30 
31     project.afterEvaluate {
32       configurations.forEach { configuration ->
33         // I suspect we're meant to use the org.gradle.usage attribute, but this works.
34         if (configuration.name.endsWith("Classpath")) {
35           configuration.attributes { attribute(ARTIFACT_TYPE_ATTRIBUTE, EXT_JAR) }
36         }
37       }
38     }
39 
40     // Warn if any AARs do make it through somehow; there must be a Gradle configuration
41     // that isn't matched above.
42     project.tasks.withType<JavaCompile>().forEach { task ->
43       task.doFirst {
44         val aarFiles = findAarFiles(task.classpath)
45 
46         check(aarFiles.isEmpty()) { "AARs on classpath: " + aarFiles.joinToString("\n  ") }
47       }
48     }
49   }
50 
51   private fun findAarFiles(files: FileCollection): List<File> {
52     return files.files.filter { it.name.lowercase().endsWith(".$EXT_AAR") }
53   }
54 
55   /** Extracts classes.jar from an AAR. */
56   abstract class ClassesJarExtractor @Inject constructor() : ExtractAarTransform() {
57     override fun transform(outputs: TransformOutputs) {
58       val classesJarFile = AtomicReference<File>()
59       val outJarFile = AtomicReference<File>()
60 
61       val transformOutputs =
62         object : TransformOutputs {
63           // This is the one that ExtractAarTransform calls.
64           override fun dir(path: Any): File {
65             // ExtractAarTransform needs a place to extract the AAR. We don't really need to
66             // register this as an output, but it'd be tricky to avoid it.
67             val dir = outputs.dir(path)
68 
69             // Also, register our jar file. Its name needs to be quasi-unique or IntelliJ
70             // Gradle/Android plugins get confused.
71             classesJarFile.set(File(File(dir, FD_JARS), FN_CLASSES_JAR))
72             outJarFile.set(File(File(dir, FD_JARS), "$path$DOT_JAR"))
73             outputs.file("$path/$FD_JARS/$path$DOT_JAR")
74 
75             return outputs.dir(path)
76           }
77 
78           override fun file(path: Any): File {
79             error("Shouldn't be called")
80           }
81         }
82 
83       super.transform(transformOutputs)
84 
85       classesJarFile.get().renameTo(outJarFile.get())
86     }
87   }
88 }
89