Skip to content

Commit

Permalink
Fix booster-task-graph
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsonlee committed Jul 21, 2024
1 parent 3d1f6ed commit 6bbcfe3
Show file tree
Hide file tree
Showing 10 changed files with 297 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -67,38 +67,71 @@ fun <T> Project.getProperty(name: String, defaultValue: T): T {
}
}

/**
* Returns the local android resources or empty list if the project is not an android project
*/
val Project.localAndroidResources: List<File>
get() = when {
isAndroid -> project.variants.mapNotNull(Variant::localAndroidResources).flatten()
else -> emptyList()
}

@JvmOverloads
fun Project.getUpstreamProjects(
transitive: Boolean = true,
variant: Variant? = null
): Set<Project> = getResolvedArtifactResults(transitive, variant).mapNotNull {
(it.id.componentIdentifier as? ProjectComponentIdentifier)?.projectPath?.let { projectPath ->
rootProject.project(projectPath)
}
filter: List<Variant>.() -> List<Variant>
): Set<Project> = getResolvedArtifacts(transitive, filter) {
it.id.componentIdentifier as? ProjectComponentIdentifier
}.map {
rootProject.project(it.projectPath)
}.toSet()

/**
* Returns the upstream artifacts of the target project, the dependencies can be filtered based on the target
* project’s variant, such as filtering the dependencies corresponding to the `debug` variant of the target project.
*
* @param T the result of transform function
* @param transitive whether to resolve the artifacts transitively
* @param filter filter the dependencies by variant
* @see [filterByNameOrBuildType]
*/
@JvmOverloads
fun <T> Project.getResolvedArtifacts(
transitive: Boolean = true,
filter: List<Variant>.() -> List<Variant>,
transform: (ResolvedArtifactResult) -> T?
): Set<T> = getResolvedArtifactResults(transitive, filter).mapNotNull {
transform(it)
}.toSet()

