blob: a4b94c1140c405c86f549a15bc6ba82e7820ad1d [file] [log] [blame]
/*
* Copyright 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.baselineprofile.gradle.consumer
import javax.inject.Inject
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.model.ObjectFactory
/**
* Allows specifying settings for the Baseline Profile Consumer Plugin.
*/
abstract class BaselineProfileConsumerExtension @Inject constructor(
objectFactory: ObjectFactory
) : BaselineProfileVariantConfiguration {
companion object {
private const val EXTENSION_NAME = "baselineProfile"
internal fun registerExtension(project: Project): BaselineProfileConsumerExtension {
val ext = project.extensions.findByType(BaselineProfileConsumerExtension::class.java)
if (ext != null) {
return ext
}
return project
.extensions.create(EXTENSION_NAME, BaselineProfileConsumerExtension::class.java)
}
}
val variants: NamedDomainObjectContainer<BaselineProfileVariantConfigurationImpl> =
objectFactory.domainObjectContainer(BaselineProfileVariantConfigurationImpl::class.java)
// Shortcut to access the "main" variant.
private val main: BaselineProfileVariantConfiguration = variants.create("main") {
// These are the default global settings.
it.mergeIntoMain = null
it.baselineProfileOutputDir = "generated/baselineProfiles"
it.enableR8BaselineProfileRewrite = false
it.saveInSrc = true
it.automaticGenerationDuringBuild = false
}
/**
* Controls the global [BaselineProfileVariantConfiguration.enableR8BaselineProfileRewrite].
* Note that this value is overridden by per variant configurations.
*/
override var enableR8BaselineProfileRewrite: Boolean?
get() = main.enableR8BaselineProfileRewrite
set(value) {
main.enableR8BaselineProfileRewrite = value
}
/**
* Controls the global [BaselineProfileVariantConfiguration.saveInSrc].
* Note that this value is overridden by per variant configurations.
*/
override var saveInSrc: Boolean?
get() = main.saveInSrc
set(value) {
main.saveInSrc = value
}
/**
* Controls the global [BaselineProfileVariantConfiguration.automaticGenerationDuringBuild].
* Note that this value is overridden by per variant configurations.
*/
override var automaticGenerationDuringBuild: Boolean?
get() = main.automaticGenerationDuringBuild
set(value) {
main.automaticGenerationDuringBuild = value
}
/**
* Controls the global [BaselineProfileVariantConfiguration.baselineProfileOutputDir].
* Note that this value is overridden by per variant configurations.
*/
override var baselineProfileOutputDir: String?
get() = main.baselineProfileOutputDir
set(value) {
main.baselineProfileOutputDir = value
}
/**
* Controls the global [BaselineProfileVariantConfiguration.mergeIntoMain].
* Note that this value is overridden by per variant configurations.
*/
override var mergeIntoMain: Boolean?
get() = main.mergeIntoMain
set(value) {
main.mergeIntoMain = value
}
/**
* Applies the global [BaselineProfileVariantConfiguration.filter].
* This function is just a shortcut for `baselineProfiles.variants.main.filters { }`
*/
override fun filter(action: FilterRules.() -> (Unit)) = main.filter(action)
/**
* Applies the global [BaselineProfileVariantConfiguration.filter].
* This function is just a shortcut for `baselineProfiles.variants.main.filters { }`
*/
override fun filter(action: Action<FilterRules>) = main.filter(action)
/**
* Applies global dependencies for baseline profiles. This has the same effect of defining
* a baseline profile dependency in the dependency block. For example:
* ```
* dependencies {
* baselineProfile(project(":baseline-profile"))
* }
* ```
*/
override fun from(project: Project, variantName: String?) = main.from(project, variantName)
fun variants(
action: Action<NamedDomainObjectContainer<BaselineProfileVariantConfigurationImpl>>
) {
action.execute(variants)
}
fun variants(
action: NamedDomainObjectContainer<out BaselineProfileVariantConfigurationImpl>.() -> Unit
) {
action.invoke(variants)
}
}
abstract class BaselineProfileVariantConfigurationImpl(val name: String) :
BaselineProfileVariantConfiguration {
internal val filters = FilterRules()
internal val dependencies = mutableListOf<Pair<Project, String?>>()
/**
* @inheritDoc
*/
override fun filter(action: FilterRules.() -> (Unit)) = action.invoke(filters)
/**
* @inheritDoc
*/
override fun filter(action: Action<FilterRules>) = action.execute(filters)
/**
* @inheritDoc
*/
override fun from(project: Project, variantName: String?) {
dependencies.add(Pair(project, variantName))
}
}
interface BaselineProfileVariantConfiguration {
/**
* Enables R8 to rewrite the incoming human readable baseline profile rules to account for
* synthetics, so they are preserved after optimizations by R8.
* TODO: This feature is experimental and currently not working properly.
* https://issuetracker.google.com/issue?id=271172067.
*/
var enableR8BaselineProfileRewrite: Boolean?
/**
* Specifies whether generated baseline profiles should be stored in the src folder.
* When this flag is set to true, the generated baseline profiles are stored in
* `src/<variant>/generated/baselineProfiles`.
*/
var saveInSrc: Boolean?
/**
* Specifies whether baseline profiles should be regenerated when building, for example, during
* a full release build for distribution. When set to true a new profile is generated as part
* of building the release build. This including rebuilding the non minified release, running
* the baseline profile tests and ultimately building the release build.
*/
var automaticGenerationDuringBuild: Boolean?
/**
* Specifies the output directory for generated baseline profiles when
* [BaselineProfileVariantConfiguration.saveInSrc] is `true`.
* Note that the dir specified here is created in the `src/<variant>/` folder.
*/
var baselineProfileOutputDir: String?
/**
* Specifies if baseline profile files should be merged into a single one when generating for
* multiple variants:
* - When `true` all the generated baseline profile for each variant are merged into
* `src/main/generated/baselineProfiles`'.
* - When `false` each variant will have its own baseline profile in
* `src/<variant>/generated/baselineProfiles`'.
* If this is not specified, by default it will be true for library modules and false for
* application modules.
* Note that when `saveInSrc` is false the output folder is in the build output folder but
* this setting still determines whether the profile included in the built apk or
* aar includes all the variant profiles.
*/
var mergeIntoMain: Boolean?
/**
* Specifies a filtering rule to decide which profiles rules should be included in this
* consumer baseline profile. This is useful especially for libraries, in order to exclude
* profile rules for class and methods for dependencies of the sample app. The filter supports:
* - Double wildcards, to match specified package and subpackages. Example: `com.example.**`
* - Wildcards, to match specified package only. Example: `com.example.*`
* - Class names, to match the specified class. Example: `com.example.MyClass`
*
* Note that when only excludes are specified, if there are no matches with any rule the profile
* rule is selected.
*
* Example to include a package and all the subpackages:
* ```
* filter { include "com.somelibrary.**" }
* ```
*
* Example to exclude some packages and include all the rest:
* ```
* filter { exclude "com.somelibrary.debug" }
* ```
*
* Example to include and exclude specific packages:
* ```
* filter {
* include "com.somelibrary.widget.grid.**"
* exclude "com.somelibrary.widget.grid.debug.**"
* include "com.somelibrary.widget.list.**"
* exclude "com.somelibrary.widget.grid.debug.**"
* include "com.somelibrary.widget.text.**"
* exclude "com.somelibrary.widget.grid.debug.**"
* }
* ```
*/
fun filter(action: FilterRules.() -> (Unit))
/**
* Specifies a filtering rule to decide which profiles rules should be included in this
* consumer baseline profile. This is useful especially for libraries, in order to exclude
* profile rules for class and methods for dependencies of the sample app. The filter supports:
* - Double wildcards, to match specified package and subpackages. Example: `com.example.**`
* - Wildcards, to match specified package only. Example: `com.example.*`
* - Class names, to match the specified class. Example: `com.example.MyClass`
*
* Note that when only excludes are specified, if there are no matches with any rule the profile
* rule is selected.
*
* Example to include a package and all the subpackages:
* ```
* filter { include "com.somelibrary.**" }
* ```
*
* Example to exclude some packages and include all the rest:
* ```
* filter { exclude "com.somelibrary.debug" }
* ```
*
* Example to include and exclude specific packages:
* ```
* filter {
* include "com.somelibrary.widget.grid.**"
* exclude "com.somelibrary.widget.grid.debug.**"
* include "com.somelibrary.widget.list.**"
* exclude "com.somelibrary.widget.list.debug.**"
* include "com.somelibrary.widget.text.**"
* exclude "com.somelibrary.widget.text.debug.**"
* }
* ```
*/
fun filter(action: Action<FilterRules>)
/**
* Allows to specify a target `com.android.test` module that has the `androidx.baselineprofile`
* plugin, and that can provide a baseline profile for this module. For example
* ```
* baselineProfile {
* variants {
* freeRelease {
* from(project(":baseline-profile"))
* }
* }
* }
* ```
*/
fun from(project: Project) = from(project, null)
/**
* Allows to specify a target `com.android.test` module that has the `androidx.baselineprofile`
* plugin, and that can provide a baseline profile for this module. The [variantName] can
* directly map to a test variant, to fetch a baseline profile for a different variant.
* For example it's possible to use a `paidRelease` baseline profile for `freeRelease` variant.
* ```
* baselineProfile {
* variants {
* freeRelease {
* from(project(":baseline-profile"), "paidRelease")
* }
* }
* }
* ```
*/
fun from(project: Project, variantName: String?)
}
class FilterRules {
internal val rules = mutableListOf<Pair<RuleType, String>>()
fun include(pkg: String) = rules.add(Pair(RuleType.INCLUDE, pkg))
fun exclude(pkg: String) = rules.add(Pair(RuleType.EXCLUDE, pkg))
}
enum class RuleType {
INCLUDE,
EXCLUDE
}