| import org.jetbrains.kotlin.gradle.tasks.KotlinCompile |
| |
| buildscript { |
| project.ext.supportRootFolder = project.projectDir.getParentFile() |
| repositories { |
| maven { |
| url("${supportRootFolder}/../../prebuilts/androidx/external") |
| } |
| } |
| |
| dependencies { |
| classpath(libs.kotlinGradlePlugin) |
| classpath(libs.kgpLeakPatcher) // KT-46368 |
| } |
| |
| configurations.classpath.resolutionStrategy { |
| eachDependency { details -> |
| if (details.requested.group == "org.jetbrains.kotlin") { |
| details.useVersion libs.versions.kotlin.get() |
| } |
| } |
| } |
| } |
| |
| apply from: "out.gradle" |
| init.chooseOutDir() |
| |
| ext.supportRootFolder = project.projectDir.getParentFile() |
| apply from: "local_dokka.gradle" |
| apply from: "repos.gradle" |
| apply plugin: "kotlin" |
| apply from: "kotlin-dsl-dependency.gradle" |
| |
| allprojects { |
| repos.addMavenRepositories(repositories) |
| |
| tasks.withType(KotlinCompile).configureEach { |
| kotlinOptions { |
| jvmTarget = "1.8" |
| freeCompilerArgs += [ |
| "-Werror", |
| "-Xskip-runtime-version-check", |
| "-Xskip-metadata-version-check", |
| // Allow `@OptIn` and `@UseExperimental` |
| "-Xopt-in=kotlin.RequiresOptIn", |
| // Issue where sam conversion in gradle's kts file causes task-out-of-date |
| // Details: KT-46445 and https://github.com/gradle/gradle/issues/17052 |
| "-Xsam-conversions=class" |
| ] |
| } |
| } |
| } |
| |
| configurations { |
| // Dependencies added to these configurations get copied into the corresponding configuration |
| // (cacheableApi gets copied into api, etc). |
| // Because we cache the resolutions of these configurations, performance is faster when |
| // artifacts are put into these configurations than when those artifacts are put into their |
| // corresponding configuration. |
| cacheableApi |
| cacheableImplementation { |
| extendsFrom(project.configurations.cacheableApi) |
| } |
| cacheableRuntimeOnly |
| } |
| |
| dependencies { |
| cacheableApi(libs.androidGradlePlugin) |
| cacheableImplementation(libs.dexMemberList) |
| cacheableApi(libs.kotlinGradlePlugin) |
| cacheableImplementation(libs.kotlinPoet) |
| cacheableImplementation(gradleApi()) |
| cacheableApi(libs.dokkaGradlePlugin) |
| // needed by inspection plugin |
| cacheableImplementation(libs.protobufGradlePlugin) |
| cacheableImplementation(libs.wireGradlePlugin) |
| cacheableImplementation(libs.shadow) |
| // dependencies that aren't used by buildSrc directly but that we resolve here so that the |
| // root project doesn't need to re-resolve them and their dependencies on every build |
| cacheableRuntimeOnly(libs.hiltAndroidGradlePlugin) |
| // room kotlintestapp uses the ksp plugin but it does not publish a plugin marker yet |
| cacheableApi(libs.kspGradlePlugin) |
| cacheableApi(libs.kgpLeakPatcher) |
| // dependencies whose resolutions we don't need to cache |
| compileOnly(findGradleKotlinDsl()) // Only one file in this configuration, no need to cache it |
| implementation(project("jetpad-integration")) // Doesn't have a .pom, so not slow to load |
| } |
| |
| apply plugin: "java-gradle-plugin" |
| apply plugin: "dev.zacsweers.kgp-150-leak-patcher" |
| |
| sourceSets { |
| main.java.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/kotlin" |
| main.resources.srcDirs += "${supportRootFolder}/benchmark/gradle-plugin/src/main/resources" |
| |
| main.java.srcDirs += "${supportRootFolder}/inspection/inspection-gradle-plugin/src/main/kotlin" |
| main.resources.srcDirs += "${supportRootFolder}/inspection/inspection-gradle-plugin/src/main" + |
| "/resources" |
| |
| main.java.srcDirs += "${supportRootFolder}/compose/material/material/icons/generator/src/main" + |
| "/kotlin" |
| } |
| |
| gradlePlugin { |
| plugins { |
| benchmark { |
| id = "androidx.benchmark" |
| implementationClass = "androidx.benchmark.gradle.BenchmarkPlugin" |
| } |
| inspection { |
| id = "androidx.inspection" |
| implementationClass = "androidx.inspection.gradle.InspectionPlugin" |
| } |
| } |
| } |
| |
| // Saves configuration into destFile |
| // Each line of destFile will be the absolute filepath of one of the files in configuration |
| def saveConfigurationResolution(configuration, destFile) { |
| def resolvedConfiguration = configuration.resolvedConfiguration |
| def files = resolvedConfiguration.files |
| def paths = files.collect { f -> f.toString() } |
| def serialized = paths.join("\n") |
| destFile.text = serialized |
| } |
| |
| // Parses a file into a list of Dependency objects representing a ResolvedConfiguration |
| def parseConfigurationResolution(savedFile, throwOnError) { |
| def savedText = savedFile.text |
| def filenames = savedText.split("\n") |
| def valid = true |
| def dependencies = filenames.collect { filename -> |
| if (!project.file(filename).exists()) { |
| if (throwOnError) { |
| throw new GradleException("\nFile " + filename + " listed as a resolved dependency in " + savedFile + " does not exist!\n\nFor more information, see b/187075069") |
| } else { |
| valid = false |
| } |
| } |
| project.dependencies.create(project.files(filename)) |
| } |
| if (!valid) { |
| return null |
| } |
| return dependencies |
| } |
| |
| // Resolves a Configuration into a list of Dependency objects |
| def resolveConfiguration(configuration) { |
| def resolvedName = configuration.name |
| def cacheDir = new File(project.buildDir, "/" + resolvedName) |
| def inputsFile = new File(cacheDir, "/deps") |
| def outputsFile = new File(cacheDir, "/result") |
| |
| def inputText = fingerprintConfiguration(configuration) |
| def parsed = null |
| if (inputsFile.exists() && inputsFile.text == inputText) { |
| // Try to parse the previously resolved configuration, but don't give up if it mentions a |
| // nonexistent file. If something has since deleted one of the referenced files, we will |
| // try to reresolve that file later |
| parsed = parseConfigurationResolution(outputsFile, false) |
| } |
| // If the configuration has changed or if any of its files have been deleted, reresolve it |
| if (parsed == null) { |
| cacheDir.mkdirs() |
| saveConfigurationResolution(configuration, outputsFile) |
| inputsFile.text = inputText |
| // confirm that the resolved configuration parses successfully |
| parsed = parseConfigurationResolution(outputsFile, true) |
| } |
| return parsed |
| } |
| |
| // Computes a unique string from a Configuration based on its dependencies |
| // This is used for up-to-date checks |
| def fingerprintConfiguration(configuration) { |
| def dependencies = configuration.allDependencies |
| def dependencyTexts = dependencies.collect { dep -> dep.group + ":" + dep.name + ":" + dep.version } |
| return dependencyTexts.join("\n") |
| } |
| |
| // Imports the contents of fromConf into toConf |
| // Uses caching to often short-circuit the resolution of fromConf |
| def loadConfigurationQuicklyInto(fromConf, toConf) { |
| def resolved = resolveConfiguration(fromConf) |
| resolved.each { dep -> |
| project.dependencies.add(toConf.name, dep) |
| } |
| } |
| |
| loadConfigurationQuicklyInto(configurations.cacheableApi, configurations.api) |
| loadConfigurationQuicklyInto(configurations.cacheableImplementation, configurations.implementation) |
| loadConfigurationQuicklyInto(configurations.cacheableRuntimeOnly, configurations.runtimeOnly) |
| |
| project.tasks.withType(Jar) { task -> |
| task.reproducibleFileOrder = true |
| task.preserveFileTimestamps = false |
| } |