• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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
18 
19 import com.android.tools.metalava.LibraryBuildInfoFile.Check
20 import com.google.gson.GsonBuilder
21 import org.gradle.api.DefaultTask
22 import org.gradle.api.GradleException
23 import org.gradle.api.Project
24 import org.gradle.api.provider.Property
25 import org.gradle.api.tasks.Input
26 import org.gradle.api.tasks.OutputFile
27 import org.gradle.api.tasks.TaskAction
28 import org.gradle.api.tasks.TaskProvider
29 import java.io.File
30 import java.util.concurrent.TimeUnit
31 
32 const val CREATE_BUILD_INFO_TASK = "createBuildInfo"
33 
34 abstract class CreateLibraryBuildInfoTask : DefaultTask() {
35     @get:Input
36     abstract val artifactId: Property<String>
37     @get:Input
38     abstract val groupId: Property<String>
39     @get:Input
40     abstract val version: Property<String>
41     @get:Input
42     abstract val sha: Property<String>
43 
44     @get:OutputFile
45     abstract val outputFile: Property<File>
46 
47     @get:OutputFile
48     abstract val aggregateOutputFile: Property<File>
49 
50     @TaskAction
createFilenull51     fun createFile() {
52         val info = LibraryBuildInfoFile()
53         info.artifactId = artifactId.get()
54         info.groupId = groupId.get()
55         info.groupIdRequiresSameVersion = false
56         info.version = version.get()
57         info.path = "/"
58         info.sha = sha.get()
59         info.dependencies = arrayListOf()
60         info.checks = arrayListOf()
61         val gson = GsonBuilder().setPrettyPrinting().create()
62         val serializedInfo: String = gson.toJson(info)
63         outputFile.get().writeText(serializedInfo)
64 
65         aggregateOutputFile.get().let {
66             it.writeText("{ \"artifacts\": [\n")
67             it.appendText(serializedInfo)
68             it.appendText("]}")
69         }
70     }
71 }
72 
configureBuildInfoTasknull73 fun configureBuildInfoTask(
74     project: Project,
75     inCI: Boolean,
76     distributionDirectory: File
77 ): TaskProvider<CreateLibraryBuildInfoTask> {
78     return project.tasks.register(CREATE_BUILD_INFO_TASK, CreateLibraryBuildInfoTask::class.java) {
79         it.artifactId.set(project.provider<String> { project.name })
80         it.groupId.set(project.provider<String> { project.group as String })
81         it.version.set(project.provider<String> { project.version as String })
82         // Only set sha when in CI to keep local builds faster
83         it.sha.set(project.provider<String> { if (inCI) getGitSha(project.projectDir) else "" })
84         it.outputFile.set(project.provider<File> {
85             File(
86                 distributionDirectory,
87                 "build-info/${project.group}_${project.name}_build_info.txt"
88             )
89         })
90         it.aggregateOutputFile.set(project.provider<File> {
91             File(distributionDirectory, "androidx_aggregate_build_info.txt")}
92         )
93     }
94 }
95 
getGitShanull96 fun getGitSha(directory: File): String {
97     val process = ProcessBuilder("git", "rev-parse", "--verify", "HEAD")
98         .directory(directory)
99         .redirectOutput(ProcessBuilder.Redirect.PIPE)
100         .redirectError(ProcessBuilder.Redirect.PIPE)
101         .start()
102     // Read output, waiting for process to finish, as needed
103     val stdout = process.inputStream.bufferedReader().readText()
104     val stderr = process.errorStream.bufferedReader().readText()
105     val message = stdout + stderr
106     // wait potentially a little bit longer in case Git was waiting for us to
107     // read its response before it exited
108     process.waitFor(10, TimeUnit.SECONDS)
109     if (stderr != "") {
110         throw GradleException("Unable to call git. Response was: $message")
111     }
112     check(process.exitValue() == 0) { "Nonzero exit value running git command." }
113     return stdout.trim()
114 }
115 
116 /**
117  * Object outlining the format of a library's build info file.
118  * This object will be serialized to json.
119  * This file should match the corresponding class in Jetpad because
120  * this object will be serialized to json and the result will be parsed by Jetpad.
121  * DO NOT TOUCH.
122  *
123  * @property groupId library maven group Id
124  * @property artifactId library maven artifact Id
125  * @property version library maven version
126  * @property path local project directory path used for development, rooted at framework/support
127  * @property sha the sha of the latest commit to modify the library (aka a commit that
128  * touches a file within [path])
129  * @property groupIdRequiresSameVersion boolean that determines if all libraries with [groupId]
130  * have the same version
131  * @property dependencies a list of dependencies on other androidx libraries
132  * @property checks arraylist of [Check]s that is used by Jetpad
133  */
134 @Suppress("UNUSED")
135 class LibraryBuildInfoFile {
136     var groupId: String? = null
137     var artifactId: String? = null
138     var version: String? = null
139     var path: String? = null
140     var sha: String? = null
141     var groupIdRequiresSameVersion: Boolean? = null
142     var dependencies: ArrayList<Dependency> = arrayListOf()
143     var checks: ArrayList<Check> = arrayListOf()
144 
145     /**
146      * @property isTipOfTree boolean that specifies whether the dependency is tip-of-tree
147      */
148     inner class Dependency {
149         var groupId: String? = null
150         var artifactId: String? = null
151         var version: String? = null
152         var isTipOfTree = false
153     }
154 
155     inner class Check {
156         var name: String? = null
157         var passing = false
158     }
159 }