blob: 30f599cff516e967d1293d55b6284e8d9ee43032 [file] [log] [blame]
Aurimas Liutikas92d97562017-11-13 13:54:27 -08001/*
Aurimas Liutikas526389b2018-02-27 14:01:24 -08002 * Copyright 2018 The Android Open Source Project
Aurimas Liutikas92d97562017-11-13 13:54:27 -08003 *
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
Aurimas Liutikas526389b2018-02-27 14:01:24 -080017package androidx.build
Aurimas Liutikas92d97562017-11-13 13:54:27 -080018
Aurimas Liutikasc53db9a2020-10-08 17:22:52 -070019import androidx.build.checkapi.shouldConfigureApiTasks
Ember Rosec662e1a2022-09-16 14:37:50 -040020import androidx.build.transform.configureAarAsJarForConfiguration
David Saffd6a966c2022-07-26 10:54:47 -040021import com.android.build.gradle.internal.crash.afterEvaluate
Aurimas Liutikas92d97562017-11-13 13:54:27 -080022import groovy.lang.Closure
Jeff Gastonce468a92020-01-08 12:51:16 -050023import org.gradle.api.GradleException
Aurimas Liutikas92d97562017-11-13 13:54:27 -080024import org.gradle.api.Project
Aurimas Liutikas2e85edf2021-08-11 14:36:23 -070025import org.gradle.api.provider.Property
Aurimas Liutikasd084e362021-11-19 09:25:43 -080026import java.io.File
27
Aurimas Liutikas92d97562017-11-13 13:54:27 -080028/**
Jeff Gastond30e0192021-08-18 21:53:23 -040029 * Extension for [AndroidXImplPlugin] that's responsible for holding configuration options.
Aurimas Liutikas92d97562017-11-13 13:54:27 -080030 */
Aurimas Liutikasb63ef632019-04-01 04:37:49 -070031open class AndroidXExtension(val project: Project) {
Aurimas Liutikasd084e362021-11-19 09:25:43 -080032 @JvmField
33 val LibraryVersions: Map<String, Version>
34 @JvmField
35 val LibraryGroups: Map<String, LibraryGroup>
36
37 init {
38 val toml = project.objects.fileProperty().fileValue(
39 File(project.getSupportRootFolder(), "libraryversions.toml")
40 )
41 val content = project.providers.fileContents(toml)
42 val composeCustomVersion = project.providers.environmentVariable("COMPOSE_CUSTOM_VERSION")
43 val composeCustomGroup = project.providers.environmentVariable("COMPOSE_CUSTOM_GROUP")
44
Aurimas Liutikasd084e362021-11-19 09:25:43 -080045 val serviceProvider = project.gradle.sharedServices.registerIfAbsent(
46 "libraryVersionsService",
47 LibraryVersionsService::class.java
48 ) { spec ->
Aurimas Liutikas9a9efd82022-02-08 15:21:48 -080049 spec.parameters.tomlFile = content.asText
50 spec.parameters.composeCustomVersion = composeCustomVersion
51 spec.parameters.composeCustomGroup = composeCustomGroup
Aurimas Liutikasd084e362021-11-19 09:25:43 -080052 }
53 LibraryGroups = serviceProvider.get().libraryGroups
54 LibraryVersions = serviceProvider.get().libraryVersions
55 }
Owen Gray74cc2592020-09-24 15:05:40 -040056
Aurimas Liutikas2e85edf2021-08-11 14:36:23 -070057 var name: Property<String?> = project.objects.property(String::class.java)
58 fun setName(newName: String) { name.set(newName) }
Aurimas Liutikas75e93a02019-05-28 16:31:38 -070059 var mavenVersion: Version? = null
60 set(value) {
Jeff Gastonce468a92020-01-08 12:51:16 -050061 field = value
62 chooseProjectVersion()
Aurimas Liutikas75e93a02019-05-28 16:31:38 -070063 }
Oussama Ben Abdelbaki34f21e02019-02-27 13:38:27 -050064 var mavenGroup: LibraryGroup? = null
Jeff Gastonce468a92020-01-08 12:51:16 -050065 set(value) {
66 field = value
67 chooseProjectVersion()
68 }
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -040069 private val ALLOWED_EXTRA_PREFIXES = listOf("-alpha", "-beta", "-rc", "-dev", "-SNAPSHOT")
Alan Viverette30a75642020-02-07 13:09:18 -050070
Jeff Gastonce468a92020-01-08 12:51:16 -050071 private fun chooseProjectVersion() {
72 val version: Version
Rahul Ravikumarfdf66b62020-08-19 15:08:32 -070073 val group: String? = mavenGroup?.group
Aurimas Liutikasd084e362021-11-19 09:25:43 -080074 val groupVersion: Version? = mavenGroup?.atomicGroupVersion
Jeff Gastonce468a92020-01-08 12:51:16 -050075 val mavenVersion: Version? = mavenVersion
76 if (mavenVersion != null) {
Alan Viverette30a75642020-02-07 13:09:18 -050077 if (groupVersion != null && !isGroupVersionOverrideAllowed()) {
Jeff Gastonbc5a9b72020-09-18 14:06:14 -040078 throw GradleException(
79 "Cannot set mavenVersion (" + mavenVersion +
80 ") for a project (" + project +
81 ") whose mavenGroup already specifies forcedVersion (" + groupVersion +
82 ")"
83 )
Jeff Gastonce468a92020-01-08 12:51:16 -050084 } else {
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -040085 verifyVersionExtraFormat(mavenVersion)
Jeff Gastonce468a92020-01-08 12:51:16 -050086 version = mavenVersion
87 }
88 } else {
89 if (groupVersion != null) {
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -040090 verifyVersionExtraFormat(groupVersion)
Jeff Gastonce468a92020-01-08 12:51:16 -050091 version = groupVersion
92 } else {
93 return
94 }
95 }
Rahul Ravikumarfdf66b62020-08-19 15:08:32 -070096 if (group != null) {
97 project.group = group
98 }
Jeff Gastonce468a92020-01-08 12:51:16 -050099 project.version = if (isSnapshotBuild()) version.copy(extra = "-SNAPSHOT") else version
100 versionIsSet = true
101 }
Alan Viverette30a75642020-02-07 13:09:18 -0500102
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -0400103 private fun verifyVersionExtraFormat(version: Version) {
104 val extra = version.extra
105 if (extra != null) {
Igor Demin0ec97c62020-10-30 14:27:41 +0300106 if (!version.isSnapshot() && project.isVersionExtraCheckEnabled()) {
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -0400107 if (ALLOWED_EXTRA_PREFIXES.any { extra.startsWith(it) }) {
108 for (potentialPrefix in ALLOWED_EXTRA_PREFIXES) {
109 if (extra.startsWith(potentialPrefix)) {
110 val secondExtraPart = extra.removePrefix(
Jeff Gastonbc5a9b72020-09-18 14:06:14 -0400111 potentialPrefix
112 )
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -0400113 if (secondExtraPart.toIntOrNull() == null) {
Jeff Gastonbc5a9b72020-09-18 14:06:14 -0400114 throw IllegalArgumentException(
115 "Version $version is not" +
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -0400116 " a properly formatted version, please ensure that " +
Jeff Gastonbc5a9b72020-09-18 14:06:14 -0400117 "$potentialPrefix is followed by a number only"
118 )
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -0400119 }
120 }
121 }
122 } else {
Jeff Gastonbc5a9b72020-09-18 14:06:14 -0400123 throw IllegalArgumentException(
124 "Version $version is not a proper " +
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -0400125 "version, version suffixes following major.minor.patch should " +
Jeff Gastonbc5a9b72020-09-18 14:06:14 -0400126 "be one of ${ALLOWED_EXTRA_PREFIXES.joinToString(", ")}"
127 )
Oussama Ben Abdelbakif46b2122020-09-18 11:55:48 -0400128 }
129 }
130 }
131 }
132
Alan Viverette30a75642020-02-07 13:09:18 -0500133 private fun isGroupVersionOverrideAllowed(): Boolean {
134 // Grant an exception to the same-version-group policy for artifacts that haven't shipped a
135 // stable API surface, e.g. 1.0.0-alphaXX, to allow for rapid early-stage development.
136 val version = mavenVersion
137 return version != null && version.major == 1 && version.minor == 0 && version.patch == 0 &&
Jeff Gastonbc5a9b72020-09-18 14:06:14 -0400138 version.isAlpha()
Alan Viverette30a75642020-02-07 13:09:18 -0500139 }
140
Jeff Gastonce468a92020-01-08 12:51:16 -0500141 private var versionIsSet = false
142 fun isVersionSet(): Boolean {
143 return versionIsSet
144 }
Aurimas Liutikas92d97562017-11-13 13:54:27 -0800145 var description: String? = null
146 var inceptionYear: String? = null
Jeff Gastonbffebcd2020-05-28 20:24:38 +0000147 /**
148 * targetsJavaConsumers = true, if project is intended to be accessed from Java-language
149 * source code.
150 */
151 var targetsJavaConsumers = true
152 get() {
153 when (project.path) {
154 // add per-project overrides here
155 // for example
156 // the following project is intended to be accessed from Java
Louis Pullen-Freilich2dbfe872021-03-11 02:47:32 +0000157 // ":compose:lint:internal-lint-checks" -> return true
Jeff Gastonbffebcd2020-05-28 20:24:38 +0000158 // the following project is not intended to be accessed from Java
159 // ":annotation:annotation" -> return false
160 }
Owen Graya7530b82020-09-22 15:07:02 -0400161 // TODO: rework this to use LibraryType. Fork Library and KolinOnlyLibrary?
Jeff Gastonbffebcd2020-05-28 20:24:38 +0000162 if (project.path.contains("-ktx")) return false
Jeremy Woodsf3d11152021-05-03 17:08:16 -0700163 if (project.path.contains("compose")) return false
Jeff Gastonbffebcd2020-05-28 20:24:38 +0000164 if (project.path.startsWith(":ui")) return false
165 return field
166 }
Aurimas Liutikas92d97562017-11-13 13:54:27 -0800167 private var licenses: MutableCollection<License> = ArrayList()
Alan Viverette6a1a0e62020-06-26 12:48:06 -0400168
Owen Graya7530b82020-09-22 15:07:02 -0400169 // Should only be used to override LibraryType.publish, if a library isn't ready to publish yet
Owen Gray74cc2592020-09-24 15:05:40 -0400170 var publish: Publish = Publish.UNSET
Fred Sladkeyf56f2f52022-06-13 14:27:14 +0000171
172 internal fun shouldPublish(): Boolean =
173 if (publish != Publish.UNSET) {
174 publish.shouldPublish()
175 } else if (type != LibraryType.UNSET) {
Fred Sladkeyaee00da2022-07-11 14:38:59 -0400176 type.publish.shouldPublish()
Fred Sladkeyf56f2f52022-06-13 14:27:14 +0000177 } else {
178 false
179 }
180
181 internal fun shouldRelease(): Boolean =
182 if (publish != Publish.UNSET) {
183 publish.shouldRelease()
184 } else if (type != LibraryType.UNSET) {
Fred Sladkeyaee00da2022-07-11 14:38:59 -0400185 type.publish.shouldRelease()
Fred Sladkeyf56f2f52022-06-13 14:27:14 +0000186 } else {
187 false
188 }
189
David Saffd6a966c2022-07-26 10:54:47 -0400190 internal fun ifReleasing(action: () -> Unit) {
191 project.afterEvaluate {
192 if (shouldRelease()) {
193 action()
194 }
195 }
196 }
197
Fred Sladkeyf56f2f52022-06-13 14:27:14 +0000198 internal fun isPublishConfigured(): Boolean = (
199 publish != Publish.UNSET ||
Fred Sladkeyaee00da2022-07-11 14:38:59 -0400200 type.publish != Publish.UNSET
Fred Sladkeyf56f2f52022-06-13 14:27:14 +0000201 )
202
Alan Viverette6a1a0e62020-06-26 12:48:06 -0400203 /**
204 * Whether to run API tasks such as tracking and linting. The default value is
205 * [RunApiTasks.Auto], which automatically picks based on the project's properties.
206 */
Owen Graya7530b82020-09-22 15:07:02 -0400207 // TODO: decide whether we want to support overriding runApiTasks
208 // @Deprecated("Replaced with AndroidXExtension.type: LibraryType.runApiTasks")
209 var runApiTasks: RunApiTasks = RunApiTasks.Auto
Owen Gray74cc2592020-09-24 15:05:40 -0400210 get() = if (field == RunApiTasks.Auto && type != LibraryType.UNSET) type.checkApi else field
Owen Graya7530b82020-09-22 15:07:02 -0400211 var type: LibraryType = LibraryType.UNSET
Fred Sladkeyf56f2f52022-06-13 14:27:14 +0000212 set(value) {
213 // don't disable multiplatform if it's already enabled, because sometimes it's enabled
214 // through flags and we don't want setting `type =` to disable it accidentally.
Fred Sladkeyaee00da2022-07-11 14:38:59 -0400215 if (value.shouldEnableMultiplatform()) {
Fred Sladkeyf56f2f52022-06-13 14:27:14 +0000216 multiplatform = true
217 }
218 field = value
219 }
Alan Viverette6f347d72020-06-10 17:36:22 -0400220 var failOnDeprecationWarnings = true
Sergey Vasilinetse8d12f22018-07-12 16:32:26 -0700221
Aurimas Liutikasc53db9a2020-10-08 17:22:52 -0700222 var legacyDisableKotlinStrictApiMode = false
223
Sam Gilbert136fa472021-05-18 09:58:21 -0400224 var benchmarkRunAlsoInterpreted = false
225
Fred Sladkeyed2344f2022-02-01 18:25:12 -0500226 var bypassCoordinateValidation = false
227
Alan Viverettefdbce5c2022-03-14 17:00:52 +0000228 /**
Alan Viverettefdbce5c2022-03-14 17:00:52 +0000229 * Whether this project uses KMP.
Alan Viverettefdbce5c2022-03-14 17:00:52 +0000230 */
Fred Sladkeyf56f2f52022-06-13 14:27:14 +0000231 private var multiplatform: Boolean = false
Jeff Gastond72edf22021-08-24 11:53:54 -0400232 set(value) {
233 Multiplatform.setEnabledForProject(project, value)
Alan Viverettefdbce5c2022-03-14 17:00:52 +0000234 field = value
Jeff Gastond72edf22021-08-24 11:53:54 -0400235 }
David Saff9c2169a2021-07-01 10:40:47 -0400236
Aurimas Liutikasc53db9a2020-10-08 17:22:52 -0700237 fun shouldEnforceKotlinStrictApiMode(): Boolean {
238 return !legacyDisableKotlinStrictApiMode &&
239 shouldConfigureApiTasks()
240 }
241
Jim Sprochb09bbc42021-01-27 13:53:54 -0800242 fun license(closure: Closure<Any>): License {
Aurimas Liutikas92d97562017-11-13 13:54:27 -0800243 val license = project.configure(License(), closure) as License
244 licenses.add(license)
245 return license
246 }
247
248 fun getLicenses(): Collection<License> {
249 return licenses
250 }
251
Ember Rosec662e1a2022-09-16 14:37:50 -0400252 fun configureAarAsJarForConfiguration(name: String) {
253 configureAarAsJarForConfiguration(project, name)
Aurimas Liutikas7d0ea3322022-09-13 18:47:56 -0700254 }
255
Aurimas Liutikas92d97562017-11-13 13:54:27 -0800256 companion object {
Alex Saveaub50d5002020-07-14 05:25:54 +0000257 const val DEFAULT_UNSPECIFIED_VERSION = "unspecified"
Aurimas Liutikas92d97562017-11-13 13:54:27 -0800258 }
259}
260
261class License {
262 var name: String? = null
263 var url: String? = null
Jake Wharton585b8f92018-07-09 13:34:52 -0400264}
Fred Sladkeyaee00da2022-07-11 14:38:59 -0400265
266private fun LibraryType.shouldEnableMultiplatform() = this is LibraryType.KmpLibrary