| /* |
| * 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 |
| } |