xref: /aosp_15_r20/external/robolectric/buildSrc/src/main/java/org/robolectric/gradle/ShadowsPlugin.kt (revision e6ba16074e6af37d123cb567d575f496bf0a58ee)
1 package org.robolectric.gradle
2 
3 import com.android.SdkConstants.DOT_JAVA
4 import com.android.SdkConstants.FD_GENERATED
5 import com.android.SdkConstants.FD_MAIN
6 import com.android.SdkConstants.SRC_FOLDER
7 import java.io.File
8 import java.util.jar.JarFile
9 import org.gradle.api.Plugin
10 import org.gradle.api.Project
11 import org.gradle.api.tasks.compile.JavaCompile
12 import org.gradle.api.tasks.javadoc.Javadoc
13 import org.gradle.jvm.tasks.Jar
14 import org.gradle.kotlin.dsl.create
15 import org.gradle.kotlin.dsl.extra
16 import org.gradle.kotlin.dsl.named
17 import org.gradle.kotlin.dsl.provideDelegate
18 import org.gradle.kotlin.dsl.withType
19 
20 class ShadowsPlugin : Plugin<Project> {
applynull21   override fun apply(project: Project) {
22     project.pluginManager.apply("idea")
23 
24     val shadows = project.extensions.create<ShadowsPluginExtension>("shadows")
25 
26     project.dependencies.add("annotationProcessor", project.project(":processor"))
27 
28     // Write generated Java into its own dir. See https://github.com/gradle/gradle/issues/4956
29     val generatedSrcDir =
30       project.layout.buildDirectory.dir("$FD_GENERATED/$SRC_FOLDER/apt/$FD_MAIN")
31 
32     project.tasks.named<JavaCompile>("compileJava").configure {
33       options.generatedSourceOutputDirectory.set(generatedSrcDir)
34 
35       doFirst {
36         val jsonDocsDir = project.layout.buildDirectory.dir("docs/json").get().asFile
37         val sdks = project.rootProject.layout.buildDirectory.file("sdks.txt").get().asFile
38 
39         with(options.compilerArgs) {
40           add("-Aorg.robolectric.annotation.processing.jsonDocsEnabled=true")
41           add("-Aorg.robolectric.annotation.processing.jsonDocsDir=$jsonDocsDir")
42           add("-Aorg.robolectric.annotation.processing.shadowPackage=${shadows.packageName}")
43           add("-Aorg.robolectric.annotation.processing.sdkCheckMode=${shadows.sdkCheckMode}")
44           add("-Aorg.robolectric.annotation.processing.sdks=$sdks")
45         }
46       }
47     }
48 
49     // Include the generated sources in the Javadoc jar
50     project.tasks.named<Javadoc>("javadoc").configure { source(generatedSrcDir) }
51 
52     // Verify that we have the apt-generated files in our Javadoc and sources jars
53     project.tasks.named<Jar>("javadocJar").configure {
54       doLast {
55         val shadowPackageNameDir = shadows.packageName.replace('.', '/')
56         checkForFile(archiveFile.get().asFile, "$shadowPackageNameDir/Shadows.html")
57       }
58     }
59 
60     project.tasks.named<Jar>("sourcesJar").configure {
61       from(generatedSrcDir)
62       doLast {
63         val shadowPackageNameDir = shadows.packageName.replace('.', '/')
64         checkForFile(archiveFile.get().asFile, "$shadowPackageNameDir/Shadows$DOT_JAVA")
65       }
66     }
67 
68     var configAnnotationProcessing: List<Project> by project.rootProject.extra
69     configAnnotationProcessing += project
70 
71     // Prevents sporadic compilation error:
72     // 'Bad service configuration file, or exception thrown while constructing
73     //  Processor object: javax.annotation.processing.Processor: Error reading
74     //  configuration file'
75     //
76     // See https://discuss.gradle.org/t/gradle-not-compiles-with-solder-tooling-jar/7583/20
77     project.tasks.withType<JavaCompile>().configureEach { options.isFork = true }
78   }
79 
80   abstract class ShadowsPluginExtension {
81     abstract var packageName: String
82     var sdkCheckMode: String = "WARN"
83   }
84 
85   private companion object {
checkForFilenull86     private fun checkForFile(jar: File, name: String) {
87       val hasFile = JarFile(jar).entries().asSequence().any { it.name == name }
88 
89       check(hasFile) { "Missing file $name in $jar" }
90     }
91   }
92 }
93