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