diff options
author | Luke Edgar <lukeedgar@google.com> | 2022-07-06 11:50:59 +0100 |
---|---|---|
committer | Luke Edgar <lukeedgar@google.com> | 2022-08-11 15:29:45 +0000 |
commit | 06f144793051babca37f4c6477bc7c3046defde9 (patch) | |
tree | 872692e4630f30c9e0db732b913206251a8e33d4 | |
parent | c0cfeebfd54a864cfe7b92187eefdf8a96accaee (diff) | |
download | base-06f144793051babca37f4c6477bc7c3046defde9.tar.gz |
Remove AbstractFusedLibraryPlugin and AbstractPrivacySandboxPlugin
Removes abstract classes extended by FusedLibraryPlugin and
PrivacySandboxSdkPlugin. Introduces a utility file to share common logic
across the plugins.
Bug: N/a
Test: Existing pass (no behaviour changes)
Change-Id: Ied47d4c2023228df88040c7b909685f9471118bb
6 files changed, 562 insertions, 738 deletions
diff --git a/build-system/gradle-core/lint_baseline.xml b/build-system/gradle-core/lint_baseline.xml index b616cbaac8..ee9bee39ac 100755 --- a/build-system/gradle-core/lint_baseline.xml +++ b/build-system/gradle-core/lint_baseline.xml @@ -56,22 +56,6 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/plugins/AbstractFusedLibraryPlugin.kt" - line="56"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location - file="src/main/java/com/android/build/gradle/internal/plugins/AbstractPrivacySandboxPlugin.kt" - line="56"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location file="src/main/java/com/android/build/gradle/internal/test/AbstractTestDataImpl.kt" line="66"/> </issue> @@ -161,7 +145,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/component/analytics/AnalyticsEnabledTestVariant.kt" - line="89"/> + line="82"/> </issue> <issue @@ -177,7 +161,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt" - line="56"/> + line="54"/> </issue> <issue @@ -185,7 +169,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt" - line="62"/> + line="60"/> </issue> <issue @@ -193,7 +177,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt" - line="75"/> + line="73"/> </issue> <issue @@ -201,7 +185,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/AndroidPluginBaseServices.kt" - line="98"/> + line="96"/> </issue> <issue @@ -608,22 +592,6 @@ id="AvoidByLazy" message="Avoid `by lazy` for simple lazy initialization"> <location - file="src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt" - line="55"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location - file="src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt" - line="63"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location file="src/main/java/com/android/build/gradle/internal/fusedlibrary/FusedLibraryVariantScopeImpl.kt" line="37"/> </issue> @@ -689,7 +657,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/api/variant/impl/LibraryVariantImpl.kt" - line="121"/> + line="120"/> </issue> <issue @@ -713,7 +681,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/ide/v2/NativeModelBuilder.kt" - line="64"/> + line="71"/> </issue> <issue @@ -721,7 +689,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/ide/v2/NativeModelBuilder.kt" - line="68"/> + line="75"/> </issue> <issue @@ -745,23 +713,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt" - line="59"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location - file="src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt" - line="75"/> - </issue> - - <issue - id="AvoidByLazy" - message="Avoid `by lazy` for simple lazy initialization"> - <location - file="src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt" - line="94"/> + line="92"/> </issue> <issue @@ -961,7 +913,7 @@ message="Avoid `by lazy` for simple lazy initialization"> <location file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="142"/> + line="151"/> </issue> <issue @@ -1073,7 +1025,7 @@ message="Do not use `java.nio.file.Files.copy(Path, Path)`. Instead, use `FileUtils.copyFile(Path, Path)` or Kotlin's `File#copyTo(File)`"> <location file="src/main/java/com/android/build/gradle/internal/tasks/AsarToApksTransform.kt" - line="72"/> + line="73"/> </issue> <issue @@ -1081,7 +1033,7 @@ message="This reference is unused: name"> <location file="src/main/java/com/android/build/gradle/internal/tasks/DependencyReportTask.kt" - line="49"/> + line="51"/> </issue> <issue @@ -1089,7 +1041,7 @@ message="This reference is unused: name"> <location file="src/main/java/com/android/build/gradle/internal/tasks/DependencyReportTask.kt" - line="56"/> + line="58"/> </issue> <issue @@ -1137,7 +1089,7 @@ message="This reference is unused: testApplicationId"> <location file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="216"/> + line="225"/> </issue> <issue @@ -1145,7 +1097,7 @@ message="This reference is unused: testApplicationId"> <location file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="312"/> + line="321"/> </issue> <issue @@ -1153,7 +1105,7 @@ message="This reference is unused: testInstrumentationRunner"> <location file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="484"/> + line="493"/> </issue> <issue @@ -1161,7 +1113,7 @@ message="This reference is unused: testHandleProfiling"> <location file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="527"/> + line="536"/> </issue> <issue @@ -1169,7 +1121,7 @@ message="This reference is unused: testFunctionalTest"> <location file="src/main/java/com/android/build/gradle/internal/core/VariantDslInfoImpl.kt" - line="548"/> + line="557"/> </issue> <issue @@ -1177,7 +1129,7 @@ message="Avoid using `org.gradle.api.Project.exec` as it is incompatible with Gradle instant execution."> <location file="src/main/java/com/android/build/gradle/internal/ide/v2/NativeModelBuilder.kt" - line="56"/> + line="63"/> </issue> <issue @@ -1201,7 +1153,7 @@ message="This method should only be accessed from tests or within private scope"> <location file="src/main/java/com/android/build/gradle/internal/tasks/featuresplit/FeatureSetMetadataWriterTask.kt" - line="127"/> + line="130"/> </issue> <issue @@ -1217,7 +1169,7 @@ message="This method should only be accessed from tests or within private scope"> <location file="src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeDexTask.kt" - line="58"/> + line="61"/> </issue> <issue @@ -1225,7 +1177,7 @@ message="This method should only be accessed from tests or within private scope"> <location file="src/main/java/com/android/build/gradle/tasks/PrivacySandboxSdkMergeDexTask.kt" - line="60"/> + line="63"/> </issue> <issue @@ -1249,7 +1201,7 @@ message="Use `Integer.valueOf(index)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="79"/> + line="81"/> </issue> <issue @@ -1257,7 +1209,7 @@ message="Use `Integer.valueOf(libraryList.size)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="102"/> + line="104"/> </issue> <issue @@ -1265,7 +1217,7 @@ message="Use `Integer.valueOf(origIndex)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="112"/> + line="114"/> </issue> <issue @@ -1273,7 +1225,7 @@ message="Use `Integer.valueOf(libraryDep.libraryIndex)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="117"/> + line="119"/> </issue> <issue @@ -1281,7 +1233,7 @@ message="Use `Integer.valueOf(depIndex)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="120"/> + line="122"/> </issue> <issue @@ -1289,7 +1241,7 @@ message="Use `Integer.valueOf(depIndex)` instead"> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleReportDependenciesTask.kt" - line="133"/> + line="135"/> </issue> <issue @@ -1409,7 +1361,7 @@ message="Avoid using common ForkJoinPool, directly or indirectly (for example via CompletableFuture). It has a limited set of threads on some machines which leads to hangs. See `go/do-not-freeze`."> <location file="src/main/java/com/android/build/gradle/internal/tasks/AsarToApksTransform.kt" - line="77"/> + line="78"/> </issue> <issue @@ -1417,7 +1369,7 @@ message="Avoid using common ForkJoinPool, directly or indirectly (for example via CompletableFuture). It has a limited set of threads on some machines which leads to hangs. See `go/do-not-freeze`."> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleToApkTask.kt" - line="111"/> + line="113"/> </issue> <issue @@ -1425,7 +1377,7 @@ message="Avoid using common ForkJoinPool, directly or indirectly (for example via CompletableFuture). It has a limited set of threads on some machines which leads to hangs. See `go/do-not-freeze`."> <location file="src/main/java/com/android/build/gradle/internal/tasks/BundleToStandaloneApkTask.kt" - line="124"/> + line="126"/> </issue> <issue @@ -1449,7 +1401,7 @@ message="Avoid using new ForkJoinPool instances when possible. Prefer using the IntelliJ application pool via `com.intellij.openapi.application.Application#executeOnPooledThread`, or for the Android Gradle Plugin use `com.android.build.gradle.internal.tasks.Workers`. See `go/do-not-freeze`."> <location file="src/main/java/com/android/build/gradle/internal/tasks/DexMergingTask.kt" - line="797"/> + line="799"/> </issue> </issues> diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/fusedlibrary/FusedLibraryPluginUtils.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/fusedlibrary/FusedLibraryPluginUtils.kt new file mode 100644 index 0000000000..c7d5659334 --- /dev/null +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/fusedlibrary/FusedLibraryPluginUtils.kt @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2022 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 com.android.build.gradle.internal.fusedlibrary + +import com.android.build.api.artifact.Artifact +import com.android.build.api.artifact.impl.ArtifactsImpl +import com.android.build.api.attributes.BuildTypeAttr +import com.android.build.gradle.internal.DependencyConfigurator +import com.android.build.gradle.internal.SdkComponentsBuildService +import com.android.build.gradle.internal.publishing.AndroidArtifacts +import com.android.build.gradle.internal.services.DslServices +import com.android.build.gradle.internal.services.DslServicesImpl +import com.android.build.gradle.internal.services.ProjectServices +import com.android.build.gradle.internal.tasks.factory.TaskCreationAction +import com.android.build.gradle.internal.tasks.factory.TaskFactoryImpl +import org.gradle.api.DefaultTask +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.component.ComponentIdentifier +import org.gradle.api.attributes.Usage +import org.gradle.api.file.RegularFile +import org.gradle.api.provider.Provider +import org.gradle.api.specs.Spec + +fun createTasks( + project: Project, + artifacts: ArtifactsImpl, + artifactForPublication: Artifact.Single<RegularFile>, + tasksCreationActions: List<TaskCreationAction<out DefaultTask>> +) { + val taskProviders = TaskFactoryImpl(project.tasks).let { taskFactory -> + tasksCreationActions.map { creationAction -> + taskFactory.register(creationAction) + } + } + + // create anchor tasks + project.tasks.register("assemble") { assembleTask -> + artifactForPublication?.let { artifactTypeForPublication -> + assembleTask.dependsOn(artifacts.get(artifactTypeForPublication)) + } ?: taskProviders.forEach { assembleTask.dependsOn(it) } + } +} + +fun configureTransforms(project: Project, projectServices: ProjectServices) { + DependencyConfigurator(project, projectServices) + .configureGeneralTransforms(namespacedAndroidResources = false) +} + +fun getDslServices(project: Project, projectServices: ProjectServices): DslServices { + val sdkComponentsBuildService: Provider<SdkComponentsBuildService> = + SdkComponentsBuildService.RegistrationAction( + project, + projectServices.projectOptions + ).execute() + + return DslServicesImpl(projectServices, sdkComponentsBuildService) +} + diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractFusedLibraryPlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractFusedLibraryPlugin.kt deleted file mode 100644 index 88a62d7070..0000000000 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractFusedLibraryPlugin.kt +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.build.gradle.internal.plugins - -import com.android.build.api.artifact.Artifact -import com.android.build.api.attributes.BuildTypeAttr -import com.android.build.gradle.internal.DependencyConfigurator -import com.android.build.gradle.internal.SdkComponentsBuildService -import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope -import com.android.build.gradle.internal.fusedlibrary.SegregatingConstraintHandler -import com.android.build.gradle.internal.publishing.AndroidArtifacts -import com.android.build.gradle.internal.services.Aapt2DaemonBuildService -import com.android.build.gradle.internal.services.Aapt2ThreadPoolBuildService -import com.android.build.gradle.internal.services.DslServicesImpl -import com.android.build.gradle.internal.tasks.factory.TaskCreationAction -import com.android.build.gradle.internal.tasks.factory.TaskFactoryImpl -import com.google.wireless.android.sdk.stats.GradleBuildProfileSpan -import groovy.namespace.QName -import groovy.util.Node -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.artifacts.ArtifactCollection -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.component.LibraryBinaryIdentifier -import org.gradle.api.artifacts.component.ModuleComponentIdentifier -import org.gradle.api.artifacts.component.ProjectComponentIdentifier -import org.gradle.api.attributes.Usage -import org.gradle.api.component.SoftwareComponentFactory -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.Provider -import org.gradle.api.publish.maven.MavenPom -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.build.event.BuildEventsListenerRegistry -import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier - -abstract class AbstractFusedLibraryPlugin ( - protected val softwareComponentFactory: SoftwareComponentFactory, - listenerRegistry: BuildEventsListenerRegistry, -): AndroidPluginBaseServices(listenerRegistry), Plugin<Project> { - - val dslServices by lazy { - withProject("dslServices") { project -> - val sdkComponentsBuildService: Provider<SdkComponentsBuildService> = - SdkComponentsBuildService.RegistrationAction( - project, - projectServices.projectOptions - ).execute() - - DslServicesImpl( - projectServices, - sdkComponentsBuildService - ) - } - } - - abstract val variantScope: FusedLibraryVariantScope - - internal fun createTasks( - project: Project, - variantScope: FusedLibraryVariantScope, - tasksCreationActions: List<TaskCreationAction<out DefaultTask>>, - ) { - configureTransforms(project) - val taskProviders = TaskFactoryImpl(project.tasks).let { taskFactory -> - tasksCreationActions.map { creationAction -> - taskFactory.register(creationAction) - } - } - - // create anchor tasks - project.tasks.register("assemble") { assembleTask -> - artifactForPublication?.let { artifactTypeForPublication -> - assembleTask.dependsOn(variantScope.artifacts.get(artifactTypeForPublication)) - } ?: taskProviders.forEach { assembleTask.dependsOn(it) } - } - } - - /** - * Returns the artifact type that will be used for maven publication or null if nothing is to - * be published to maven. - */ - abstract val artifactForPublication: Artifact.Single<RegularFile>? - - abstract val artifactTypeForPublication: AndroidArtifacts.ArtifactType - - override fun apply(project: Project) { - super.basePluginApply(project) - - // so far by default, we consume and publish only 'debug' variant - - // 'include' is the configuration that users will use to indicate which dependencies should - // be fused. - val includeConfigurations = project.configurations.create("include").also { - it.isCanBeConsumed = false - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - } - - // This is the internal configuration that will be used to feed tasks that require access - // to the resolved 'include' dependency. It is for JAVA_API usage which mean all transitive - // dependencies that are implementation() scoped will not be included. - val includeApiClasspath = project.configurations.create("includeApiClasspath").also { - it.isCanBeConsumed = false - it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) - ) - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - it.extendsFrom(includeConfigurations) - } - variantScope.incomingConfigurations.addConfiguration(includeApiClasspath) - - // This is the configuration that will contain all the JAVA_API dependencies that are not - // fused in the resulting aar library. - val includedApiUnmerged = project.configurations.create("includeApiUnmerged").also { - it.isCanBeConsumed = true - it.isCanBeResolved = true - it.incoming.beforeResolve( - SegregatingConstraintHandler( - includeApiClasspath, - it, - variantScope.mergeSpec, - project, - ) - ) - } - - // This is the internal configuration that will be used to feed tasks that require access - // to the resolved 'include' dependency. It is for JAVA_RUNTIME usage which mean all transitive - // dependencies that are implementation() scoped will be included. - val includeRuntimeClasspath = project.configurations.create("includeRuntimeClasspath").also { - it.isCanBeConsumed = false - it.isCanBeResolved = true - - it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) - ) - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - - it.extendsFrom(includeConfigurations) - } - variantScope.incomingConfigurations.addConfiguration(includeRuntimeClasspath) - - // This is the configuration that will contain all the JAVA_RUNTIME dependencies that are - // not fused in the resulting aar library. - val includeRuntimeUnmerged = project.configurations.create("includeRuntimeUnmerged").also { - it.isCanBeConsumed = false - it.isCanBeResolved = true - it.incoming.beforeResolve( - SegregatingConstraintHandler( - includeConfigurations, - it, - variantScope.mergeSpec, - project, - ) - ) - } - - // we are only interested in the last provider in the chain of transformers for this bundle. - // Obviously, this is theoretical at this point since there is no variant API to replace - // artifacts, there is always only one. - val bundleTaskProvider = artifactForPublication?.let { - variantScope - .artifacts - .getArtifactContainer(it) - .getTaskProviders() - .last() - } - - // this is the outgoing configuration for JAVA_API scoped declarations, it will contain - // this module and all transitive non merged dependencies - - fun configureApiRuntimeElements(elements: Configuration) { - elements.isCanBeResolved = false - elements.isCanBeConsumed = true - elements.isTransitive = true - - if (bundleTaskProvider != null) { - elements.outgoing.variants { variants -> - variants.create(artifactTypeForPublication.type) {variant -> - variant.artifact(bundleTaskProvider) { artifact -> - artifact.type = artifactTypeForPublication.type - } - } - } - } - } - - val includeApiElements = project.configurations.create("apiElements") { apiElements -> - configureApiRuntimeElements(apiElements) - apiElements.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) - ) - apiElements.extendsFrom(includedApiUnmerged) - } - - // this is the outgoing configuration for JAVA_RUNTIME scoped declarations, it will contain - // this module and all transitive non merged dependencies - val includeRuntimeElements = project.configurations.create("runtimeElements") { runtimeElements -> - configureApiRuntimeElements(runtimeElements) - runtimeElements.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) - ) - runtimeElements.extendsFrom(includeRuntimeUnmerged) - } - - maybePublishToMaven( - project, - includeApiElements, - includeRuntimeElements, - includeRuntimeUnmerged - ) - } - - override fun configureProject(project: Project) { - val projectOptions = projectServices.projectOptions - Aapt2ThreadPoolBuildService.RegistrationAction(project, projectOptions).execute() - Aapt2DaemonBuildService.RegistrationAction(project, projectOptions).execute() - } - - protected abstract fun maybePublishToMaven( - project: Project, - includeApiElements: Configuration, - includeRuntimeElements: Configuration, - includeRuntimeUnmerged: Configuration - ) - - fun component( - publication: MavenPublication, - unmergedArtifacts: ArtifactCollection, - ) { - - publication.pom { pom: MavenPom -> - pom.withXml { xml -> - val dependenciesNode = xml.asNode().let { - it.children().firstOrNull { node -> - ((node as Node).name() as QName).qualifiedName == "dependencies" - } ?: it.appendNode("dependencies") - } as Node - - unmergedArtifacts.forEach { artifact -> - if (artifact.id is ModuleComponentArtifactIdentifier) { - when (val moduleIdentifier = artifact.id.componentIdentifier) { - is ModuleComponentIdentifier -> { - val dependencyNode = dependenciesNode.appendNode("dependency") - dependencyNode.appendNode("groupId", moduleIdentifier.group) - dependencyNode.appendNode("artifactId", moduleIdentifier.module) - dependencyNode.appendNode("version", moduleIdentifier.version) - dependencyNode.appendNode("scope", "runtime") - } - is ProjectComponentIdentifier -> println("Project : ${moduleIdentifier.projectPath}") - is LibraryBinaryIdentifier -> println("Library : ${moduleIdentifier.projectPath}") - else -> println("Unknown dependency ${moduleIdentifier.javaClass} : $artifact") - } - } else { - println("Unknown module ${artifact.id.javaClass} : ${artifact.id}") - } - } - } - } - } - - fun configureTransforms(project: Project) { - configuratorService.recordBlock( - GradleBuildProfileSpan.ExecutionType.ARTIFACT_TRANSFORM, - project.path, - null - ) { - DependencyConfigurator(project, projectServices) - .configureGeneralTransforms(namespacedAndroidResources = false) - } - } -} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractPrivacySandboxPlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractPrivacySandboxPlugin.kt deleted file mode 100644 index eb252ab2d4..0000000000 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/AbstractPrivacySandboxPlugin.kt +++ /dev/null @@ -1,251 +0,0 @@ -/* - * Copyright (C) 2022 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 com.android.build.gradle.internal.plugins - -import com.android.build.api.artifact.Artifact -import com.android.build.api.attributes.BuildTypeAttr -import com.android.build.gradle.internal.DependencyConfigurator -import com.android.build.gradle.internal.SdkComponentsBuildService -import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope -import com.android.build.gradle.internal.fusedlibrary.SegregatingConstraintHandler -import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScope -import com.android.build.gradle.internal.publishing.AndroidArtifacts -import com.android.build.gradle.internal.services.Aapt2DaemonBuildService -import com.android.build.gradle.internal.services.Aapt2ThreadPoolBuildService -import com.android.build.gradle.internal.services.DslServicesImpl -import com.android.build.gradle.internal.tasks.factory.TaskCreationAction -import com.android.build.gradle.internal.tasks.factory.TaskFactoryImpl -import com.google.wireless.android.sdk.stats.GradleBuildProfileSpan -import groovy.namespace.QName -import groovy.util.Node -import org.gradle.api.DefaultTask -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.artifacts.ArtifactCollection -import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.component.LibraryBinaryIdentifier -import org.gradle.api.artifacts.component.ModuleComponentIdentifier -import org.gradle.api.artifacts.component.ProjectComponentIdentifier -import org.gradle.api.attributes.Usage -import org.gradle.api.component.SoftwareComponentFactory -import org.gradle.api.file.RegularFile -import org.gradle.api.provider.Provider -import org.gradle.api.publish.maven.MavenPom -import org.gradle.api.publish.maven.MavenPublication -import org.gradle.build.event.BuildEventsListenerRegistry -import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier - -abstract class AbstractPrivacySandboxPlugin( - listenerRegistry: BuildEventsListenerRegistry, -): AndroidPluginBaseServices(listenerRegistry), Plugin<Project> { - - val dslServices by lazy { - withProject("dslServices") { project -> - val sdkComponentsBuildService: Provider<SdkComponentsBuildService> = - SdkComponentsBuildService.RegistrationAction( - project, - projectServices.projectOptions - ).execute() - - DslServicesImpl( - projectServices, - sdkComponentsBuildService - ) - } - } - - abstract val variantScope: PrivacySandboxSdkVariantScope - - internal fun createTasks( - project: Project, - variantScope: PrivacySandboxSdkVariantScope, - tasksCreationActions: List<TaskCreationAction<out DefaultTask>>, - ) { - configureTransforms(project) - val taskProviders = TaskFactoryImpl(project.tasks).let { taskFactory -> - tasksCreationActions.map { creationAction -> - taskFactory.register(creationAction) - } - } - - // create anchor tasks - project.tasks.register("assemble") { assembleTask -> - artifactForPublication?.let { artifactTypeForPublication -> - assembleTask.dependsOn(variantScope.artifacts.get(artifactTypeForPublication)) - } ?: taskProviders.forEach { assembleTask.dependsOn(it) } - } - } - - /** - * Returns the artifact type that will be used for maven publication or null if nothing is to - * be published to maven. - */ - internal abstract val artifactForPublication: Artifact.Single<RegularFile>? - - internal abstract val artifactTypeForPublication: AndroidArtifacts.ArtifactType - - override fun apply(project: Project) { - super.basePluginApply(project) - - // so far by default, we consume and publish only 'debug' variant - - // 'include' is the configuration that users will use to indicate which dependencies should - // be fused. - val includeConfigurations = project.configurations.create("include").also { - it.isCanBeConsumed = false - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - } - - // This is the internal configuration that will be used to feed tasks that require access - // to the resolved 'include' dependency. It is for JAVA_API usage which mean all transitive - // dependencies that are implementation() scoped will not be included. - val includeApiClasspath = project.configurations.create("includeApiClasspath").also { - it.isCanBeConsumed = false - it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) - ) - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - it.extendsFrom(includeConfigurations) - } - variantScope.incomingConfigurations.addConfiguration(includeApiClasspath) - - // This is the configuration that will contain all the JAVA_API dependencies that are not - // fused in the resulting aar library. - val includedApiUnmerged = project.configurations.create("includeApiUnmerged").also { - it.isCanBeConsumed = true - it.isCanBeResolved = true - it.incoming.beforeResolve( - SegregatingConstraintHandler( - includeApiClasspath, - it, - variantScope.mergeSpec, - project, - ) - ) - } - - // This is the internal configuration that will be used to feed tasks that require access - // to the resolved 'include' dependency. It is for JAVA_RUNTIME usage which mean all transitive - // dependencies that are implementation() scoped will be included. - val includeRuntimeClasspath = project.configurations.create("includeRuntimeClasspath").also { - it.isCanBeConsumed = false - it.isCanBeResolved = true - - it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) - ) - val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") - it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - buildType, - ) - - it.extendsFrom(includeConfigurations) - } - variantScope.incomingConfigurations.addConfiguration(includeRuntimeClasspath) - - // This is the configuration that will contain all the JAVA_RUNTIME dependencies that are - // not fused in the resulting aar library. - val includeRuntimeUnmerged = project.configurations.create("includeRuntimeUnmerged").also { - it.isCanBeConsumed = false - it.isCanBeResolved = true - it.incoming.beforeResolve( - SegregatingConstraintHandler( - includeConfigurations, - it, - variantScope.mergeSpec, - project, - ) - ) - } - - // we are only interested in the last provider in the chain of transformers for this bundle. - // Obviously, this is theoretical at this point since there is no variant API to replace - // artifacts, there is always only one. - val bundleTaskProvider = artifactForPublication?.let { - variantScope - .artifacts - .getArtifactContainer(it) - .getTaskProviders() - .last() - } - - // this is the outgoing configuration for JAVA_API scoped declarations, it will contain - // this module and all transitive non merged dependencies - - fun configureApiRuntimeElements(elements: Configuration) { - elements.isCanBeResolved = false - elements.isCanBeConsumed = true - elements.isTransitive = true - - if (bundleTaskProvider != null) { - elements.outgoing.variants { variants -> - variants.create(artifactTypeForPublication.type) {variant -> - variant.artifact(bundleTaskProvider) { artifact -> - artifact.type = artifactTypeForPublication.type - } - } - } - } - } - - val includeApiElements = project.configurations.create("apiElements") { apiElements -> - configureApiRuntimeElements(apiElements) - apiElements.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) - ) - } - - // this is the outgoing configuration for JAVA_RUNTIME scoped declarations, it will contain - // this module and all transitive non merged dependencies - val includeRuntimeElements = project.configurations.create("runtimeElements") { runtimeElements -> - configureApiRuntimeElements(runtimeElements) - runtimeElements.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) - ) - } - } - - override fun configureProject(project: Project) { - val projectOptions = projectServices.projectOptions - Aapt2ThreadPoolBuildService.RegistrationAction(project, projectOptions).execute() - Aapt2DaemonBuildService.RegistrationAction(project, projectOptions).execute() - } - - private fun configureTransforms(project: Project) { - configuratorService.recordBlock( - GradleBuildProfileSpan.ExecutionType.ARTIFACT_TRANSFORM, - project.path, - null - ) { - DependencyConfigurator(project, projectServices) - .configureGeneralTransforms(namespacedAndroidResources = false) - } - } -} diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt index 560172ad3e..a98dc55c71 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/FusedLibraryPlugin.kt @@ -17,23 +17,37 @@ package com.android.build.gradle.internal.plugins import com.android.build.api.artifact.Artifact +import com.android.build.api.artifact.impl.ArtifactsImpl import com.android.build.api.attributes.BuildTypeAttr import com.android.build.api.dsl.FusedLibraryExtension import com.android.build.gradle.internal.dsl.FusedLibraryExtensionImpl import com.android.build.gradle.internal.fusedlibrary.FusedLibraryInternalArtifactType +import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScope import com.android.build.gradle.internal.fusedlibrary.FusedLibraryVariantScopeImpl +import com.android.build.gradle.internal.fusedlibrary.SegregatingConstraintHandler +import com.android.build.gradle.internal.fusedlibrary.configureTransforms +import com.android.build.gradle.internal.fusedlibrary.createTasks +import com.android.build.gradle.internal.fusedlibrary.getDslServices import com.android.build.gradle.internal.publishing.AndroidArtifacts +import com.android.build.gradle.internal.services.DslServices import com.android.build.gradle.internal.tasks.MergeJavaResourceTask import com.android.build.gradle.tasks.FusedLibraryBundleAar import com.android.build.gradle.tasks.FusedLibraryBundleClasses -import com.android.build.gradle.tasks.FusedLibraryMergeClasses import com.android.build.gradle.tasks.FusedLibraryClassesRewriteTask import com.android.build.gradle.tasks.FusedLibraryManifestMergerTask import com.android.build.gradle.tasks.FusedLibraryMergeArtifactTask +import com.android.build.gradle.tasks.FusedLibraryMergeClasses import com.android.build.gradle.tasks.FusedLibraryMergeResourcesTask import com.google.wireless.android.sdk.stats.GradleBuildProject +import groovy.namespace.QName +import groovy.util.Node +import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.artifacts.ArtifactCollection import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.component.LibraryBinaryIdentifier +import org.gradle.api.artifacts.component.ModuleComponentIdentifier +import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.attributes.Bundling import org.gradle.api.attributes.Category import org.gradle.api.attributes.LibraryElements @@ -41,18 +55,25 @@ import org.gradle.api.attributes.Usage import org.gradle.api.component.SoftwareComponentFactory import org.gradle.api.file.RegularFile import org.gradle.api.publish.PublishingExtension +import org.gradle.api.publish.maven.MavenPom import org.gradle.api.publish.maven.MavenPublication import org.gradle.build.event.BuildEventsListenerRegistry +import org.gradle.internal.component.external.model.ModuleComponentArtifactIdentifier import javax.inject.Inject @Suppress("UnstableApiUsage") class FusedLibraryPlugin @Inject constructor( - softwareComponentFactory: SoftwareComponentFactory, - listenerRegistry: BuildEventsListenerRegistry, -): AbstractFusedLibraryPlugin(softwareComponentFactory, listenerRegistry) { + private val softwareComponentFactory: SoftwareComponentFactory, + listenerRegistry: BuildEventsListenerRegistry, +) : AndroidPluginBaseServices(listenerRegistry), Plugin<Project> { + + val dslServices: DslServices by lazy(LazyThreadSafetyMode.NONE) { + withProject("dslServices") { project -> + getDslServices(project, projectServices) + } + } - // so far, there is only one variant. - override val variantScope by lazy { + private val variantScope: FusedLibraryVariantScope by lazy(LazyThreadSafetyMode.NONE) { withProject("variantScope") { project -> FusedLibraryVariantScopeImpl( project @@ -60,45 +81,48 @@ class FusedLibraryPlugin @Inject constructor( } } - private val extension: FusedLibraryExtension by lazy { + private val extension: FusedLibraryExtension by lazy(LazyThreadSafetyMode.NONE) { withProject("extension") { project -> instantiateExtension(project) } } + override fun configureProject(project: Project) { + } + override fun configureExtension(project: Project) { extension } private fun instantiateExtension(project: Project): FusedLibraryExtension { - val fusedLibraryExtensionImpl= dslServices.newDecoratedInstance( - FusedLibraryExtensionImpl::class.java, - dslServices, + val fusedLibraryExtensionImpl = dslServices.newDecoratedInstance( + FusedLibraryExtensionImpl::class.java, + dslServices, ) abstract class Extension( - val publicExtensionImpl: FusedLibraryExtensionImpl, + val publicExtensionImpl: FusedLibraryExtensionImpl, ): FusedLibraryExtension by publicExtensionImpl return project.extensions.create( - FusedLibraryExtension::class.java, - "android", - Extension::class.java, - fusedLibraryExtensionImpl + FusedLibraryExtension::class.java, + "android", + Extension::class.java, + fusedLibraryExtensionImpl ) } - override fun maybePublishToMaven( - project: Project, - includeApiElements: Configuration, - includeRuntimeElements: Configuration, - includeRuntimeUnmerged: Configuration + private fun maybePublishToMaven( + project: Project, + includeApiElements: Configuration, + includeRuntimeElements: Configuration, + includeRuntimeUnmerged: Configuration ) { val bundleTaskProvider = variantScope .artifacts - .getArtifactContainer(artifactForPublication) + .getArtifactContainer(FusedLibraryInternalArtifactType.BUNDLED_LIBRARY) .getTaskProviders() .last() @@ -107,27 +131,27 @@ class FusedLibraryPlugin @Inject constructor( it.isCanBeResolved = false it.isVisible = false it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_API) + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_API) ) it.attributes.attribute( - Bundling.BUNDLING_ATTRIBUTE, - project.objects.named(Bundling::class.java, Bundling.EXTERNAL) + Bundling.BUNDLING_ATTRIBUTE, + project.objects.named(Bundling::class.java, Bundling.EXTERNAL) ) it.attributes.attribute( - Category.CATEGORY_ATTRIBUTE, - project.objects.named(Category::class.java, Category.LIBRARY) + Category.CATEGORY_ATTRIBUTE, + project.objects.named(Category::class.java, Category.LIBRARY) ) it.attributes.attribute( - LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, - project.objects.named( - LibraryElements::class.java, - AndroidArtifacts.ArtifactType.AAR.type - ) + LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, + project.objects.named( + LibraryElements::class.java, + AndroidArtifacts.ArtifactType.AAR.type + ) ) it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - project.objects.named(BuildTypeAttr::class.java, "debug") + BuildTypeAttr.ATTRIBUTE, + project.objects.named(BuildTypeAttr::class.java, "debug") ) it.extendsFrom(includeApiElements) variantScope.outgoingConfigurations.addConfiguration(it) @@ -141,27 +165,27 @@ class FusedLibraryPlugin @Inject constructor( it.isCanBeResolved = false it.isVisible = false it.attributes.attribute( - Usage.USAGE_ATTRIBUTE, - project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) ) it.attributes.attribute( - Bundling.BUNDLING_ATTRIBUTE, - project.objects.named(Bundling::class.java, Bundling.EXTERNAL) + Bundling.BUNDLING_ATTRIBUTE, + project.objects.named(Bundling::class.java, Bundling.EXTERNAL) ) it.attributes.attribute( - Category.CATEGORY_ATTRIBUTE, - project.objects.named(Category::class.java, Category.LIBRARY) + Category.CATEGORY_ATTRIBUTE, + project.objects.named(Category::class.java, Category.LIBRARY) ) it.attributes.attribute( - LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, - project.objects.named( - LibraryElements::class.java, - AndroidArtifacts.ArtifactType.AAR.type - ) + LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, + project.objects.named( + LibraryElements::class.java, + AndroidArtifacts.ArtifactType.AAR.type + ) ) it.attributes.attribute( - BuildTypeAttr.ATTRIBUTE, - project.objects.named(BuildTypeAttr::class.java, "debug") + BuildTypeAttr.ATTRIBUTE, + project.objects.named(BuildTypeAttr::class.java, "debug") ) it.extendsFrom(includeRuntimeElements) variantScope.outgoingConfigurations.addConfiguration(it) @@ -185,19 +209,52 @@ class FusedLibraryPlugin @Inject constructor( project.afterEvaluate { project.extensions.findByType(PublishingExtension::class.java)?.also { component( - it.publications.create("maven", MavenPublication::class.java) - .also { mavenPublication -> - mavenPublication.from(adhocComponent) - }, includeRuntimeUnmerged.incoming.artifacts + it.publications.create("maven", MavenPublication::class.java) + .also { mavenPublication -> + mavenPublication.from(adhocComponent) + }, includeRuntimeUnmerged.incoming.artifacts ) } } } + fun component(publication: MavenPublication, unmergedArtifacts: ArtifactCollection) { + publication.pom { pom: MavenPom -> + pom.withXml { xml -> + val dependenciesNode = xml.asNode().let { + it.children().firstOrNull { node -> + ((node as Node).name() as QName).qualifiedName == "dependencies" + } ?: it.appendNode("dependencies") + } as Node + + unmergedArtifacts.forEach { artifact -> + if (artifact.id is ModuleComponentArtifactIdentifier) { + when (val moduleIdentifier = artifact.id.componentIdentifier) { + is ModuleComponentIdentifier -> { + val dependencyNode = dependenciesNode.appendNode("dependency") + dependencyNode.appendNode("groupId", moduleIdentifier.group) + dependencyNode.appendNode("artifactId", moduleIdentifier.module) + dependencyNode.appendNode("version", moduleIdentifier.version) + dependencyNode.appendNode("scope", "runtime") + } + is ProjectComponentIdentifier -> println("Project : ${moduleIdentifier.projectPath}") + is LibraryBinaryIdentifier -> println("Library : ${moduleIdentifier.projectPath}") + else -> println("Unknown dependency ${moduleIdentifier.javaClass} : $artifact") + } + } else { + println("Unknown module ${artifact.id.javaClass} : ${artifact.id}") + } + } + } + } + } + override fun createTasks(project: Project) { + configureTransforms(project, projectServices) createTasks( project, - variantScope, + variantScope.artifacts, + FusedLibraryInternalArtifactType.BUNDLED_LIBRARY, listOf( FusedLibraryClassesRewriteTask.CreationAction(variantScope), FusedLibraryManifestMergerTask.CreationAction(variantScope), @@ -210,12 +267,157 @@ class FusedLibraryPlugin @Inject constructor( ) } - override fun getAnalyticsPluginType(): GradleBuildProject.PluginType = - GradleBuildProject.PluginType.FUSED_LIBRARIES + override fun getAnalyticsPluginType(): GradleBuildProject.PluginType = + GradleBuildProject.PluginType.FUSED_LIBRARIES + + override fun apply(project: Project) { + super.basePluginApply(project) + + // so far by default, we consume and publish only 'debug' variant + + // 'include' is the configuration that users will use to indicate which dependencies should + // be fused. + val includeConfigurations = project.configurations.create("include").also { + it.isCanBeConsumed = false + val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + } + // This is the internal configuration that will be used to feed tasks that require access + // to the resolved 'include' dependency. It is for JAVA_API usage which mean all transitive + // dependencies that are implementation() scoped will not be included. + val includeApiClasspath = project.configurations.create("includeApiClasspath").also { + it.isCanBeConsumed = false + it.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_API) + ) + val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + it.extendsFrom(includeConfigurations) + } + // This is the configuration that will contain all the JAVA_API dependencies that are not + // fused in the resulting aar library. + val includedApiUnmerged = project.configurations.create("includeApiUnmerged").also { + it.isCanBeConsumed = true + it.isCanBeResolved = true + it.incoming.beforeResolve( + SegregatingConstraintHandler( + includeApiClasspath, + it, + variantScope.mergeSpec, + project, + ) + ) + } + // This is the internal configuration that will be used to feed tasks that require access + // to the resolved 'include' dependency. It is for JAVA_RUNTIME usage which mean all transitive + // dependencies that are implementation() scoped will be included. + val includeRuntimeClasspath = + project.configurations.create("includeRuntimeClasspath").also { + it.isCanBeConsumed = false + it.isCanBeResolved = true + + it.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) + ) + val buildType: BuildTypeAttr = + project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + + it.extendsFrom(includeConfigurations) + } + // This is the configuration that will contain all the JAVA_RUNTIME dependencies that are + // not fused in the resulting aar library. + val includeRuntimeUnmerged = project.configurations.create("includeRuntimeUnmerged").also { + it.isCanBeConsumed = false + it.isCanBeResolved = true + it.incoming.beforeResolve( + SegregatingConstraintHandler( + includeConfigurations, + it, + variantScope.mergeSpec, + project, + ) + ) + } + // this is the outgoing configuration for JAVA_API scoped declarations, it will contain + // this module and all transitive non merged dependencies + fun configureElements( + elements: Configuration, + usage: String, + artifacts: ArtifactsImpl, + publicationArtifact: Artifact.Single<RegularFile>, + publicationArtifactType: AndroidArtifacts.ArtifactType + ) { + // we are only interested in the last provider in the chain of transformers for this bundle. + // Obviously, this is theoretical at this point since there is no variant API to replace + // artifacts, there is always only one. + val bundleTaskProvider = publicationArtifact.let { + artifacts + .getArtifactContainer(it) + .getTaskProviders() + .last() + } + elements.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, usage) + ) + elements.isCanBeResolved = false + elements.isCanBeConsumed = true + elements.isTransitive = true + + elements.outgoing.variants { variants -> + variants.create(publicationArtifactType.type) { variant -> + variant.artifact(bundleTaskProvider) { artifact -> + artifact.type = publicationArtifactType.type + } + } + } + } - override val artifactForPublication: Artifact.Single<RegularFile> - get() = FusedLibraryInternalArtifactType.BUNDLED_LIBRARY + val includeApiElements = + project.configurations.create("apiElements") { apiElements -> + configureElements( + apiElements, + Usage.JAVA_API, + variantScope.artifacts, + FusedLibraryInternalArtifactType.BUNDLED_LIBRARY, + AndroidArtifacts.ArtifactType.AAR) - override val artifactTypeForPublication: AndroidArtifacts.ArtifactType - get() = AndroidArtifacts.ArtifactType.AAR + apiElements.extendsFrom(includedApiUnmerged) + } + // this is the outgoing configuration for JAVA_RUNTIME scoped declarations, it will contain + // this module and all transitive non merged dependencies + val includeRuntimeElements = + project.configurations.create("runtimeElements") { runtimeElements -> + configureElements( + runtimeElements, + Usage.JAVA_RUNTIME, + variantScope.artifacts, + FusedLibraryInternalArtifactType.BUNDLED_LIBRARY, + AndroidArtifacts.ArtifactType.AAR) + runtimeElements.extendsFrom(includeRuntimeUnmerged) + } + + val configurationsToAdd = listOf(includeApiClasspath, includeRuntimeClasspath) + configurationsToAdd.forEach { configuration -> + variantScope.incomingConfigurations.addConfiguration(configuration) + } + maybePublishToMaven( + project, + includeApiElements, + includeRuntimeElements, + includeRuntimeUnmerged + ) + } } diff --git a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt index 762746fb79..07bab17956 100644 --- a/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt +++ b/build-system/gradle-core/src/main/java/com/android/build/gradle/internal/plugins/PrivacySandboxSdkPlugin.kt @@ -17,9 +17,15 @@ package com.android.build.gradle.internal.plugins import com.android.build.api.artifact.Artifact +import com.android.build.api.artifact.impl.ArtifactsImpl +import com.android.build.api.attributes.BuildTypeAttr import com.android.build.api.dsl.PrivacySandboxSdkExtension import com.android.build.gradle.internal.dsl.InternalPrivacySandboxSdkExtension import com.android.build.gradle.internal.dsl.PrivacySandboxSdkExtensionImpl +import com.android.build.gradle.internal.fusedlibrary.SegregatingConstraintHandler +import com.android.build.gradle.internal.fusedlibrary.configureTransforms +import com.android.build.gradle.internal.fusedlibrary.createTasks +import com.android.build.gradle.internal.fusedlibrary.getDslServices import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkInternalArtifactType import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScope import com.android.build.gradle.internal.privaysandboxsdk.PrivacySandboxSdkVariantScopeImpl @@ -27,6 +33,7 @@ import com.android.build.gradle.internal.publishing.AndroidArtifacts import com.android.build.gradle.internal.res.PrivacySandboxSdkLinkAndroidResourcesTask import com.android.build.gradle.internal.services.Aapt2DaemonBuildService import com.android.build.gradle.internal.services.Aapt2ThreadPoolBuildService +import com.android.build.gradle.internal.services.DslServices import com.android.build.gradle.internal.services.TaskCreationServicesImpl import com.android.build.gradle.internal.services.VersionedSdkLoaderService import com.android.build.gradle.internal.tasks.AppMetadataTask @@ -47,99 +54,250 @@ import com.android.build.gradle.tasks.PrivacySandboxSdkMergeResourcesTask import com.android.repository.Revision import com.google.wireless.android.sdk.stats.GradleBuildProject import org.gradle.api.GradleException +import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.Usage import org.gradle.api.component.SoftwareComponentFactory import org.gradle.api.file.RegularFile import org.gradle.build.event.BuildEventsListenerRegistry import javax.inject.Inject class PrivacySandboxSdkPlugin @Inject constructor( - listenerRegistry: BuildEventsListenerRegistry, -): AbstractPrivacySandboxPlugin(listenerRegistry) { + val softwareComponentFactory: SoftwareComponentFactory, + listenerRegistry: BuildEventsListenerRegistry, +) : AndroidPluginBaseServices(listenerRegistry), Plugin<Project> { - private val versionedSdkLoaderService: VersionedSdkLoaderService by lazy { + val dslServices: DslServices by lazy(LazyThreadSafetyMode.NONE) { + withProject("dslServices") { project -> + getDslServices(project, projectServices) + } + } + + private val versionedSdkLoaderService: VersionedSdkLoaderService by lazy(LazyThreadSafetyMode.NONE) { withProject("versionedSdkLoaderService") { project -> VersionedSdkLoaderService( - dslServices, - project, - { - variantScope.compileSdkVersion - }, - { - Revision.parseRevision(extension.buildToolsVersion, Revision.Precision.MICRO) - }, + dslServices, + project, + { variantScope.compileSdkVersion }, + { + Revision.parseRevision(extension.buildToolsVersion, + Revision.Precision.MICRO) + }, ) } } // so far, there is only one variant. - override val variantScope: PrivacySandboxSdkVariantScope by lazy { + private val variantScope: PrivacySandboxSdkVariantScope by lazy { withProject("variantScope") { project -> PrivacySandboxSdkVariantScopeImpl( - project, - TaskCreationServicesImpl(projectServices), - { extension }, - { - BootClasspathConfigImpl( + project, + TaskCreationServicesImpl(projectServices), + { extension }, + ) { + BootClasspathConfigImpl( project, projectServices, versionedSdkLoaderService, null, false - ) - } - ) + ) + } } } - private val extension: PrivacySandboxSdkExtension by lazy { + private val extension: PrivacySandboxSdkExtension by lazy(LazyThreadSafetyMode.NONE) + { withProject("extension") { project -> instantiateExtension(project) } } + override fun configureProject(project: Project) { + val projectOptions = projectServices.projectOptions + Aapt2ThreadPoolBuildService.RegistrationAction(project, projectOptions).execute() + Aapt2DaemonBuildService.RegistrationAction(project, projectOptions).execute() + } + override fun configureExtension(project: Project) { extension } override fun apply(project: Project) { - super.apply(project) + super.basePluginApply(project) if (!projectServices.projectOptions[BooleanOption.PRIVACY_SANDBOX_SDK_SUPPORT]) { throw GradleException( "Privacy Sandbox SDK support is experimental, and must be explicitly enabled.\n" + - "To enable support, add\n" + - " ${BooleanOption.PRIVACY_SANDBOX_SDK_SUPPORT.propertyName}=true\n" + - "to your project's gradle.properties file." + "To enable support, add\n" + + " ${BooleanOption.PRIVACY_SANDBOX_SDK_SUPPORT.propertyName}=true\n" + + "to your project's gradle.properties file." + ) + } + + // so far by default, we consume and publish only 'debug' variant + + // 'include' is the configuration that users will use to indicate which dependencies should + // be fused. + val includeConfigurations = project.configurations.create("include").also { + it.isCanBeConsumed = false + val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + } + // This is the internal configuration that will be used to feed tasks that require access + // to the resolved 'include' dependency. It is for JAVA_API usage which mean all transitive + // dependencies that are implementation() scoped will not be included. + val includeApiClasspath = project.configurations.create("includeApiClasspath").also { + it.isCanBeConsumed = false + it.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_API) + ) + val buildType: BuildTypeAttr = project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + it.extendsFrom(includeConfigurations) + } + // This is the configuration that will contain all the JAVA_API dependencies that are not + // fused in the resulting aar library. + val includedApiUnmerged = project.configurations.create("includeApiUnmerged").also { + it.isCanBeConsumed = true + it.isCanBeResolved = true + it.incoming.beforeResolve( + SegregatingConstraintHandler( + includeApiClasspath, + it, + variantScope.mergeSpec, + project, + ) + ) + } + // This is the internal configuration that will be used to feed tasks that require access + // to the resolved 'include' dependency. It is for JAVA_RUNTIME usage which mean all transitive + // dependencies that are implementation() scoped will be included. + val includeRuntimeClasspath = + project.configurations.create("includeRuntimeClasspath").also { + it.isCanBeConsumed = false + it.isCanBeResolved = true + + it.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME) + ) + val buildType: BuildTypeAttr = + project.objects.named(BuildTypeAttr::class.java, "debug") + it.attributes.attribute( + BuildTypeAttr.ATTRIBUTE, + buildType, + ) + + it.extendsFrom(includeConfigurations) + } + // This is the configuration that will contain all the JAVA_RUNTIME dependencies that are + // not fused in the resulting aar library. + val includeRuntimeUnmerged = project.configurations.create("includeRuntimeUnmerged").also { + it.isCanBeConsumed = false + it.isCanBeResolved = true + it.incoming.beforeResolve( + SegregatingConstraintHandler( + includeConfigurations, + it, + variantScope.mergeSpec, + project, + ) + ) + } + // this is the outgoing configuration for JAVA_API scoped declarations, it will contain + // this module and all transitive non merged dependencies + fun configureElements( + elements: Configuration, + usage: String, + artifacts: ArtifactsImpl, + publicationArtifact: Artifact.Single<RegularFile>, + publicationArtifactType: AndroidArtifacts.ArtifactType + ) { + // we are only interested in the last provider in the chain of transformers for this bundle. + // Obviously, this is theoretical at this point since there is no variant API to replace + // artifacts, there is always only one. + val bundleTaskProvider = publicationArtifact.let { + artifacts + .getArtifactContainer(it) + .getTaskProviders() + .last() + } + elements.attributes.attribute( + Usage.USAGE_ATTRIBUTE, + project.objects.named(Usage::class.java, usage) ) + elements.isCanBeResolved = false + elements.isCanBeConsumed = true + elements.isTransitive = true + + elements.outgoing.variants { variants -> + variants.create(publicationArtifactType.type) { variant -> + variant.artifact(bundleTaskProvider) { artifact -> + artifact.type = publicationArtifactType.type + } + } + } + } + project.configurations.create("apiElements") { apiElements -> + configureElements( + apiElements, + Usage.JAVA_API, + variantScope.artifacts, + PrivacySandboxSdkInternalArtifactType.ASAR, + AndroidArtifacts.ArtifactType.ANDROID_PRIVACY_SANDBOX_SDK_ARCHIVE) + + apiElements.extendsFrom(includedApiUnmerged) + } + // this is the outgoing configuration for JAVA_RUNTIME scoped declarations, it will contain + // this module and all transitive non merged dependencies + project.configurations.create("runtimeElements") { runtimeElements -> + configureElements( + runtimeElements, + Usage.JAVA_RUNTIME, + variantScope.artifacts, + PrivacySandboxSdkInternalArtifactType.ASAR, + AndroidArtifacts.ArtifactType.ANDROID_PRIVACY_SANDBOX_SDK_ARCHIVE) + runtimeElements.extendsFrom(includeRuntimeUnmerged) + } + val configurationsToAdd = listOf(includeApiClasspath, includeRuntimeClasspath) + configurationsToAdd.forEach { configuration -> + variantScope.incomingConfigurations.addConfiguration(configuration) } - Aapt2ThreadPoolBuildService.RegistrationAction(project, projectServices.projectOptions).execute() - Aapt2DaemonBuildService.RegistrationAction(project, projectServices.projectOptions).execute() } private fun instantiateExtension(project: Project): PrivacySandboxSdkExtension { - val sdkLibraryExtensionImpl= dslServices.newDecoratedInstance( - PrivacySandboxSdkExtensionImpl::class.java, - dslServices, + val sdkLibraryExtensionImpl = dslServices.newDecoratedInstance( + PrivacySandboxSdkExtensionImpl::class.java, + dslServices, ) abstract class Extension( - val publicExtensionImpl: PrivacySandboxSdkExtensionImpl, + val publicExtensionImpl: PrivacySandboxSdkExtensionImpl, ): InternalPrivacySandboxSdkExtension by publicExtensionImpl return project.extensions.create( - PrivacySandboxSdkExtension::class.java, - "android", - Extension::class.java, - sdkLibraryExtensionImpl + PrivacySandboxSdkExtension::class.java, + "android", + Extension::class.java, + sdkLibraryExtensionImpl ) } override fun createTasks(project: Project) { + configureTransforms(project, projectServices) createTasks( project, - variantScope, + variantScope.artifacts, + PrivacySandboxSdkInternalArtifactType.ASAR, listOf( AppMetadataTask.PrivacySandboxSdkCreationAction(variantScope), FusedLibraryMergeClasses.PrivacySandboxSdkCreationAction(variantScope), @@ -154,18 +312,10 @@ class PrivacySandboxSdkPlugin @Inject constructor( PerModuleBundleTask.PrivacySandboxSdkCreationAction(variantScope), PackagePrivacySandboxSdkBundle.CreationAction(variantScope), ValidateSigningTask.PrivacySandboxSdkCreationAction(variantScope), - ) + FusedLibraryMergeArtifactTask.getCreationActions(variantScope), + ) + FusedLibraryMergeArtifactTask.getCreationActions(variantScope) ) } - override fun getAnalyticsPluginType(): GradleBuildProject.PluginType = - GradleBuildProject.PluginType.PRIVACY_SANDBOX_SDK - - /** - * ASB only get published to Play Store, not maven - */ - override val artifactForPublication: Artifact.Single<RegularFile> = PrivacySandboxSdkInternalArtifactType.ASAR - - override val artifactTypeForPublication: AndroidArtifacts.ArtifactType - get() = AndroidArtifacts.ArtifactType.ANDROID_PRIVACY_SANDBOX_SDK_ARCHIVE + override fun getAnalyticsPluginType(): GradleBuildProject.PluginType = + GradleBuildProject.PluginType.PRIVACY_SANDBOX_SDK } |