1 /* <lambda>null2 * Copyright 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.build 18 19 import com.google.common.annotations.VisibleForTesting 20 import java.io.File 21 import org.gradle.api.DefaultTask 22 import org.gradle.api.Project 23 import org.gradle.api.artifacts.repositories.MavenArtifactRepository 24 import org.gradle.api.file.DirectoryProperty 25 import org.gradle.api.file.RegularFileProperty 26 import org.gradle.api.plugins.JavaPluginExtension 27 import org.gradle.api.provider.Property 28 import org.gradle.api.tasks.Input 29 import org.gradle.api.tasks.InputFile 30 import org.gradle.api.tasks.Optional 31 import org.gradle.api.tasks.OutputDirectory 32 import org.gradle.api.tasks.PathSensitive 33 import org.gradle.api.tasks.PathSensitivity 34 import org.gradle.api.tasks.TaskAction 35 import org.gradle.api.tasks.TaskProvider 36 import org.gradle.kotlin.dsl.getByType 37 import org.gradle.work.DisableCachingByDefault 38 39 @DisableCachingByDefault(because = "Simply generates a small file and doesn't benefit from caching") 40 abstract class SdkResourceGenerator : DefaultTask() { 41 @get:Input lateinit var tipOfTreeMavenRepoRelativePath: String 42 43 @get:[InputFile PathSensitive(PathSensitivity.NONE)] 44 abstract val debugKeystore: RegularFileProperty 45 46 @get:Input abstract val compileSdk: Property<Int> 47 48 @get:Input abstract val buildToolsVersion: Property<String> 49 50 @get:Input abstract val minSdkVersion: Property<Int> 51 52 @get:Input abstract val agpDependency: Property<String> 53 54 @get:Input abstract val kotlinStdlib: Property<String> 55 56 @get:Input abstract val kgpVersion: Property<String> 57 58 @get:Input abstract val kspVersion: Property<String> 59 60 @get:Input lateinit var repositoryUrls: List<String> 61 62 @get:Input 63 val rootProjectRelativePath: String = 64 project.rootProject.rootDir.toRelativeString(project.projectDir) 65 66 @get:Input 67 @get:Optional 68 val prebuiltsRelativePath: String? = 69 if (ProjectLayoutType.isPlayground(project)) { 70 null 71 } else { 72 project.getPrebuiltsRoot().toRelativeString(project.projectDir) 73 } 74 75 private val projectDir: File = project.projectDir 76 77 @get:OutputDirectory abstract val outputDir: DirectoryProperty 78 79 @TaskAction 80 fun generateFile() { 81 // Note all the paths in sdk.prop have to be relative to projectDir to make this task 82 // cacheable between different computers 83 val outputFile = outputDir.file("sdk.prop") 84 outputFile.get().asFile.writer().use { writer -> 85 writer.write("tipOfTreeMavenRepoRelativePath=$tipOfTreeMavenRepoRelativePath\n") 86 writer.write( 87 "debugKeystoreRelativePath=${ 88 debugKeystore.get().asFile.toRelativeString(projectDir) 89 }\n" 90 ) 91 writer.write("rootProjectRelativePath=$rootProjectRelativePath\n") 92 val encodedRepositoryUrls = repositoryUrls.joinToString(",") 93 writer.write("repositoryUrls=$encodedRepositoryUrls\n") 94 95 writer.write("agpDependency=${agpDependency.get()}\n") 96 writer.write("kotlinStdlib=${kotlinStdlib.get()}\n") 97 writer.write("compileSdk=${compileSdk.get()}\n") 98 writer.write("buildToolsVersion=${buildToolsVersion.get()}\n") 99 writer.write("minSdkVersion=${minSdkVersion.get()}\n") 100 writer.write("kgpVersion=${kgpVersion.get()}\n") 101 writer.write("kspVersion=${kspVersion.get()}\n") 102 if (prebuiltsRelativePath != null) { 103 writer.write("prebuiltsRelativePath=$prebuiltsRelativePath\n") 104 } 105 } 106 } 107 108 companion object { 109 const val TASK_NAME = "generateSdkResource" 110 111 @JvmStatic 112 fun generateForHostTest(project: Project) { 113 val provider = registerSdkResourceGeneratorTask(project) 114 val extension = project.extensions.getByType<JavaPluginExtension>() 115 val testSources = extension.sourceSets.getByName("test") 116 testSources.output.dir(provider.flatMap { it.outputDir }) 117 } 118 119 @VisibleForTesting 120 fun registerSdkResourceGeneratorTask( 121 project: Project, 122 kspVersion: String = project.getVersionByName("ksp"), 123 agpVersion: String = project.getVersionByName("androidGradlePlugin"), 124 kgpVersion: String = project.getVersionByName("kotlin") 125 ): TaskProvider<SdkResourceGenerator> { 126 val generatedDirectory = project.layout.buildDirectory.dir("generated/resources") 127 return project.tasks.register(TASK_NAME, SdkResourceGenerator::class.java) { 128 it.tipOfTreeMavenRepoRelativePath = 129 project.getRepositoryDirectory().toRelativeString(project.projectDir) 130 it.debugKeystore.set(project.getKeystore()) 131 it.outputDir.set(generatedDirectory) 132 it.buildToolsVersion.set( 133 project.provider { project.defaultAndroidConfig.buildToolsVersion } 134 ) 135 it.minSdkVersion.set(project.defaultAndroidConfig.minSdk) 136 it.compileSdk.set(project.defaultAndroidConfig.compileSdk) 137 it.kotlinStdlib.set( 138 project.androidXConfiguration.kotlinBomVersion.map { version -> 139 "org.jetbrains.kotlin:kotlin-stdlib:$version" 140 } 141 ) 142 it.kspVersion.set(kspVersion) 143 it.agpDependency.set("com.android.tools.build:gradle:$agpVersion") 144 it.kgpVersion.set(kgpVersion) 145 // Copy repositories used for the library project so that it can replicate the same 146 // maven structure in test. 147 it.repositoryUrls = 148 project.repositories.filterIsInstance<MavenArtifactRepository>().map { 149 if (it.url.scheme == "file") { 150 // Make file paths relative to projectDir 151 File(it.url.path).toRelativeString(project.projectDir) 152 } else { 153 it.url.toString() 154 } 155 } 156 } 157 } 158 } 159 } 160