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