• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 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 com.android.tools.metalava.buildinfo
18 
19 import com.android.tools.metalava.buildinfo.CreateAggregateLibraryBuildInfoFileTask.Companion.CREATE_AGGREGATE_BUILD_INFO_FILES_TASK
20 import com.android.tools.metalava.getDistributionDirectory
21 import com.google.gson.Gson
22 import org.gradle.api.DefaultTask
23 import org.gradle.api.Project
24 import org.gradle.api.attributes.AttributeContainer
25 import org.gradle.api.attributes.Category
26 import org.gradle.api.file.ConfigurableFileCollection
27 import org.gradle.api.tasks.InputFiles
28 import org.gradle.api.tasks.OutputFile
29 import org.gradle.api.tasks.TaskAction
30 import org.gradle.kotlin.dsl.named
31 import org.gradle.work.DisableCachingByDefault
32 import java.io.File
33 
34 /** Task for a json file of all dependencies for each artifactId */
35 @DisableCachingByDefault(because = "Not worth caching")
36 abstract class CreateAggregateLibraryBuildInfoFileTask : DefaultTask() {
37     init {
38         group = "Help"
39         description = "Generates a file containing library build information serialized to json"
40     }
41 
42     /** List of each build_info.txt file for each project. */
43     @get:InputFiles
44     abstract val libraryBuildInfoFiles: ConfigurableFileCollection
45 
46     @OutputFile
47     val outputFile =
48         File(getDistributionDirectory(project), getAndroidxAggregateBuildInfoFilename())
49 
50     private fun getAndroidxAggregateBuildInfoFilename(): String {
51         return "androidx_aggregate_build_info.txt"
52     }
53 
54     private data class AllLibraryBuildInfoFiles(val artifacts: ArrayList<LibraryBuildInfoFile>)
55 
56     /** Reads in file and checks that json is valid */
57     private fun jsonFileIsValid(jsonFile: File, artifactList: MutableList<String>): Boolean {
58         if (!jsonFile.exists()) {
59             return false
60         }
61         val gson = Gson()
62         val jsonString: String = jsonFile.readText(Charsets.UTF_8)
63         val aggregateBuildInfoFile = gson.fromJson(jsonString, AllLibraryBuildInfoFiles::class.java)
64         aggregateBuildInfoFile.artifacts.forEach { artifact ->
65             if (!artifactList.contains("${artifact.groupId}_${artifact.artifactId}")) {
66                 println("Failed to find ${artifact.artifactId} in artifact list!")
67                 return false
68             }
69         }
70         return true
71     }
72 
73     /**
74      * Create the output file to contain the final complete AndroidX project build info graph file.
75      * Iterate through the list of project-specific build info files, and collects all dependencies
76      * as a JSON string. Finally, write this complete dependency graph to a text file as a json list
77      * of every project's build information
78      */
79     @TaskAction
80     fun createAndroidxAggregateBuildInfoFile() {
81         // Loop through each file in the list of libraryBuildInfoFiles and collect all build info
82         // data from each of these $groupId-$artifactId-_build_info.txt files
83         val output = StringBuilder()
84         output.append("{ \"artifacts\": [\n")
85         val artifactList = mutableListOf<String>()
86         for (infoFile in libraryBuildInfoFiles.files) {
87             if (
88                 (infoFile.isFile and (infoFile.name != outputFile.name)) and
89                     (infoFile.name.contains("_build_info.txt"))
90             ) {
91                 val fileText: String = infoFile.readText(Charsets.UTF_8)
92                 output.append("$fileText,")
93                 artifactList.add(infoFile.name.replace("_build_info.txt", ""))
94             }
95         }
96         // Remove final ',' from list (so a null object doesn't get added to the end of the list)
97         output.setLength(output.length - 1)
98         output.append("]}")
99         outputFile.writeText(output.toString(), Charsets.UTF_8)
100         if (!jsonFileIsValid(outputFile, artifactList)) {
101             throw RuntimeException("JSON written to $outputFile was invalid.")
102         }
103     }
104 
105     companion object {
106         const val CREATE_AGGREGATE_BUILD_INFO_FILES_TASK = "createAggregateBuildInfoFiles"
107     }
108 }
109 
setBuildInfoAttributesnull110 internal fun AttributeContainer.setBuildInfoAttributes(project: Project) {
111     attribute(Category.CATEGORY_ATTRIBUTE, project.objects.named("build-info"))
112 
113 }
114 
Projectnull115 fun Project.setUpAggregateBuildInfoFileTask() {
116     val buildInfoConsumer = configurations.register("buildInfoConsumer") { configuration ->
117         configuration.isCanBeConsumed = false
118         configuration.isCanBeResolved = true
119         configuration.attributes.setBuildInfoAttributes(project)
120     }
121     subprojects { subproject ->
122         buildInfoConsumer.configure {
123             it.dependencies.add(dependencies.create(subproject))
124         }
125     }
126     val buildInfoCollection = buildInfoConsumer.map {
127         it.incoming.artifactView { it.lenient(true) }.files
128     }
129     tasks.create(
130         CREATE_AGGREGATE_BUILD_INFO_FILES_TASK,
131         CreateAggregateLibraryBuildInfoFileTask::class.java
132     ) {
133         it.libraryBuildInfoFiles.from(buildInfoCollection)
134     }
135 }
136