@JvmOverloads
fun Project.getResolvedArtifactResults(
transitive: Boolean = true,
variant: Variant? = null
filter: List<Variant>.() -> List<Variant>
): Set<ResolvedArtifactResult> = when {
variant == null -> emptySet()
isAndroid -> getResolvedArtifactResultsRecursively(transitive) {
filterByVariant(variant).map { v ->
variants.filter().map { v ->
AGP.run { v.getDependencies(transitive) }
}.flatten()
}

isJava -> getResolvedArtifactResultsRecursively(transitive) {
configurations.getByName(RUNTIME_CLASSPATH_CONFIGURATION_NAME).resolvedConfiguration.resolvedArtifacts.map {
ResolvedArtifactResultImpl(it.id, it.file)
}
}

else -> emptySet()
}.distinctBy {
it.id.componentIdentifier
}.toSet()

private fun Project.getResolvedArtifactResultsRecursively(transitive: Boolean, resolve: Project.() -> List<ResolvedArtifactResult>): Set<ResolvedArtifactResult> {
/**
* Returns the resolved artifact results recursively
*/
@JvmOverloads
fun Project.getResolvedArtifactResultsRecursively(
transitive: Boolean = true,
resolve: Project.() -> List<ResolvedArtifactResult>
): Set<ResolvedArtifactResult> {
val stack = Stack<Project>()
val results = mutableMapOf<ComponentIdentifier, ResolvedArtifactResult>()

Expand All @@ -125,44 +158,43 @@ private fun Project.getResolvedArtifactResultsRecursively(transitive: Boolean, r

/**
* Returns the jar files which could be the outputs of the jar task or createFullJar task
*
* @param variant The build variant
*/
fun Project.getJars(variant: Variant? = null): Set<File> = getJarTaskProviders(variant).map {
fun Project.getJars(
filter: List<Variant>.() -> List<Variant>
): Set<File> = getJarTaskProviders(filter).map {
it.get().outputs.files
}.flatten().toSet()

fun Project.getJarTaskProviders(variant: Variant? = null): Collection<TaskProvider<out Task>> = when {
/**
* Returns the jar task provider of all matched variants
* * Android Project
* - application: createFullJar
* - library: bundleClasses
* * Java Project
* - jar
*/
fun Project.getJarTaskProviders(
filter: List<Variant>.() -> List<Variant>
): Collection<TaskProvider<out Task>> = when {
isAndroid -> when (getAndroidComponentsOrNull<AndroidComponentsExtension<*, *, *>>()) {
is LibraryAndroidComponentsExtension -> filterByVariant(variant).mapNotNull(Variant::createFullJarTaskProvider)
is ApplicationAndroidComponentsExtension -> filterByVariant(variant).mapNotNull(Variant::bundleClassesTaskProvider)
is LibraryAndroidComponentsExtension -> variants.filter().mapNotNull(Variant::createFullJarTaskProvider)
is ApplicationAndroidComponentsExtension -> variants.filter().mapNotNull(Variant::bundleClassesTaskProvider)
else -> emptyList()
}

isJavaLibrary -> listOf(tasks.named(JavaPlugin.JAR_TASK_NAME))
else -> emptyList()
}

private fun Project.filterByVariant(variant: Variant? = null): Collection<Variant> {
val variants = when (getAndroidComponentsOrNull<AndroidComponentsExtension<*, *, *>>()) {
is ApplicationAndroidComponentsExtension -> plugins.getPlugin(AppPlugin::class.java).variantManager
is LibraryAndroidComponentsExtension -> plugins.getPlugin(LibraryPlugin::class.java).variantManager
val Project.variants: List<Variant>
get() = when (getAndroidComponentsOrNull<AndroidComponentsExtension<*, *, *>>()) {
is ApplicationAndroidComponentsExtension -> plugins.getPlugin(AppPlugin::class.java)
is LibraryAndroidComponentsExtension -> plugins.getPlugin(LibraryPlugin::class.java)
else -> null
}?.mainComponents?.map {
}?.variantManager?.mainComponents?.map {
it.variant
}?.filterIsInstance<Variant>() ?: emptyList()

if (null == variant) return variants

return variants.filter {
it.name == variant.name
}.takeIf {
it.isNotEmpty()
} ?: variants.filter {
it.buildType == variant.buildType
}
}

private data class ResolvedArtifactResultImpl(
private val artifactId: ComponentArtifactIdentifier,
private val artifactFile: File
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.didiglobal.booster.gradle

import com.android.build.api.artifact.ScopedArtifact
import com.android.build.api.variant.ScopedArtifacts
import com.android.build.api.variant.Variant
import org.gradle.api.DefaultTask
import org.gradle.api.file.Directory
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.InputFiles
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskProvider

abstract class ScopedTask : DefaultTask() {

@get:Internal
abstract val variant: Property<Variant>

@get:InputFiles
@get:PathSensitive(PathSensitivity.NONE)
abstract val inputJars: ListProperty<RegularFile>

@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val inputDirectories: ListProperty<Directory>

interface CreationAction<T : ScopedTask> {

val artifactScope: ScopedArtifacts.Scope
get() = ScopedArtifacts.Scope.PROJECT

val artifactType: ScopedArtifact
get() = ScopedArtifact.CLASSES

fun configure(task: T) {}
}

}

/**
* Register a task for the specified variant
*
* @param prefix The prefix of task name
* @param action The task creation action
*/
inline fun <reified T : ScopedTask, reified A : ScopedTask.CreationAction<T>> Variant.registerTask(
prefix: String,
action: A
): TaskProvider<T> = project.tasks.register(getTaskName(prefix), T::class.java) {
it.variant.set(this)
action.configure(it)
}.also { taskProvider ->
artifacts.forScope(action.artifactScope)
.use(taskProvider)
.toGet(action.artifactType, ScopedTask::inputJars, ScopedTask::inputDirectories)
}

/**
* Register a task for the specified variant
*
* @param prefix The prefix of task name
* @param suffix The suffix of task name
* @param action The task creation action
*/
inline fun <reified T : ScopedTask, reified A : ScopedTask.CreationAction<T>> Variant.registerTask(
prefix: String,
suffix: String,
action: A
): TaskProvider<T> = project.tasks.register(getTaskName(prefix, suffix), T::class.java) {
it.variant.set(this)
action.configure(it)
}.also { taskProvider ->
artifacts.forScope(action.artifactScope)
.use(taskProvider)
.toGet(action.artifactType, ScopedTask::inputJars, ScopedTask::inputDirectories)
}
Original file line number Diff line number Diff line change
Expand Up @@ -126,18 +126,18 @@ fun Variant.getTaskName(prefix: String, suffix: String): String = AGP.run {
getTaskName(prefix, suffix)
}

val Variant.isApplication: Boolean
get() = AGP.run {
val Variant?.isApplication: Boolean
get() = null != this && AGP.run {
isApplication
}

val Variant.isLibrary: Boolean
get() = AGP.run {
val Variant?.isLibrary: Boolean
get() = null != this && AGP.run {
isLibrary
}

val Variant.isDynamicFeature: Boolean
get() = AGP.run {
val Variant?.isDynamicFeature: Boolean
get() = null != this && AGP.run {
isDynamicFeature
}

Expand Down Expand Up @@ -246,6 +246,11 @@ val Variant.symbolListWithPackageName: FileCollection
symbolListWithPackageName
}

val Variant.localAndroidResources: FileCollection
get() = AGP.run {
localAndroidResources
}

val Variant.allArtifacts: Map<String, FileCollection>
get() = AGP.run {
allArtifacts
Expand All @@ -256,7 +261,54 @@ val Variant.buildTools: BuildToolInfo
buildTools
}

val Variant.isPrecompileDependenciesResourcesEnabled: Boolean
get() = AGP.run {
val Variant?.isPrecompileDependenciesResourcesEnabled: Boolean
get() = null != this && AGP.run {
isPrecompileDependenciesResourcesEnabled
}

val Variant?.isDebuggable: Boolean
get() = null != this && AGP.run {
isDebuggable
}

/**
* Filter variants by variant name
*/
fun Variant?.filterByName(): List<Variant>.() -> List<Variant> = {
val variant = this@filterByName

if (null == variant) this else this.filter {
it.name == variant.name
}
}

/**
* Filter variants by build type
*/
fun Variant?.filterByBuildType(): List<Variant>.() -> List<Variant> = {
val variant = this@filterByBuildType

if (null == variant) this else this.filter {
it.buildType == variant.buildType
}
}

/**
* Filter variants by flavor name
*/
fun Variant?.filterByFlavorName(): List<Variant>.() -> List<Variant> = {
val variant = this@filterByFlavorName

if (null == variant) this else this.filter {
it.flavorName == variant.flavorName
}
}

/**
* Filter variants by variant name or build type
*/
fun Variant?.filterByNameOrBuildType(): List<Variant>.() -> List<Variant> = {
filterByName().invoke(this).takeIf {
it.isNotEmpty()
} ?: filterByBuildType().invoke(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ interface AGPInterface {

val Variant.isPrecompileDependenciesResourcesEnabled: Boolean

val Variant.isDebuggable: Boolean

fun Variant.getDependencies(
transitive: Boolean = true,
filter: (ComponentIdentifier) -> Boolean = { true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ internal object V80 : AGPInterface {
get() = when (this) {
is VariantImpl<*> -> this
is AnalyticsEnabledVariant -> this.delegate as VariantImpl<*>
else -> TODO("No implementationed!")
else -> TODO("No implemented!")
}

@Suppress("UnstableApiUsage")
Expand Down Expand Up @@ -304,6 +304,9 @@ internal object V80 : AGPInterface {
override val Variant.isPrecompileDependenciesResourcesEnabled: Boolean
get() = component.androidResourcesCreationConfig?.isPrecompileDependenciesResourcesEnabled == true

override val Variant.isDebuggable: Boolean
get() = component.debuggable

override fun Variant.getDependencies(
transitive: Boolean,
filter: (ComponentIdentifier) -> Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ internal object V81 : AGPInterface {
get() = when (this) {
is VariantImpl<*> -> this
is AnalyticsEnabledVariant -> this.delegate as VariantImpl<*>
else -> TODO("No implementationed!")
else -> TODO("No implemented!")
}

@Suppress("UnstableApiUsage")
Expand Down Expand Up @@ -307,6 +307,9 @@ internal object V81 : AGPInterface {
override val Variant.isPrecompileDependenciesResourcesEnabled: Boolean
get() = component.androidResourcesCreationConfig?.isPrecompileDependenciesResourcesEnabled == true

override val Variant.isDebuggable: Boolean
get() = component.debuggable

override fun Variant.getDependencies(
transitive: Boolean,
filter: (ComponentIdentifier) -> Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ internal object V82 : AGPInterface {
get() = when (this) {
is VariantImpl<*> -> this
is AnalyticsEnabledVariant -> this.delegate as VariantImpl<*>
else -> TODO("No implementationed!")
else -> TODO("No implemented!")
}

@Suppress("UnstableApiUsage")
Expand Down Expand Up @@ -307,6 +307,9 @@ internal object V82 : AGPInterface {
override val Variant.isPrecompileDependenciesResourcesEnabled: Boolean
get() = component.androidResourcesCreationConfig?.isPrecompileDependenciesResourcesEnabled == true

override val Variant.isDebuggable: Boolean
get() = component.debuggable

override fun Variant.getDependencies(
transitive: Boolean,
filter: (ComponentIdentifier) -> Boolean
Expand Down
Loading

0 comments on commit 6bbcfe3

Please sign in to comment.