1 /*
<lambda>null2  * Copyright 2022 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.buildInfo
18 
19 import androidx.build.buildInfo.CreateAggregateLibraryBuildInfoFileTask.Companion.CREATE_AGGREGATE_BUILD_INFO_FILES_TASK
20 import androidx.build.getDistributionDirectory
21 import androidx.build.jetpad.LibraryBuildInfoFile
22 import com.google.gson.Gson
23 import java.io.File
24 import org.gradle.api.DefaultTask
25 import org.gradle.api.Project
26 import org.gradle.api.provider.ListProperty
27 import org.gradle.api.provider.Provider
28 import org.gradle.api.tasks.Input
29 import org.gradle.api.tasks.OutputFile
30 import org.gradle.api.tasks.TaskAction
31 import org.gradle.work.DisableCachingByDefault
32 
33 /** Task for a json file of all dependencies for each artifactId */
34 @DisableCachingByDefault(because = "Not worth caching")
35 abstract class CreateAggregateLibraryBuildInfoFileTask : DefaultTask() {
36     init {
37         group = "Help"
38         description = "Generates a file containing library build information serialized to json"
39     }
40 
41     /** List of each build_info.txt file for each project. */
42     @get:Input abstract val libraryBuildInfoFiles: ListProperty<File>
43 
44     @OutputFile
45     val outputFile =
46         File(project.getDistributionDirectory(), getAndroidxAggregateBuildInfoFilename())
47 
48     private fun getAndroidxAggregateBuildInfoFilename(): String {
49         return "androidx_aggregate_build_info.txt"
50     }
51 
52     private data class AllLibraryBuildInfoFiles(val artifacts: ArrayList<LibraryBuildInfoFile>)
53 
54     /** Reads in file and checks that json is valid */
55     private fun jsonFileIsValid(jsonFile: File, artifactList: MutableList<String>): Boolean {
56         if (!jsonFile.exists()) {
57             return false
58         }
59         val gson = Gson()
60         val jsonString: String = jsonFile.readText(Charsets.UTF_8)
61         val aggregateBuildInfoFile = gson.fromJson(jsonString, AllLibraryBuildInfoFiles::class.java)
62         aggregateBuildInfoFile.artifacts.forEach { artifact ->
63             if (!artifactList.contains("${artifact.groupId}_${artifact.artifactId}")) {
64                 println("Failed to find ${artifact.artifactId} in artifact list!")
65                 return false
66             }
67         }
68         return true
69     }
70 
71     /**
72      * Create the output file to contain the final complete AndroidX project build info graph file.
73      * Iterate through the list of project-specific build info files, and collects all dependencies
74      * as a JSON string. Finally, write this complete dependency graph to a text file as a json list
75      * of every project's build information
76      */
77     @TaskAction
78     fun createAndroidxAggregateBuildInfoFile() {
79         // Loop through each file in the list of libraryBuildInfoFiles and collect all build info
80         // data from each of these $groupId-$artifactId-_build_info.txt files
81         val output = StringBuilder()
82         output.append("{ \"artifacts\": [\n")
83         val artifactList = mutableListOf<String>()
84         for (infoFile in libraryBuildInfoFiles.get()) {
85             if (
86                 (infoFile.isFile and (infoFile.name != outputFile.name)) and
87                     (infoFile.name.contains("_build_info.txt"))
88             ) {
89                 val fileText: String = infoFile.readText(Charsets.UTF_8)
90                 output.append("$fileText,")
91                 artifactList.add(infoFile.name.replace("_build_info.txt", ""))
92             }
93         }
94         // Remove final ',' from list (so a null object doesn't get added to the end of the list)
95         output.setLength(output.length - 1)
96         output.append("]}")
97         outputFile.writeText(output.toString(), Charsets.UTF_8)
98         if (!jsonFileIsValid(outputFile, artifactList)) {
99             throw RuntimeException("JSON written to $outputFile was invalid.")
100         }
101     }
102 
103     companion object {
104         const val CREATE_AGGREGATE_BUILD_INFO_FILES_TASK = "createAggregateBuildInfoFiles"
105     }
106 }
107 
Projectnull108 fun Project.addTaskToAggregateBuildInfoFileTask(task: Provider<CreateLibraryBuildInfoFileTask>) {
109     rootProject.tasks.named(CREATE_AGGREGATE_BUILD_INFO_FILES_TASK).configure {
110         val aggregateLibraryBuildInfoFileTask = it as CreateAggregateLibraryBuildInfoFileTask
111         aggregateLibraryBuildInfoFileTask.libraryBuildInfoFiles.add(
112             task.flatMap { task -> task.outputFile.asFile }
113         )
114     }
115 }
116