<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