diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index bb8e3eb4e..42a330c04 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -10,8 +10,11 @@ moshix = "0.19.0"
okio = "2.10.0"
retrofit = "2.9.0"
-agp = "7.4.2"
-agp-common = "30.4.2"
+agp = "8.0.2"
+#agp = "8.1.4
+#agp = "8.2.1"
+#agp = "8.3.0-beta01" # Provides `Sources.manifests`
+agp-common = "31.2.0"
[libraries]
agp = { module = "com.android.tools.build:gradle", version.ref = "agp" }
diff --git a/src/functionalTest/groovy/com/autonomousapps/AbstractProject.groovy b/src/functionalTest/groovy/com/autonomousapps/AbstractProject.groovy
index 16695ccd6..360bb291f 100644
--- a/src/functionalTest/groovy/com/autonomousapps/AbstractProject.groovy
+++ b/src/functionalTest/groovy/com/autonomousapps/AbstractProject.groovy
@@ -7,17 +7,26 @@ import com.autonomousapps.kit.GradleProject
import com.autonomousapps.kit.gradle.BuildscriptBlock
import com.autonomousapps.kit.gradle.GradleProperties
import com.autonomousapps.kit.gradle.dependencies.Plugins
+import com.autonomousapps.utils.DebugAware
@SuppressWarnings('GrMethodMayBeStatic')
abstract class AbstractProject extends AbstractGradleProject {
- protected static final PRINT_ADVICE = "dependency.analysis.print.build.health=true"
+ protected static final String PRINT_ADVICE = "dependency.analysis.print.build.health=true"
@Override
- protected GradleProject.Builder newGradleProjectBuilder(GradleProject.DslKind dslKind = GradleProject.DslKind.GROOVY) {
+ protected GradleProject.Builder newGradleProjectBuilder(
+ GradleProject.DslKind dslKind = GradleProject.DslKind.GROOVY
+ ) {
+ def additionalProperties = GradleProperties.of(PRINT_ADVICE)
+ // There is a Gradle bug that makes tests break when the test uses CC and we're also debugging
+ if (!DebugAware.debug) {
+ additionalProperties += GradleProperties.enableConfigurationCache()
+ }
+
return super.newGradleProjectBuilder(dslKind)
.withRootProject { r ->
- r.gradleProperties += GradleProperties.enableConfigurationCache() + PRINT_ADVICE
+ r.gradleProperties += additionalProperties
r.withBuildScript { bs ->
bs.plugins(Plugins.dependencyAnalysis, Plugins.kotlinNoApply)
}
diff --git a/src/functionalTest/groovy/com/autonomousapps/android/AbstractAndroidSpec.groovy b/src/functionalTest/groovy/com/autonomousapps/android/AbstractAndroidSpec.groovy
index 56f56aef4..2dfac700f 100644
--- a/src/functionalTest/groovy/com/autonomousapps/android/AbstractAndroidSpec.groovy
+++ b/src/functionalTest/groovy/com/autonomousapps/android/AbstractAndroidSpec.groovy
@@ -7,30 +7,36 @@ import com.autonomousapps.fixtures.ProjectDirProvider
import com.autonomousapps.internal.android.AgpVersion
import org.gradle.util.GradleVersion
+/**
+ * @see AGP artifacts
+ */
abstract class AbstractAndroidSpec extends AbstractFunctionalSpec {
protected ProjectDirProvider androidProject = null
- protected static final AGP_7_3 = AgpVersion.version('7.3.1')
- protected static final AGP_7_4 = AgpVersion.version('7.4.2')
protected static final AGP_8_0 = AgpVersion.version('8.0.2')
- protected static final AGP_8_1 = AgpVersion.version('8.1.0')
- protected static final AGP_8_2 = AgpVersion.version('8.2.0-alpha16')
+ protected static final AGP_8_1 = AgpVersion.version('8.1.4')
+ protected static final AGP_8_2 = AgpVersion.version('8.2.0')
+ protected static final AGP_8_3 = AgpVersion.version('8.3.0-beta01')
+ protected static final AGP_8_4 = AgpVersion.version('8.4.0-alpha01')
- protected static final AGP_LATEST = AGP_8_2
+ protected static final AGP_LATEST = AGP_8_4
/**
- * {@code AGP_7_4} represents the minimum stable _tested_ version. {@code AGP_8_1} represents the maximum stable
+ * TODO(tsr): this doc is perpetually out of date.
+ *
+ * {@code AGP_8_0} represents the minimum stable _tested_ version. {@code AGP_8_1} represents the maximum stable
* _tested_ version. We also test against the latest alpha, {@code AGP_8_2} at time of writing. DAGP may work with
* other versions of AGP, but they aren't tested, primarily for CI performance reasons.
*
* @see AGP releases
*/
protected static final SUPPORTED_AGP_VERSIONS = [
- AGP_7_4,
-// AGP_8_0,
+ AGP_8_0,
AGP_8_1,
AGP_8_2,
+ AGP_8_3,
+ AGP_8_4,
]
protected static List agpVersions(AgpVersion minAgpVersion = AgpVersion.AGP_MIN) {
diff --git a/src/functionalTest/groovy/com/autonomousapps/android/DuplicateDependencyVersionsSpec.groovy b/src/functionalTest/groovy/com/autonomousapps/android/DuplicateDependencyVersionsSpec.groovy
index 0858f4845..e33d269bf 100644
--- a/src/functionalTest/groovy/com/autonomousapps/android/DuplicateDependencyVersionsSpec.groovy
+++ b/src/functionalTest/groovy/com/autonomousapps/android/DuplicateDependencyVersionsSpec.groovy
@@ -46,6 +46,6 @@ final class DuplicateDependencyVersionsSpec extends AbstractAndroidSpec {
.contains(project.expectedOutput)
where:
- [gradleVersion, agpVersion] << multivariableDataPipe([GRADLE_7_5], [AGP_7_3.version])
+ [gradleVersion, agpVersion] << multivariableDataPipe([GRADLE_8_0], [AGP_8_0.version])
}
}
diff --git a/src/functionalTest/groovy/com/autonomousapps/android/IgnoredVariantSpec.groovy b/src/functionalTest/groovy/com/autonomousapps/android/IgnoredVariantSpec.groovy
index b10ae075b..c746b1d24 100644
--- a/src/functionalTest/groovy/com/autonomousapps/android/IgnoredVariantSpec.groovy
+++ b/src/functionalTest/groovy/com/autonomousapps/android/IgnoredVariantSpec.groovy
@@ -13,7 +13,7 @@ import static com.google.common.truth.Truth.assertAbout
@SuppressWarnings("GroovyAssignabilityCheck")
final class IgnoredVariantSpec extends AbstractAndroidSpec {
- def "plugin ignore android variants (#gradleVersion AGP #agpVersion ignored debug)"() {
+ def "can ignore debug variant (#gradleVersion AGP #agpVersion)"() {
given:
def project = new DebugVariantIgnoredProject(agpVersion)
gradleProject = project.gradleProject
@@ -30,7 +30,7 @@ final class IgnoredVariantSpec extends AbstractAndroidSpec {
[gradleVersion, agpVersion] << gradleAgpMatrix()
}
- def "plugin ignore android variants (#gradleVersion AGP #agpVersion ignored release)"() {
+ def "can ignore release variant (#gradleVersion AGP #agpVersion)"() {
given:
def project = new ReleaseVariantIgnoredProject(agpVersion)
gradleProject = project.gradleProject
@@ -47,7 +47,7 @@ final class IgnoredVariantSpec extends AbstractAndroidSpec {
[gradleVersion, agpVersion] << gradleAgpMatrix()
}
- def "plugin ignore android variants (#gradleVersion AGP #agpVersion ignored all variants)"() {
+ def "can ignore all (debug and release) variants (#gradleVersion AGP #agpVersion)"() {
given:
def project = new AllVariantsIgnoredProject(agpVersion)
gradleProject = project.gradleProject
diff --git a/src/functionalTest/groovy/com/autonomousapps/android/projects/AbstractVariantProject.groovy b/src/functionalTest/groovy/com/autonomousapps/android/projects/AbstractVariantProject.groovy
index edcc9de06..6876a513c 100644
--- a/src/functionalTest/groovy/com/autonomousapps/android/projects/AbstractVariantProject.groovy
+++ b/src/functionalTest/groovy/com/autonomousapps/android/projects/AbstractVariantProject.groovy
@@ -15,6 +15,7 @@ import com.autonomousapps.kit.gradle.GradleProperties
import com.autonomousapps.kit.gradle.Plugin
import com.autonomousapps.kit.gradle.dependencies.Plugins
import com.autonomousapps.model.ProjectAdvice
+import com.autonomousapps.utils.DebugAware
import static com.autonomousapps.AdviceHelper.actualProjectAdvice
import static com.autonomousapps.kit.gradle.dependencies.Dependencies.*
@@ -37,9 +38,15 @@ abstract class AbstractVariantProject extends AbstractAndroidProject {
}
private GradleProject build() {
+ def properties = projectGradleProperties
+ if (!DebugAware.debug) {
+ // There is a Gradle bug that makes tests break when the test uses CC and we're also debugging
+ properties += GradleProperties.enableConfigurationCache()
+ }
+
return newAndroidGradleProjectBuilder(agpVersion)
.withRootProject { root ->
- root.gradleProperties = projectGradleProperties + GradleProperties.enableConfigurationCache()
+ root.gradleProperties = properties
}
.withAndroidSubproject('app') { a ->
a.sources = sources
diff --git a/src/functionalTest/groovy/com/autonomousapps/android/projects/DataBindingUsagesExclusionsProject.groovy b/src/functionalTest/groovy/com/autonomousapps/android/projects/DataBindingUsagesExclusionsProject.groovy
index 5080d28e0..8f745a99c 100644
--- a/src/functionalTest/groovy/com/autonomousapps/android/projects/DataBindingUsagesExclusionsProject.groovy
+++ b/src/functionalTest/groovy/com/autonomousapps/android/projects/DataBindingUsagesExclusionsProject.groovy
@@ -14,7 +14,6 @@ import com.autonomousapps.model.ProjectAdvice
import static com.autonomousapps.AdviceHelper.*
import static com.autonomousapps.kit.gradle.Dependency.project
import static com.autonomousapps.kit.gradle.dependencies.Dependencies.appcompat
-import static com.autonomousapps.kit.gradle.dependencies.Dependencies.kotlinStdLib
final class DataBindingUsagesExclusionsProject extends AbstractAndroidProject {
@@ -59,7 +58,6 @@ final class DataBindingUsagesExclusionsProject extends AbstractAndroidProject {
lib.withBuildScript { bs ->
bs.plugins = [Plugins.androidLib, Plugins.kotlinAndroid, Plugins.kapt]
bs.android = defaultAndroidLibBlock(true, 'com.example.lib')
- bs.dependencies = libDependencies
bs.withGroovy("android.buildFeatures.dataBinding true")
}
lib.sources = libSources
@@ -93,9 +91,8 @@ final class DataBindingUsagesExclusionsProject extends AbstractAndroidProject {
]
private List appDependencies = [
- kotlinStdLib("implementation"),
- appcompat("implementation"),
- project("implementation", ":lib"),
+ appcompat('implementation'),
+ project('implementation', ':lib'),
]
private libSources = [
@@ -114,10 +111,6 @@ final class DataBindingUsagesExclusionsProject extends AbstractAndroidProject {
)
]
- private List libDependencies = [
- kotlinStdLib('api')
- ]
-
private final Set expectedBuildHealthWithExclusions = [
projectAdviceForDependencies(':app', [
Advice.ofRemove(projectCoordinates(':lib'), 'implementation')
diff --git a/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidProjectAnalyzer.kt b/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidProjectAnalyzer.kt
index e7f75d353..8cc56ce2a 100644
--- a/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidProjectAnalyzer.kt
+++ b/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidProjectAnalyzer.kt
@@ -4,7 +4,6 @@
package com.autonomousapps.internal.analyzer
-import com.android.build.gradle.api.BaseVariant
import com.autonomousapps.internal.ArtifactAttributes
import com.autonomousapps.internal.OutputPaths
import com.autonomousapps.internal.android.AndroidGradlePluginFactory
@@ -16,8 +15,6 @@ import com.autonomousapps.services.InMemoryCache
import com.autonomousapps.tasks.*
import org.gradle.api.Project
import org.gradle.api.Task
-import org.gradle.api.file.FileCollection
-import org.gradle.api.file.FileTree
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
@@ -25,41 +22,37 @@ import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.register
import java.io.File
-/**
- * Base class for analyzing an Android project (com.android.application or com.android.library only).
- */
+/** Base class for analyzing an Android project (`com.android.application` or `com.android.library` only). */
internal abstract class AndroidAnalyzer(
project: Project,
- protected val variant: BaseVariant,
- protected val variantSourceSet: VariantSourceSet,
+ protected val variant: AndroidVariant,
+ protected val androidSources: AndroidSources,
agpVersion: String,
) : AbstractDependencyAnalyzer(project) {
protected val agp = AndroidGradlePluginFactory(project, agpVersion).newAdapter()
- private val dataBindingEnabled = agp.isDataBindingEnabled()
- private val viewBindingEnabled = agp.isViewBindingEnabled()
final override val flavorName: String = variant.flavorName
- final override val variantName: String = variant.name
- final override val buildType: String = variant.buildType.name
- final override val kind: SourceSetKind = variantSourceSet.variant.kind
+ final override val variantName: String = variant.variantName
+ final override val buildType: String = variant.buildType
+ final override val kind: SourceSetKind = androidSources.variant.kind
final override val variantNameCapitalized: String = variantName.capitalizeSafely()
final override val taskNameSuffix: String = computeTaskNameSuffix()
- final override val compileConfigurationName = variantSourceSet.compileClasspathConfigurationName
- final override val runtimeConfigurationName = variantSourceSet.runtimeClasspathConfigurationName
+ final override val compileConfigurationName = androidSources.compileClasspathConfigurationName
+ final override val runtimeConfigurationName = androidSources.runtimeClasspathConfigurationName
final override val kaptConfigurationName = kaptConfName()
final override val annotationProcessorConfigurationName = "${variantName}AnnotationProcessorClasspath"
- final override val testInstrumentationRunner: String? = variant.mergedFlavor.testInstrumentationRunner
- final override val kotlinSourceFiles: FileCollection = getKotlinSources()
- final override val javaSourceFiles: FileCollection = getJavaSources()
- final override val groovySourceFiles: FileCollection = getGroovySources()
- final override val scalaSourceFiles: FileCollection = getScalaSources()
+ final override val testInstrumentationRunner: Provider = variant.testInstrumentationRunner
+ final override val kotlinSourceFiles: Provider> = androidSources.getKotlinSources()
+ final override val javaSourceFiles: Provider> = androidSources.getJavaSources()
+ final override val groovySourceFiles: Provider> = project.provider { project.files() }
+ final override val scalaSourceFiles: Provider> = project.provider { project.files() }
// TODO(2.0): verify this is the correct attribute.
final override val attributeValueJar = ArtifactAttributes.ANDROID_CLASSES_JAR
- final override val isDataBindingEnabled: Boolean = dataBindingEnabled
- final override val isViewBindingEnabled: Boolean = viewBindingEnabled
+ final override val isDataBindingEnabled: Provider = agp.isDataBindingEnabled()
+ final override val isViewBindingEnabled: Provider = agp.isViewBindingEnabled()
final override val outputPaths = OutputPaths(project, "$variantName${kind.taskNameSuffix}")
@@ -98,9 +91,9 @@ internal abstract class AndroidAnalyzer(
final override fun registerExplodeXmlSourceTask(): TaskProvider {
return project.tasks.register("explodeXmlSource$taskNameSuffix") {
- androidLocalRes.setFrom(getAndroidRes())
- layouts(variant.sourceSets.flatMap { it.resDirectories })
- manifestFiles.setFrom(variant.sourceSets.map { it.manifestFile })
+ androidLocalRes.setFrom(androidSources.getAndroidRes())
+ layoutFiles.setFrom(androidSources.getLayoutFiles())
+ manifestFiles.setFrom(androidSources.getManifestFiles())
namespace.set(agp.namespace())
output.set(outputPaths.androidResToResUsagePath)
}
@@ -108,7 +101,7 @@ internal abstract class AndroidAnalyzer(
final override fun registerExplodeAssetSourceTask(): TaskProvider {
return project.tasks.register("explodeAssetSource$taskNameSuffix") {
- androidLocalAssets.setFrom(getAndroidAssets())
+ androidLocalAssets.setFrom(androidSources.getAndroidAssets())
output.set(outputPaths.androidAssetSourcePath)
}
}
@@ -146,7 +139,7 @@ internal abstract class AndroidAnalyzer(
}
private fun kaptConfName(): String {
- return when (variantSourceSet.variant.kind) {
+ return when (androidSources.variant.kind) {
SourceSetKind.MAIN -> "kapt$variantNameCapitalized"
SourceSetKind.TEST -> "kaptTest"
SourceSetKind.ANDROID_TEST -> "kaptAndroidTest"
@@ -156,7 +149,7 @@ internal abstract class AndroidAnalyzer(
// Known to exist in Kotlin 1.3.61.
private fun kotlinCompileTask(): TaskProvider? {
- return when (variantSourceSet.variant.kind) {
+ return when (androidSources.variant.kind) {
SourceSetKind.MAIN -> project.tasks.namedOrNull("compile${variantNameCapitalized}Kotlin")
SourceSetKind.TEST -> project.tasks.namedOrNull("compile${variantNameCapitalized}UnitTestKotlin")
SourceSetKind.ANDROID_TEST -> project.tasks.namedOrNull("compile${variantNameCapitalized}AndroidTestKotlin")
@@ -167,7 +160,7 @@ internal abstract class AndroidAnalyzer(
// Known to exist in AGP 3.5, 3.6, and 4.0, albeit with different backing classes (AndroidJavaCompile,
// JavaCompile)
private fun javaCompileTask(): TaskProvider {
- return when (variantSourceSet.variant.kind) {
+ return when (androidSources.variant.kind) {
SourceSetKind.MAIN -> project.tasks.named("compile${variantNameCapitalized}JavaWithJavac")
SourceSetKind.TEST -> project.tasks.named("compile${variantNameCapitalized}UnitTestJavaWithJavac")
SourceSetKind.ANDROID_TEST -> project.tasks.named("compile${variantNameCapitalized}AndroidTestJavaWithJavac")
@@ -176,76 +169,37 @@ internal abstract class AndroidAnalyzer(
}
private fun computeTaskNameSuffix(): String {
- return if (variantSourceSet.variant.kind == SourceSetKind.MAIN) {
+ return if (androidSources.variant.kind == SourceSetKind.MAIN) {
// "flavorDebug" -> "FlavorDebug"
variantName.capitalizeSafely()
} else {
// "flavorDebug" + "Test" -> "FlavorDebugTest"
- variantName.capitalizeSafely() + variantSourceSet.variant.kind.taskNameSuffix
+ variantName.capitalizeSafely() + androidSources.variant.kind.taskNameSuffix
}
}
-
- private fun getGroovySources(): FileCollection = getSourceDirectories().matching(Language.filterOf(Language.GROOVY))
- private fun getJavaSources(): FileCollection = getSourceDirectories().matching(Language.filterOf(Language.JAVA))
- private fun getKotlinSources(): FileCollection = getSourceDirectories().matching(Language.filterOf(Language.KOTLIN))
- private fun getScalaSources(): FileCollection = getSourceDirectories().matching(Language.filterOf(Language.SCALA))
-
- private fun getSourceDirectories(): FileTree {
- // Java dirs regardless of whether they exist
- val javaDirs = variantSourceSet.androidSourceSets.flatMap { it.javaDirectories }
-
- // Kotlin dirs, only if they exist. If we filtered the above for existence, and there was no
- // Java dir, then this would also be empty.
- val kotlinDirs = javaDirs
- .map { it.path }
- .map { it.removeSuffix("java") + "kotlin" }
- .map { File(it) }
- .filter { it.exists() }
-
- // Now finally filter Java dirs for existence
- return project.files(javaDirs.filter { it.exists() } + kotlinDirs).asFileTree
- }
-
- private fun getAndroidRes(): FileTree {
- val resDirs = variant.sourceSets.flatMap {
- it.resDirectories
- }.filter { it.exists() }
-
- return project.files(resDirs).asFileTree.matching {
- include("**/*.xml")
- }
- }
-
- private fun getAndroidAssets(): FileCollection {
- val assetsDirs = variant.sourceSets.flatMap {
- it.assetsDirectories
- }.filter { it.exists() }
-
- return project.files(assetsDirs).asFileTree
- }
}
internal class AndroidAppAnalyzer(
project: Project,
- variant: BaseVariant,
+ variant: AndroidVariant,
agpVersion: String,
- variantSourceSet: VariantSourceSet,
+ androidSources: AndroidSources,
) : AndroidAnalyzer(
project = project,
variant = variant,
- variantSourceSet = variantSourceSet,
+ androidSources = androidSources,
agpVersion = agpVersion
)
internal class AndroidLibAnalyzer(
project: Project,
- variant: BaseVariant,
+ variant: AndroidVariant,
agpVersion: String,
- variantSourceSet: VariantSourceSet,
+ androidSources: AndroidSources,
) : AndroidAnalyzer(
project = project,
variant = variant,
- variantSourceSet = variantSourceSet,
+ androidSources = androidSources,
agpVersion = agpVersion
) {
diff --git a/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidSources.kt b/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidSources.kt
new file mode 100644
index 000000000..29788170b
--- /dev/null
+++ b/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidSources.kt
@@ -0,0 +1,96 @@
+// Copyright (c) 2024. Tony Robalik.
+// SPDX-License-Identifier: Apache-2.0
+package com.autonomousapps.internal.analyzer
+
+import com.android.build.api.artifact.SingleArtifact
+import com.android.build.api.variant.Sources
+import com.autonomousapps.model.declaration.Variant
+import org.gradle.api.Project
+import org.gradle.api.provider.Provider
+import java.io.File
+
+/**
+ * All the relevant sources for a given Android variant, including Java, Kotlin, assets, res, manifest files, and
+ * layouts.
+ */
+internal interface AndroidSources {
+ val variant: Variant
+
+ /** E.g., `debugCompileClasspath` or `debugUnitTestCompileClasspath` */
+ val compileClasspathConfigurationName: String
+
+ /** E.g., `debugRuntimeClasspath` or `debugUnitTestRuntimeClasspath` */
+ val runtimeClasspathConfigurationName: String
+
+ fun getJavaSources(): Provider>
+ fun getKotlinSources(): Provider>
+ fun getAndroidAssets(): Provider>
+ fun getAndroidRes(): Provider>
+ fun getManifestFiles(): Provider>
+ fun getLayoutFiles(): Provider>
+}
+
+@Suppress("UnstableApiUsage")
+internal class DefaultAndroidSources(
+ private val project: Project,
+ private val agpVariant: com.android.build.api.variant.Variant,
+ private val sources: Sources,
+ override val variant: Variant,
+ override val compileClasspathConfigurationName: String,
+ override val runtimeClasspathConfigurationName: String,
+) : AndroidSources {
+
+ override fun getJavaSources(): Provider> {
+ return sources.kotlin?.all
+ ?.map { directories ->
+ directories.map { directory -> directory.asFileTree.matching(Language.filterOf(Language.JAVA)) }
+ }?.map { trees -> trees.flatten() }
+ ?: project.provider { emptyList() }
+ }
+
+ override fun getKotlinSources(): Provider> {
+ return sources.kotlin?.all
+ ?.map { directories ->
+ directories.map { directory -> directory.asFileTree.matching(Language.filterOf(Language.KOTLIN)) }
+ }?.map { trees -> trees.flatten() }
+ ?: project.provider { emptyList() }
+ }
+
+ override fun getAndroidAssets(): Provider> {
+ return sources.assets?.all
+ ?.map { layers -> layers.flatten() }
+ ?.map { directories -> directories.map { directory -> directory.asFileTree } }
+ ?.map { trees -> trees.flatten() }
+ ?: project.provider { emptyList() }
+ }
+
+ override fun getAndroidRes(): Provider> {
+ return sources.res?.all
+ ?.map { layers -> layers.flatten() }
+ ?.map { directories ->
+ directories.map { directory -> directory.asFileTree.matching(Language.filterOf(Language.XML)) }
+ }
+ ?.map { trees -> trees.flatten() }
+ ?: project.provider { emptyList() }
+ }
+
+ override fun getLayoutFiles(): Provider> {
+ return sources.res?.all
+ ?.map { layers -> layers.flatten() }
+ ?.map { directories -> directories.map { directory -> directory.asFileTree } }
+ ?.map { fileTrees ->
+ fileTrees.map { fileTree ->
+ fileTree.matching {
+ include("**/layout/**/*.xml")
+ }
+ }.flatten()
+ }
+ ?: project.provider { emptyList() }
+ }
+
+ override fun getManifestFiles(): Provider> {
+ return agpVariant.artifacts.get(SingleArtifact.MERGED_MANIFEST).map {
+ listOf(it.asFile)
+ }
+ }
+}
diff --git a/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidVariant.kt b/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidVariant.kt
new file mode 100644
index 000000000..d5579c43d
--- /dev/null
+++ b/src/main/kotlin/com/autonomousapps/internal/analyzer/AndroidVariant.kt
@@ -0,0 +1,39 @@
+// Copyright (c) 2024. Tony Robalik.
+// SPDX-License-Identifier: Apache-2.0
+package com.autonomousapps.internal.analyzer
+
+import com.android.build.api.variant.HasAndroidTest
+import com.android.build.api.variant.Variant
+import org.gradle.api.Project
+import org.gradle.api.provider.Provider
+
+internal interface AndroidVariant {
+ val flavorName: String
+ val variantName: String
+ val buildType: String
+ val testInstrumentationRunner: Provider
+}
+
+internal class DefaultAndroidVariant(
+ override val flavorName: String,
+ override val variantName: String,
+ override val buildType: String,
+ override val testInstrumentationRunner: Provider,
+) : AndroidVariant {
+ constructor(project: Project, variant: Variant) : this(
+ flavorName = variant.flavorName.orEmpty(),
+ variantName = variant.name,
+ buildType = variant.buildType.orEmpty(),
+ testInstrumentationRunner = getTestInstrumentationRunner(project, variant),
+ )
+
+ private companion object {
+ fun getTestInstrumentationRunner(project: Project, variant: Variant): Provider {
+ return if (variant is HasAndroidTest) {
+ variant.androidTest?.instrumentationRunner ?: project.provider { null }
+ } else {
+ project.provider { null }
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/com/autonomousapps/internal/analyzer/DependencyAnalyzer.kt b/src/main/kotlin/com/autonomousapps/internal/analyzer/DependencyAnalyzer.kt
index 2b8716ff7..ab9fc2734 100644
--- a/src/main/kotlin/com/autonomousapps/internal/analyzer/DependencyAnalyzer.kt
+++ b/src/main/kotlin/com/autonomousapps/internal/analyzer/DependencyAnalyzer.kt
@@ -6,20 +6,18 @@ package com.autonomousapps.internal.analyzer
import com.autonomousapps.internal.OutputPaths
import com.autonomousapps.model.declaration.SourceSetKind
-import com.autonomousapps.services.InMemoryCache
import com.autonomousapps.tasks.*
import org.gradle.api.Project
import org.gradle.api.UnknownDomainObjectException
import org.gradle.api.UnknownTaskException
import org.gradle.api.artifacts.Configuration
-import org.gradle.api.file.FileCollection
-import org.gradle.api.file.FileTree
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.kotlin.dsl.get
import org.gradle.kotlin.dsl.named
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+import java.io.File
/** Abstraction for differentiating between android-app, android-lib, and java-lib projects. */
internal interface DependencyAnalyzer {
@@ -53,17 +51,18 @@ internal interface DependencyAnalyzer {
val annotationProcessorConfigurationName: String
/** E.g., "androidx.test.runner.AndroidJUnitRunner" */
- val testInstrumentationRunner: String?
+ val testInstrumentationRunner: Provider
val attributeValueJar: String
- val kotlinSourceFiles: FileCollection
- val javaSourceFiles: FileCollection?
- val groovySourceFiles: FileCollection
- val scalaSourceFiles: FileCollection
+ /** Kotlin projects have no Java source */
+ val javaSourceFiles: Provider>?
+ val kotlinSourceFiles: Provider>
+ val groovySourceFiles: Provider>
+ val scalaSourceFiles: Provider>
- val isDataBindingEnabled: Boolean
- val isViewBindingEnabled: Boolean
+ val isDataBindingEnabled: Provider
+ val isViewBindingEnabled: Provider
val testJavaCompileName: String
val testKotlinCompileName: String
@@ -94,16 +93,16 @@ internal interface DependencyAnalyzer {
fun registerAndroidScoreTask(
synthesizeDependenciesTask: TaskProvider,
- synthesizeProjectViewTask: TaskProvider
+ synthesizeProjectViewTask: TaskProvider,
): TaskProvider? = null
}
internal abstract class AbstractDependencyAnalyzer(
- protected val project: Project
+ protected val project: Project,
) : DependencyAnalyzer {
// Always null for JVM projects. May be null for Android projects.
- override val testInstrumentationRunner: String? = null
+ override val testInstrumentationRunner: Provider = project.provider { null }
protected val testJavaCompile by lazy {
try {
diff --git a/src/main/kotlin/com/autonomousapps/internal/analyzer/JvmProjectAnalyzer.kt b/src/main/kotlin/com/autonomousapps/internal/analyzer/JvmProjectAnalyzer.kt
index 0f706d8d6..ddc4763b5 100644
--- a/src/main/kotlin/com/autonomousapps/internal/analyzer/JvmProjectAnalyzer.kt
+++ b/src/main/kotlin/com/autonomousapps/internal/analyzer/JvmProjectAnalyzer.kt
@@ -18,6 +18,7 @@ import org.gradle.api.provider.Provider
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
import org.gradle.kotlin.dsl.register
+import java.io.File
internal abstract class JvmAnalyzer(
project: Project,
@@ -39,13 +40,13 @@ internal abstract class JvmAnalyzer(
final override val attributeValueJar = "jar"
- final override val kotlinSourceFiles: FileCollection = getKotlinSources()
- override val javaSourceFiles: FileCollection? = getJavaSources()
- final override val groovySourceFiles: FileCollection = getGroovySources()
- final override val scalaSourceFiles: FileCollection = getScalaSources()
+ final override val kotlinSourceFiles: Provider> = getKotlinSources()
+ override val javaSourceFiles: Provider>? = getJavaSources()
+ final override val groovySourceFiles: Provider> = getGroovySources()
+ final override val scalaSourceFiles: Provider> = getScalaSources()
- final override val isDataBindingEnabled: Boolean = false
- final override val isViewBindingEnabled: Boolean = false
+ final override val isDataBindingEnabled: Provider = project.provider { false }
+ final override val isViewBindingEnabled: Provider = project.provider { false }
override val outputPaths = OutputPaths(project, variantName)
@@ -92,10 +93,19 @@ internal abstract class JvmAnalyzer(
}
}
- private fun getGroovySources(): FileCollection = getSourceDirectories().matching(Language.filterOf(Language.GROOVY))
- private fun getJavaSources(): FileCollection = getSourceDirectories().matching(Language.filterOf(Language.JAVA))
- private fun getKotlinSources(): FileCollection = getSourceDirectories().matching(Language.filterOf(Language.KOTLIN))
- private fun getScalaSources(): FileCollection = getSourceDirectories().matching(Language.filterOf(Language.SCALA))
+ private fun getGroovySources(): Provider> {
+ return project.provider { getSourceDirectories().matching(Language.filterOf(Language.GROOVY)) }
+ }
+ private fun getJavaSources(): Provider> {
+ return project.provider { getSourceDirectories().matching(Language.filterOf(Language.JAVA)) }
+ }
+ private fun getKotlinSources(): Provider> {
+ return project.provider { getSourceDirectories().matching(Language.filterOf(Language.KOTLIN)) }
+ }
+
+ private fun getScalaSources(): Provider> {
+ return project.provider { getSourceDirectories().matching(Language.filterOf(Language.SCALA)) }
+ }
private fun getSourceDirectories(): FileTree {
val allSource = sourceSet.sourceCode.sourceDirectories
@@ -134,7 +144,7 @@ internal abstract class KotlinJvmAnalyzer(
sourceSet = KotlinSourceSet(sourceSet, kind),
hasAbi = hasAbi
) {
- final override val javaSourceFiles: FileTree? = null
+ final override val javaSourceFiles = null
}
internal class KotlinJvmAppAnalyzer(
diff --git a/src/main/kotlin/com/autonomousapps/internal/analyzer/JvmSourceSet.kt b/src/main/kotlin/com/autonomousapps/internal/analyzer/JvmSourceSet.kt
index 77f67d1ed..5c05f2727 100644
--- a/src/main/kotlin/com/autonomousapps/internal/analyzer/JvmSourceSet.kt
+++ b/src/main/kotlin/com/autonomousapps/internal/analyzer/JvmSourceSet.kt
@@ -2,9 +2,7 @@
// SPDX-License-Identifier: Apache-2.0
package com.autonomousapps.internal.analyzer
-import com.android.builder.model.SourceProvider
import com.autonomousapps.model.declaration.SourceSetKind
-import com.autonomousapps.model.declaration.Variant
import org.gradle.api.file.FileCollection
import org.gradle.api.file.FileTree
import org.gradle.api.file.SourceDirectorySet
@@ -62,30 +60,17 @@ internal class KotlinSourceSet(
override val classesDirs: FileCollection = sourceSet.output.classesDirs
}
-/** All the relevant Java and Kotlin source sets for a given Android variant. */
-internal class VariantSourceSet(
- val variant: Variant,
- val androidSourceSets: Set = emptySet(),
- /** E.g., `debugCompileClasspath` or `debugUnitTestCompileClasspath` */
- val compileClasspathConfigurationName: String,
- /** E.g., `debugRuntimeClasspath` or `debugUnitTestRuntimeClasspath` */
- val runtimeClasspathConfigurationName: String,
-)
-
internal fun SourceSet.java(): FileTree {
- return java.sourceDirectories.asFileTree.matching {
- include("**/*.java")
- }
+ return java.sourceDirectories.asFileTree.matching(Language.filterOf(Language.JAVA))
}
internal fun JbKotlinSourceSet.kotlin(): FileTree {
- return kotlin.sourceDirectories.asFileTree.matching {
- include("**/*.kt")
- }
+ return kotlin.sourceDirectories.asFileTree.matching(Language.filterOf(Language.KOTLIN))
}
internal fun SourceSet.groovy(): FileTree? {
- return extensions.findByType()?.sourceDirectories?.asFileTree?.matching {
- include("**/*.groovy")
- }
+ return extensions.findByType()
+ ?.sourceDirectories
+ ?.asFileTree
+ ?.matching(Language.filterOf(Language.GROOVY))
}
diff --git a/src/main/kotlin/com/autonomousapps/internal/analyzer/Language.kt b/src/main/kotlin/com/autonomousapps/internal/analyzer/Language.kt
index f8ba29956..92d2f3674 100644
--- a/src/main/kotlin/com/autonomousapps/internal/analyzer/Language.kt
+++ b/src/main/kotlin/com/autonomousapps/internal/analyzer/Language.kt
@@ -10,6 +10,7 @@ internal enum class Language(val pattern: String) {
JAVA("**/*.java"),
KOTLIN("**/*.kt"),
SCALA("**/*.scala"),
+ XML("**/*.xml"),
;
companion object {
diff --git a/src/main/kotlin/com/autonomousapps/internal/android/AgpVersion.kt b/src/main/kotlin/com/autonomousapps/internal/android/AgpVersion.kt
index 9cc9943fa..cd2a7359b 100644
--- a/src/main/kotlin/com/autonomousapps/internal/android/AgpVersion.kt
+++ b/src/main/kotlin/com/autonomousapps/internal/android/AgpVersion.kt
@@ -5,14 +5,17 @@ package com.autonomousapps.internal.android
import com.android.Version
import com.autonomousapps.internal.utils.VersionNumber
+/**
+ * @see AGP artifacts
+ */
internal class AgpVersion private constructor(val version: String) : Comparable {
private val versionNumber = VersionNumber.parse(version)
companion object {
- @JvmStatic val AGP_MIN = version("7.4.2")
- @JvmStatic val AGP_MAX = version("8.2.0-alpha16")
+ @JvmStatic val AGP_MIN = version("8.0.0")
+ @JvmStatic val AGP_MAX = version("8.4.0-alpha01")
@JvmStatic fun current(): AgpVersion = AgpVersion(agpVersion())
@JvmStatic fun version(version: String): AgpVersion = AgpVersion(version)
diff --git a/src/main/kotlin/com/autonomousapps/internal/android/AndroidGradlePlugin.kt b/src/main/kotlin/com/autonomousapps/internal/android/AndroidGradlePlugin.kt
index c25f300fe..72994d14f 100644
--- a/src/main/kotlin/com/autonomousapps/internal/android/AndroidGradlePlugin.kt
+++ b/src/main/kotlin/com/autonomousapps/internal/android/AndroidGradlePlugin.kt
@@ -7,8 +7,8 @@ import org.gradle.api.provider.Provider
internal interface AndroidGradlePlugin {
fun getBundleTaskOutput(variantName: String): Provider
- fun isViewBindingEnabled(): Boolean
- fun isDataBindingEnabled(): Boolean
+ fun isViewBindingEnabled(): Provider
+ fun isDataBindingEnabled(): Provider
/**
* The package name or "namespace" of this Android module.
diff --git a/src/main/kotlin/com/autonomousapps/internal/android/AndroidGradlePlugin4_2.kt b/src/main/kotlin/com/autonomousapps/internal/android/AndroidGradlePlugin4_2.kt
index f7759d75f..f40234d31 100644
--- a/src/main/kotlin/com/autonomousapps/internal/android/AndroidGradlePlugin4_2.kt
+++ b/src/main/kotlin/com/autonomousapps/internal/android/AndroidGradlePlugin4_2.kt
@@ -5,17 +5,14 @@
package com.autonomousapps.internal.android
import com.android.build.api.dsl.CommonExtension
-import com.android.build.gradle.BaseExtension
import org.gradle.api.Project
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Provider
-import org.gradle.kotlin.dsl.the
-import org.gradle.kotlin.dsl.withGroovyBuilder
internal class AndroidGradlePlugin4_2(
project: Project,
- agpVersion: String
+ agpVersion: String,
) : BaseAndroidGradlePlugin(project, agpVersion) {
override val bundleTaskType: String = "com.android.build.gradle.internal.tasks.BundleLibraryClassesJar"
@@ -32,14 +29,12 @@ internal class AndroidGradlePlugin4_2(
}
}
- override fun isViewBindingEnabled(): Boolean = project.the().withGroovyBuilder {
- getProperty("buildFeatures").withGroovyBuilder { getProperty("viewBinding") } as Boolean?
- ?: false
+ override fun isViewBindingEnabled(): Provider {
+ return project.provider { project.extensions.getByType(CommonExtension::class.java).viewBinding.enable }
}
- override fun isDataBindingEnabled(): Boolean = project.the().withGroovyBuilder {
- getProperty("buildFeatures").withGroovyBuilder { getProperty("dataBinding") } as Boolean?
- ?: false
+ override fun isDataBindingEnabled(): Provider {
+ return project.provider { project.extensions.getByType(CommonExtension::class.java).dataBinding.enable }
}
override fun namespace(): Provider {
diff --git a/src/main/kotlin/com/autonomousapps/subplugin/ProjectPlugin.kt b/src/main/kotlin/com/autonomousapps/subplugin/ProjectPlugin.kt
index 982fe5911..bb42d680c 100644
--- a/src/main/kotlin/com/autonomousapps/subplugin/ProjectPlugin.kt
+++ b/src/main/kotlin/com/autonomousapps/subplugin/ProjectPlugin.kt
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: Apache-2.0
package com.autonomousapps.subplugin
+import com.android.build.api.variant.AndroidComponentsExtension
+import com.android.build.api.variant.HasAndroidTest
+import com.android.build.api.variant.Sources
import com.android.build.gradle.AppExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.BaseVariant
@@ -148,56 +151,60 @@ internal class ProjectPlugin(private val project: Project) {
/** Has the `com.android.application` plugin applied. */
private fun Project.configureAndroidAppProject() {
val project = this
- val appExtension = the()
val ignoredVariantNames = androidIgnoredVariants()
- val allowedVariants = appExtension.applicationVariants.matching { variant ->
- !ignoredVariantNames.contains(variant.name)
- }
-
- allowedVariants.all {
- val mainSourceSets = sourceSets
- val unitTestSourceSets = if (shouldAnalyzeTests()) unitTestVariant?.sourceSets else null
- val androidTestSourceSets = if (shouldAnalyzeTests()) testVariant?.sourceSets else null
-
- val agpVersion = AgpVersion.current().version
-
- mainSourceSets.let { sourceSets ->
- val variantSourceSet = newVariantSourceSet(name, SourceSetKind.MAIN, sourceSets)
- val dependencyAnalyzer = AndroidAppAnalyzer(
- project = project,
- variant = this,
- agpVersion = agpVersion,
- variantSourceSet = variantSourceSet
- )
- isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
- isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
- analyzeDependencies(dependencyAnalyzer)
- }
- unitTestSourceSets?.let { sourceSets ->
- val variantSourceSet = newVariantSourceSet(name, SourceSetKind.TEST, sourceSets)
- val dependencyAnalyzer = AndroidAppAnalyzer(
- project = project,
- variant = this,
- agpVersion = agpVersion,
- variantSourceSet = variantSourceSet
- )
- isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
- isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
- analyzeDependencies(dependencyAnalyzer)
- }
+ val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
+ // val newAgpVersion = androidComponents.pluginVersion.toString().removePrefix("Android Gradle Plugin version ")
+ val agpVersion = AgpVersion.current().version
- androidTestSourceSets?.let { sourceSets ->
- val variantSourceSet = newVariantSourceSet(name, SourceSetKind.ANDROID_TEST, sourceSets)
- val dependencyAnalyzer = AndroidAppAnalyzer(
- project = this@configureAndroidAppProject,
- variant = this,
- agpVersion = agpVersion,
- variantSourceSet = variantSourceSet
- )
- isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
- isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
- analyzeDependencies(dependencyAnalyzer)
+ androidComponents.onVariants { variant ->
+ if (variant.name !in ignoredVariantNames) {
+ val mainSourceSets = variant.sources
+ val unitTestSourceSets = if (shouldAnalyzeTests()) variant.unitTest?.sources else null
+ val androidTestSourceSets = if (shouldAnalyzeTests() && variant is HasAndroidTest) {
+ variant.androidTest?.sources
+ } else {
+ null
+ }
+
+ mainSourceSets.let { sourceSets ->
+ val variantSourceSet = newVariantSourceSet(variant.name, SourceSetKind.MAIN, variant, sourceSets)
+ val dependencyAnalyzer = AndroidAppAnalyzer(
+ project = project,
+ variant = DefaultAndroidVariant(project, variant),
+ agpVersion = agpVersion,
+ androidSources = variantSourceSet
+ )
+ isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
+ isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
+ analyzeDependencies(dependencyAnalyzer)
+ }
+
+ unitTestSourceSets?.let { sourceSets ->
+ val variantSourceSet = newVariantSourceSet(variant.name, SourceSetKind.TEST, variant, sourceSets)
+ val dependencyAnalyzer = AndroidAppAnalyzer(
+ project = project,
+ variant = DefaultAndroidVariant(project, variant),
+ agpVersion = agpVersion,
+ androidSources = variantSourceSet
+ )
+ isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
+ isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
+ analyzeDependencies(dependencyAnalyzer)
+ }
+
+ androidTestSourceSets?.let { sourceSets ->
+ val variantSourceSet = newVariantSourceSet(variant.name, SourceSetKind.ANDROID_TEST, variant, sourceSets)
+ val dependencyAnalyzer = AndroidAppAnalyzer(
+ project = this@configureAndroidAppProject,
+ variant = DefaultAndroidVariant(project, variant),
+ agpVersion = agpVersion,
+ androidSources = variantSourceSet
+ )
+ isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
+ isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
+ analyzeDependencies(dependencyAnalyzer)
+ }
}
}
}
@@ -205,55 +212,60 @@ internal class ProjectPlugin(private val project: Project) {
/** Has the `com.android.library` plugin applied. */
private fun Project.configureAndroidLibProject() {
val project = this
- val libraryExtension = the()
val ignoredVariantNames = androidIgnoredVariants()
- val allowedVariants = libraryExtension.libraryVariants.matching { variant ->
- !ignoredVariantNames.contains(variant.name)
- }
- allowedVariants.all {
- val mainSourceSets = sourceSets
- val unitTestSourceSets = if (shouldAnalyzeTests()) unitTestVariant?.sourceSets else null
- val androidTestSourceSets = if (shouldAnalyzeTests()) testVariant?.sourceSets else null
-
- val agpVersion = AgpVersion.current().version
-
- mainSourceSets.let { sourceSets ->
- val variantSourceSet = newVariantSourceSet(name, SourceSetKind.MAIN, sourceSets)
- val dependencyAnalyzer = AndroidLibAnalyzer(
- project = project,
- variant = this,
- agpVersion = agpVersion,
- variantSourceSet = variantSourceSet
- )
- isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
- isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
- analyzeDependencies(dependencyAnalyzer)
- }
- unitTestSourceSets?.let { sourceSets ->
- val variantSourceSet = newVariantSourceSet(name, SourceSetKind.TEST, sourceSets)
- val dependencyAnalyzer = AndroidLibAnalyzer(
- project = project,
- variant = this,
- agpVersion = agpVersion,
- variantSourceSet = variantSourceSet
- )
- isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
- isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
- analyzeDependencies(dependencyAnalyzer)
- }
+ val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
+ // val newAgpVersion = androidComponents.pluginVersion.toString().removePrefix("Android Gradle Plugin version ")
+ val agpVersion = AgpVersion.current().version
- androidTestSourceSets?.let { sourceSets ->
- val variantSourceSet = newVariantSourceSet(name, SourceSetKind.ANDROID_TEST, sourceSets)
- val dependencyAnalyzer = AndroidLibAnalyzer(
- project = project,
- variant = this,
- agpVersion = agpVersion,
- variantSourceSet = variantSourceSet
- )
- isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
- isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
- analyzeDependencies(dependencyAnalyzer)
+ androidComponents.onVariants { variant ->
+ if (variant.name !in ignoredVariantNames) {
+ val mainSourceSets = variant.sources
+ val unitTestSourceSets = if (shouldAnalyzeTests()) variant.unitTest?.sources else null
+ val androidTestSourceSets = if (shouldAnalyzeTests() && variant is HasAndroidTest) {
+ variant.androidTest?.sources
+ } else {
+ null
+ }
+
+ mainSourceSets.let { sourceSets ->
+ val variantSourceSet = newVariantSourceSet(variant.name, SourceSetKind.MAIN, variant, sourceSets)
+ val dependencyAnalyzer = AndroidLibAnalyzer(
+ project = project,
+ variant = DefaultAndroidVariant(project, variant),
+ agpVersion = agpVersion,
+ androidSources = variantSourceSet
+ )
+ isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
+ isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
+ analyzeDependencies(dependencyAnalyzer)
+ }
+
+ unitTestSourceSets?.let { sourceSets ->
+ val variantSourceSet = newVariantSourceSet(variant.name, SourceSetKind.TEST, variant, sourceSets)
+ val dependencyAnalyzer = AndroidLibAnalyzer(
+ project = project,
+ variant = DefaultAndroidVariant(project, variant),
+ agpVersion = agpVersion,
+ androidSources = variantSourceSet
+ )
+ isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
+ isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
+ analyzeDependencies(dependencyAnalyzer)
+ }
+
+ androidTestSourceSets?.let { sourceSets ->
+ val variantSourceSet = newVariantSourceSet(variant.name, SourceSetKind.ANDROID_TEST, variant, sourceSets)
+ val dependencyAnalyzer = AndroidLibAnalyzer(
+ project = project,
+ variant = DefaultAndroidVariant(project, variant),
+ agpVersion = agpVersion,
+ androidSources = variantSourceSet
+ )
+ isDataBindingEnabled.set(dependencyAnalyzer.isDataBindingEnabled)
+ isViewBindingEnabled.set(dependencyAnalyzer.isViewBindingEnabled)
+ analyzeDependencies(dependencyAnalyzer)
+ }
}
}
}
@@ -261,10 +273,13 @@ internal class ProjectPlugin(private val project: Project) {
private fun newVariantSourceSet(
variantName: String,
kind: SourceSetKind,
- androidSourceSets: List,
- ) = VariantSourceSet(
+ variant: com.android.build.api.variant.Variant,
+ sources: Sources,
+ ): AndroidSources = DefaultAndroidSources(
+ project = project,
+ sources = sources,
+ agpVariant = variant,
variant = Variant(variantName, kind),
- androidSourceSets = androidSourceSets.toSortedSet(JAVA_COMPARATOR),
compileClasspathConfigurationName = kind.compileClasspathConfigurationName(variantName),
runtimeClasspathConfigurationName = kind.runtimeClasspathConfigurationName(variantName),
)
@@ -749,7 +764,7 @@ internal class ProjectPlugin(private val project: Project) {
// Optional: only exists for Android libraries.
explodeAssetSourceTask?.let { t -> androidAssetsSource.set(t.flatMap { it.output }) }
// Optional: only exists for Android projects.
- dependencyAnalyzer.testInstrumentationRunner?.let { testInstrumentationRunner.set(it) }
+ testInstrumentationRunner.set(dependencyAnalyzer.testInstrumentationRunner)
output.set(outputPaths.syntheticProjectPath)
}
diff --git a/src/main/kotlin/com/autonomousapps/tasks/XmlSourceExploderTask.kt b/src/main/kotlin/com/autonomousapps/tasks/XmlSourceExploderTask.kt
index 065b04c52..9ffc47585 100644
--- a/src/main/kotlin/com/autonomousapps/tasks/XmlSourceExploderTask.kt
+++ b/src/main/kotlin/com/autonomousapps/tasks/XmlSourceExploderTask.kt
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: Apache-2.0
package com.autonomousapps.tasks
-import com.autonomousapps.TASK_GROUP_DEP_INTERNAL
import com.autonomousapps.internal.parse.AndroidLayoutParser
import com.autonomousapps.internal.parse.AndroidManifestParser
import com.autonomousapps.internal.parse.AndroidResBuilder
@@ -14,13 +13,11 @@ import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RegularFileProperty
-import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
-import java.io.File
import javax.inject.Inject
/**
@@ -46,14 +43,8 @@ import javax.inject.Inject
abstract class XmlSourceExploderTask @Inject constructor(
private val workerExecutor: WorkerExecutor,
private val layout: ProjectLayout,
- private val objects: ObjectFactory
) : DefaultTask() {
- init {
- group = TASK_GROUP_DEP_INTERNAL
- description = "Produces a report of all resources references in this project"
- }
-
@get:PathSensitive(PathSensitivity.RELATIVE)
@get:InputFiles
abstract val androidLocalRes: ConfigurableFileCollection
@@ -74,22 +65,6 @@ abstract class XmlSourceExploderTask @Inject constructor(
@get:OutputFile
abstract val output: RegularFileProperty
- internal fun layouts(files: List) {
- for (file in files) {
- layoutFiles.from(
- objects.fileTree().from(file)
- .matching {
- // At this point in the filtering, there's a mix of directories and files
- // Can't filter on file extension
- include { it.path.contains("layout") }
- }.files
- // At this point, we have only files. It is safe to filter on extension. We
- // only want XML files.
- .filter { it.extension == "xml" }
- )
- }
- }
-
@TaskAction fun action() {
workerExecutor.noIsolation().submit(XmlSourceExploderWorkAction::class.java) {
projectDir.set(layout.projectDirectory)