1 /*
2 * Copyright 2018 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.checkapi
18
19 import androidx.build.Version
20 import androidx.build.version
21 import java.io.File
22 import java.io.Serializable
23 import org.gradle.api.Project
24 import org.gradle.api.file.Directory
25 import org.gradle.api.provider.Provider
26
27 private const val BCV_DIR_NAME = "bcv"
28
29 /**
30 * Contains information about the files used to record a library's API surfaces. This class may
31 * represent a versioned API txt file or the "current" API txt file.
32 *
33 * <p>
34 * This class is responsible for understanding the naming pattern used by various types of API
35 * files:
36 * <ul>
37 * <li>public
38 * <li>restricted
39 * <li>resource
40 * </ul>
41 */
42 data class ApiLocation(
43 // Directory where the library's API files are stored
44 val apiFileDirectory: File,
45 // File where the library's public API surface is recorded
46 val publicApiFile: File,
47 // File where the library's public plus restricted (see @RestrictTo) API surfaces are recorded
48 val restrictedApiFile: File,
49 // File where the library's public resources are recorded
50 val resourceFile: File,
51 // Directory where the library's stable AIDL surface is recorded
52 val aidlApiDirectory: File,
53 // File where the API version history is recorded, for use in docs
54 val apiLevelsFile: File
55 ) : Serializable {
56
57 /**
58 * Returns the library version represented by this API location, or {@code null} if this is a
59 * current API file.
60 */
versionnull61 fun version(): Version? {
62 val baseName = publicApiFile.nameWithoutExtension
63 if (baseName == CURRENT) {
64 return null
65 }
66 return Version(baseName)
67 }
68
69 companion object {
fromPublicApiFilenull70 fun fromPublicApiFile(f: File): ApiLocation {
71 return fromBaseName(f.parentFile, f.nameWithoutExtension)
72 }
73
fromVersionnull74 fun fromVersion(apiFileDir: File, version: Version): ApiLocation {
75 return fromBaseName(apiFileDir, version.toApiFileBaseName())
76 }
77
fromCurrentnull78 fun fromCurrent(apiFileDir: File): ApiLocation {
79 return fromBaseName(apiFileDir, CURRENT)
80 }
81
isResourceApiFilenamenull82 fun isResourceApiFilename(filename: String): Boolean {
83 return filename.startsWith(PREFIX_RESOURCE)
84 }
85
fromBaseNamenull86 private fun fromBaseName(apiFileDir: File, baseName: String): ApiLocation {
87 return ApiLocation(
88 apiFileDirectory = apiFileDir,
89 publicApiFile = File(apiFileDir, "$baseName$EXTENSION"),
90 restrictedApiFile = File(apiFileDir, "$PREFIX_RESTRICTED$baseName$EXTENSION"),
91 resourceFile = File(apiFileDir, "$PREFIX_RESOURCE$baseName$EXTENSION"),
92 aidlApiDirectory = File(apiFileDir, AIDL_API_DIRECTORY_NAME).resolve(baseName),
93 apiLevelsFile = File(apiFileDir, API_LEVELS)
94 )
95 }
96
97 /** File name extension used by API files. */
98 private const val EXTENSION = ".txt"
99
100 /** Base file name used by current API files. */
101 private const val CURRENT = "current"
102
103 /** Prefix used for restricted API surface files. */
104 private const val PREFIX_RESTRICTED = "restricted_"
105
106 /** Prefix used for resource-type API files. */
107 private const val PREFIX_RESOURCE = "res-"
108
109 /** Directory name for location of AIDL API files */
110 private const val AIDL_API_DIRECTORY_NAME = "aidl"
111
112 /** File name for API version history file. */
113 private const val API_LEVELS = "apiLevels.json"
114 }
115 }
116
117 /** Converts the version to a valid API file base name. */
Versionnull118 private fun Version.toApiFileBaseName(): String {
119 return getApiFileVersion(this).toString()
120 }
121
122 /** Returns the directory containing the project's versioned and current ABI files. */
Projectnull123 fun Project.getBcvFileDirectory(): Directory = project.layout.projectDirectory.dir(BCV_DIR_NAME)
124
125 /** Returns the directory containing the project's versioned and current API files. */
126 fun Project.getApiFileDirectory(): File {
127 return File(project.projectDir, "api")
128 }
129
130 /** Returns whether the project's API file directory exists. */
Projectnull131 fun Project.hasApiFileDirectory(): Boolean {
132 return project.getApiFileDirectory().exists()
133 }
134
135 /** Returns the directory containing the project's built current API file. */
Projectnull136 private fun Project.getBuiltApiFileDirectory(): File {
137 @Suppress("DEPRECATION") return File(project.buildDir, "api")
138 }
139
140 /** Returns the directory containing the project's built current ABI file. */
Projectnull141 fun Project.getBuiltBcvFileDirectory(): Provider<Directory> =
142 project.layout.buildDirectory.dir(BCV_DIR_NAME)
143
144 /**
145 * Returns an ApiLocation with the given version, or with the project's current version if not
146 * specified. This method is guaranteed to return an ApiLocation that represents a versioned API txt
147 * and not a current API txt.
148 *
149 * @param version the project version for which an API file should be returned
150 * @return an ApiLocation representing a versioned API file
151 */
152 fun Project.getVersionedApiLocation(version: Version = project.version()): ApiLocation {
153 return ApiLocation.fromVersion(project.getApiFileDirectory(), version)
154 }
155
156 /**
157 * Returns an ApiLocation for the current version. This method is guaranteed to return an
158 * ApiLocation that represents a current API txt and not a versioned API txt.
159 */
Projectnull160 fun Project.getCurrentApiLocation(): ApiLocation {
161 return ApiLocation.fromCurrent(project.getApiFileDirectory())
162 }
163
164 /**
165 * Returns an ApiLocation for the "work-in-progress" current version which is built from tip-of-tree
166 * and lives in the build output directory.
167 */
Projectnull168 fun Project.getBuiltApiLocation(): ApiLocation {
169 return ApiLocation.fromCurrent(project.getBuiltApiFileDirectory())
170 }
171
172 /**
173 * Contains information about the files used to record a library's API compatibility and lint
174 * violation baselines.
175 *
176 * <p>
177 * This class is responsible for understanding the naming pattern used by various types of API
178 * compatibility and linting violation baseline files:
179 * <ul>
180 * <li>public API compatibility
181 * <li>restricted API compatibility
182 * <li>API lint
183 * </ul>
184 */
185 data class ApiBaselinesLocation(
186 val ignoreFileDirectory: File,
187 val publicApiFile: File,
188 val restrictedApiFile: File,
189 val apiLintFile: File
190 ) : Serializable {
191
192 companion object {
fromApiLocationnull193 fun fromApiLocation(apiLocation: ApiLocation): ApiBaselinesLocation {
194 val ignoreFileDirectory = apiLocation.apiFileDirectory
195 return ApiBaselinesLocation(
196 ignoreFileDirectory = ignoreFileDirectory,
197 publicApiFile =
198 File(
199 ignoreFileDirectory,
200 apiLocation.publicApiFile.nameWithoutExtension + EXTENSION
201 ),
202 restrictedApiFile =
203 File(
204 ignoreFileDirectory,
205 apiLocation.restrictedApiFile.nameWithoutExtension + EXTENSION
206 ),
207 apiLintFile = File(ignoreFileDirectory, "api_lint$EXTENSION")
208 )
209 }
210
211 private const val EXTENSION = ".ignore"
212 }
213 }
214