| Jeff Gaston | d72edf2 | 2021-08-24 11:53:54 -0400 | [diff] [blame] | 1 | import org.jetbrains.kotlin.gradle.tasks.KotlinCompile |
| 2 | |
| 3 | apply plugin: "kotlin" |
| 4 | apply from: "../kotlin-dsl-dependency.gradle" |
| Jeff Gaston | 5e3e7de | 2022-04-21 14:49:47 -0400 | [diff] [blame^] | 5 | apply plugin: "java-gradle-plugin" |
| Jeff Gaston | d72edf2 | 2021-08-24 11:53:54 -0400 | [diff] [blame] | 6 | |
| 7 | buildscript { |
| 8 | project.ext.supportRootFolder = project.projectDir.getParentFile().getParentFile() |
| 9 | apply from: "../repos.gradle" |
| 10 | repos.addMavenRepositories(repositories) |
| 11 | dependencies { |
| 12 | classpath(libs.kotlinGradlePluginz) |
| 13 | } |
| 14 | } |
| 15 | |
| 16 | configurations { |
| 17 | // Dependencies added to these configurations get copied into the corresponding configuration |
| 18 | // (cacheableApi gets copied into api, etc). |
| 19 | // Because we cache the resolutions of these configurations, performance is faster when |
| 20 | // artifacts are put into these configurations than when those artifacts are put into their |
| 21 | // corresponding configuration. |
| 22 | cacheableApi |
| 23 | cacheableImplementation { |
| 24 | extendsFrom(project.configurations.cacheableApi) |
| 25 | } |
| 26 | cacheableRuntimeOnly |
| 27 | } |
| 28 | |
| 29 | dependencies { |
| Aurimas Liutikas | d084e36 | 2021-11-19 09:25:43 -0800 | [diff] [blame] | 30 | cacheableApi(libs.toml) |
| Alan Viverette | fdbce5c | 2022-03-14 17:00:52 +0000 | [diff] [blame] | 31 | cacheableImplementation(libs.gson) |
| Alan Viverette | 6b52a14 | 2022-03-21 16:49:27 -0400 | [diff] [blame] | 32 | cacheableImplementation(libs.dom4j) { |
| 33 | // Optional dependency where Ivy fails to parse the POM file. |
| 34 | exclude(group:"net.java.dev.msv", module:"xsdlib") |
| 35 | } |
| Jeff Gaston | d72edf2 | 2021-08-24 11:53:54 -0400 | [diff] [blame] | 36 | cacheableApi(libs.androidGradlePluginz) |
| 37 | cacheableImplementation(libs.dexMemberList) |
| 38 | cacheableApi(libs.kotlinGradlePluginz) |
| 39 | cacheableImplementation(gradleApi()) |
| 40 | cacheableApi(libs.dokkaGradlePluginz) |
| 41 | // needed by inspection plugin |
| 42 | cacheableImplementation(libs.protobufGradlePluginz) |
| 43 | cacheableImplementation(libs.wireGradlePluginz) |
| 44 | cacheableImplementation(libs.shadow) |
| 45 | // dependencies that aren't used by buildSrc directly but that we resolve here so that the |
| 46 | // root project doesn't need to re-resolve them and their dependencies on every build |
| 47 | cacheableRuntimeOnly(libs.hiltAndroidGradlePluginz) |
| 48 | // room kotlintestapp uses the ksp plugin but it does not publish a plugin marker yet |
| 49 | cacheableApi(libs.kspGradlePluginz) |
| 50 | cacheableApi(libs.japicmpPluginz) |
| 51 | // dependencies whose resolutions we don't need to cache |
| 52 | compileOnly(findGradleKotlinDsl()) // Only one file in this configuration, no need to cache it |
| 53 | implementation(project(":jetpad-integration")) // Doesn't have a .pom, so not slow to load |
| 54 | } |
| 55 | |
| 56 | // Exclude dokka coming from AGP. We don't need it and it conflicts with dackka: b/195305339 |
| 57 | configurations.configureEach { conf -> |
| 58 | conf.exclude(group:"org.jetbrains.dokka", module:"dokka-core") |
| 59 | } |
| 60 | |
| Jeff Gaston | d72edf2 | 2021-08-24 11:53:54 -0400 | [diff] [blame] | 61 | // Saves configuration into destFile |
| 62 | // Each line of destFile will be the absolute filepath of one of the files in configuration |
| 63 | def saveConfigurationResolution(configuration, destFile) { |
| 64 | def resolvedConfiguration = configuration.resolvedConfiguration |
| 65 | def files = resolvedConfiguration.files |
| 66 | def paths = files.collect { f -> f.toString() } |
| 67 | def serialized = paths.join("\n") |
| 68 | destFile.text = serialized |
| 69 | } |
| 70 | |
| 71 | // Parses a file into a list of Dependency objects representing a ResolvedConfiguration |
| 72 | def parseConfigurationResolution(savedFile, throwOnError) { |
| 73 | def savedText = savedFile.text |
| 74 | def filenames = savedText.split("\n") |
| 75 | def valid = true |
| 76 | def dependencies = filenames.collect { filename -> |
| 77 | if (!project.file(filename).exists()) { |
| 78 | if (throwOnError) { |
| 79 | throw new GradleException("\nFile " + filename + " listed as a resolved dependency in " + savedFile + " does not exist!\n\nFor more information, see b/187075069") |
| 80 | } else { |
| 81 | valid = false |
| 82 | } |
| 83 | } |
| 84 | project.dependencies.create(project.files(filename)) |
| 85 | } |
| 86 | if (!valid) { |
| 87 | return null |
| 88 | } |
| 89 | return dependencies |
| 90 | } |
| 91 | |
| 92 | // Resolves a Configuration into a list of Dependency objects |
| 93 | def resolveConfiguration(configuration) { |
| 94 | def resolvedName = configuration.name |
| 95 | def cacheDir = new File(project.buildDir, "/" + resolvedName) |
| 96 | def inputsFile = new File(cacheDir, "/deps") |
| 97 | def outputsFile = new File(cacheDir, "/result") |
| 98 | |
| 99 | def inputText = fingerprintConfiguration(configuration) |
| 100 | def parsed = null |
| 101 | if (inputsFile.exists() && inputsFile.text == inputText) { |
| 102 | // Try to parse the previously resolved configuration, but don't give up if it mentions a |
| 103 | // nonexistent file. If something has since deleted one of the referenced files, we will |
| 104 | // try to reresolve that file later |
| 105 | parsed = parseConfigurationResolution(outputsFile, false) |
| 106 | } |
| 107 | // If the configuration has changed or if any of its files have been deleted, reresolve it |
| 108 | if (parsed == null) { |
| 109 | cacheDir.mkdirs() |
| 110 | saveConfigurationResolution(configuration, outputsFile) |
| 111 | inputsFile.text = inputText |
| 112 | // confirm that the resolved configuration parses successfully |
| 113 | parsed = parseConfigurationResolution(outputsFile, true) |
| 114 | } |
| 115 | return parsed |
| 116 | } |
| 117 | |
| 118 | // Computes a unique string from a Configuration based on its dependencies |
| 119 | // This is used for up-to-date checks |
| 120 | def fingerprintConfiguration(configuration) { |
| 121 | def dependencies = configuration.allDependencies |
| 122 | def dependencyTexts = dependencies.collect { dep -> dep.group + ":" + dep.name + ":" + dep.version } |
| 123 | return dependencyTexts.join("\n") |
| 124 | } |
| 125 | |
| 126 | // Imports the contents of fromConf into toConf |
| 127 | // Uses caching to often short-circuit the resolution of fromConf |
| 128 | def loadConfigurationQuicklyInto(fromConf, toConf) { |
| 129 | def resolved = resolveConfiguration(fromConf) |
| 130 | resolved.each { dep -> |
| 131 | project.dependencies.add(toConf.name, dep) |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | loadConfigurationQuicklyInto(configurations.cacheableApi, configurations.api) |
| 136 | loadConfigurationQuicklyInto(configurations.cacheableImplementation, configurations.implementation) |
| 137 | loadConfigurationQuicklyInto(configurations.cacheableRuntimeOnly, configurations.runtimeOnly) |
| 138 | |
| 139 | project.tasks.withType(Jar) { task -> |
| 140 | task.reproducibleFileOrder = true |
| 141 | task.preserveFileTimestamps = false |
| 142 | } |
| Jeff Gaston | 5e3e7de | 2022-04-21 14:49:47 -0400 | [diff] [blame^] | 143 | |
| 144 | validatePlugins { |
| 145 | enableStricterValidation = true |
| 146 | } |