Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flavors support #30

Merged
merged 2 commits into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion constants.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
// TODO migrate to version catalogs
ext {
groupId = "com.grab.grazel"
versionName = "0.4.0-alpha15"
versionName = "0.4.0-alpha16"

kotlinVersion = "1.6.10"
agpVersion = "7.1.2"
Expand Down
2 changes: 1 addition & 1 deletion grazel-gradle-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ buildscript {

plugins {
id "java-gradle-plugin"
id "org.gradle.kotlin.kotlin-dsl" version "2.1.4"
id "org.gradle.kotlin.kotlin-dsl" version "2.1.6"
id "com.gradle.plugin-publish" version "0.14.0"
id "maven-publish"
id "idea"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,26 @@
package com.grab.grazel.bazel.starlark

import com.grab.grazel.gradle.buildTargetName
import com.grab.grazel.gradle.dependencies.BuildGraphType
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency


sealed class BazelDependency {
data class ProjectDependency(val project: Project) : BazelDependency() {
data class ProjectDependency(
val dependencyProject: Project,
val suffix: String = ""
) : BazelDependency() {

override fun toString(): String {
val relativeProjectPath = project.rootProject.relativePath(project.projectDir)
val relativeProjectPath =
dependencyProject.rootProject.relativePath(dependencyProject.projectDir)
return if (relativeProjectPath.contains("/")) {
val path = relativeProjectPath.split("/").dropLast(1).joinToString("/")
"//" + path + "/" + project.buildTargetName()
"//" + path + "/" + dependencyProject.buildTargetName() + ":" +
dependencyProject.buildTargetName() + suffix
} else {
"//" + project.buildTargetName()
"//" + dependencyProject.buildTargetName() + ":" +
dependencyProject.buildTargetName() + suffix
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import com.grab.grazel.bazel.rules.Visibility
import com.grab.grazel.bazel.rules.rule
import java.io.PrintWriter

class FunctionStatement(
data class FunctionStatement(
val name: String,
private val params: List<AssignStatement>,
private val multilineParams: Boolean = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.TestVariant
import com.android.build.gradle.api.UnitTestVariant
import com.android.builder.model.BuildType
import com.android.builder.model.ProductFlavor
import com.grab.grazel.extension.DefaultVariantFilter
import com.grab.grazel.extension.VariantFilter
Expand Down Expand Up @@ -51,13 +52,38 @@ internal interface AndroidVariantDataSource {
* @return The list of variants that can be migrated.
*/
fun getMigratableVariants(project: Project): List<BaseVariant>

/**
* return all variants minus the ones that declared in filtered variants
*/
fun getMigratableVariants(
project: Project,
configurationScope: ConfigurationScope?
): Set<BaseVariant>
}

internal class DefaultAndroidVariantDataSource(
private val androidVariantsExtractor: AndroidVariantsExtractor = DefaultAndroidVariantsExtractor(),
override val variantFilter: Action<VariantFilter>? = null
) : AndroidVariantDataSource {

override fun getMigratableVariants(
project: Project,
configurationScope: ConfigurationScope?
): Set<BaseVariant> {
return when (configurationScope) {
ConfigurationScope.TEST -> {
androidVariantsExtractor.getUnitTestVariants(project)
}
ConfigurationScope.ANDROID_TEST -> {
androidVariantsExtractor.getTestVariants(project)
}
else -> {
androidVariantsExtractor.getVariants(project)
}
}.filterNot(::ignoredVariantFilter).toSet()
}

override fun getIgnoredFlavors(project: Project): List<ProductFlavor> {
val supportFlavors = getMigratableVariants(project).flatMap(BaseVariant::getProductFlavors)
return androidVariantsExtractor.getFlavors(project)
Expand Down Expand Up @@ -88,6 +114,7 @@ internal interface AndroidVariantsExtractor {
fun getTestVariants(project: Project): Set<BaseVariant>
fun getVariants(project: Project): Set<BaseVariant>
fun getFlavors(project: Project): Set<ProductFlavor>
fun getBuildTypes(project: Project): Set<BuildType>
}


Expand Down Expand Up @@ -127,6 +154,14 @@ internal class DefaultAndroidVariantsExtractor @Inject constructor() : AndroidVa
else -> emptySet()
}
}

override fun getBuildTypes(project: Project): Set<BuildType> {
return when {
project.isAndroidAppOrDynFeature -> project.the<AppExtension>().buildTypes
project.isAndroidLibrary -> project.the<LibraryExtension>().buildTypes
else -> emptySet()
}
}
}

internal fun AndroidVariantDataSource.getMigratableBuildVariants(project: Project): List<BaseVariant> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,16 @@

package com.grab.grazel.gradle

import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.internal.variant.BaseVariantFactory
import com.grab.grazel.GrazelExtension
import com.grab.grazel.gradle.dependencies.BuildGraphType
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import javax.inject.Inject
import javax.inject.Singleton

internal enum class ConfigurationScope {
enum class ConfigurationScope {
BUILD, TEST, ANDROID_TEST;
}

Expand All @@ -41,14 +44,22 @@ internal interface ConfigurationDataSource {
*/
fun resolvedConfigurations(
project: Project,
vararg scopes: ConfigurationScope
vararg buildGraphTypes: BuildGraphType
): Sequence<Configuration>

/**
* Return a sequence of the configurations filtered out by the ignore flavors, build variants and the configuration scopes
* If the scopes is empty, the build scope will be used by default.
*/
fun configurations(project: Project, vararg scopes: ConfigurationScope): Sequence<Configuration>
fun configurations(
project: Project,
vararg scope: ConfigurationScope
): Sequence<Configuration>

fun isThisConfigurationBelongsToThisVariants(
vararg variants: BaseVariant?,
configuration: Configuration
): Boolean
}

@Singleton
Expand All @@ -69,14 +80,14 @@ internal class DefaultConfigurationDataSource @Inject constructor(
.filter { !it.name.contains("_internal_aapt2_binary") }
.filter { !it.name.contains("archives") }
.filter { !it.isDynamicConfiguration() } // Remove when Grazel support dynamic-feature plugin
.filter {
.filter { configuration ->
when {
scopes.isEmpty() -> it.isNotTest() // If the scopes is empty, the build scope will be used by default.
scopes.isEmpty() -> configuration.isNotTest() // If the scopes is empty, the build scope will be used by default.
else -> scopes.any { scope ->
when (scope) {
ConfigurationScope.TEST -> !it.isAndroidTest() && it.isUnitTest()
ConfigurationScope.ANDROID_TEST -> !it.isUnitTest()
ConfigurationScope.BUILD -> it.isNotTest()
ConfigurationScope.TEST -> !configuration.isAndroidTest() && configuration.isUnitTest()
ConfigurationScope.ANDROID_TEST -> !configuration.isUnitTest()
ConfigurationScope.BUILD -> configuration.isNotTest()
}
}
}
Expand All @@ -90,11 +101,24 @@ internal class DefaultConfigurationDataSource @Inject constructor(
}
}

override fun isThisConfigurationBelongsToThisVariants(
vararg variants: BaseVariant?,
configuration: Configuration
) = variants.any { variant ->
variant == null ||
variant.compileConfiguration.hierarchy.contains(configuration) ||
variant.runtimeConfiguration.hierarchy.contains(configuration) ||
variant.annotationProcessorConfiguration.hierarchy.contains(configuration)
}

override fun resolvedConfigurations(
project: Project,
vararg scopes: ConfigurationScope
vararg buildGraphTypes: BuildGraphType
): Sequence<Configuration> {
return configurations(project, *scopes).filter { it.isCanBeResolved }
return configurations(
project,
*buildGraphTypes.map { it.configurationScope }.toTypedArray()
).filter { it.isCanBeResolved }
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2022 Grabtaxi Holdings PTE LTD (GRAB)
*
* 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.grab.grazel.gradle.dependencies

import com.android.build.gradle.api.BaseVariant
import com.grab.grazel.gradle.ConfigurationScope

data class BuildGraphType(
val configurationScope: ConfigurationScope,
val variant: BaseVariant? = null
)

private val HUMPS = "(?<=.)(?=\\p{Upper})".toRegex()
fun String.variantNameSuffix() = "-${replace(HUMPS, "-").toLowerCase()}"
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import com.grab.grazel.GrazelExtension
import com.grab.grazel.bazel.rules.MavenInstallArtifact
import com.grab.grazel.bazel.rules.MavenInstallArtifact.Exclusion.SimpleExclusion
import com.grab.grazel.di.qualifiers.RootProject
import com.grab.grazel.gradle.AndroidVariantsExtractor
import com.grab.grazel.gradle.ConfigurationDataSource
import com.grab.grazel.gradle.ConfigurationScope
import com.grab.grazel.gradle.RepositoryDataSource
Expand Down Expand Up @@ -83,7 +84,10 @@ internal interface DependenciesDataSource {
/**
* Return the project's maven dependencies before the resolution strategy and any other custom substitution by Gradle
*/
fun mavenDependencies(project: Project, vararg scopes: ConfigurationScope): Sequence<Dependency>
fun mavenDependencies(
project: Project,
vararg buildGraphTypes: BuildGraphType
): Sequence<Dependency>

/**
* Return the project's project (module) dependencies before the resolution strategy and any other custom
Expand Down Expand Up @@ -142,7 +146,8 @@ internal class DefaultDependenciesDataSource @Inject constructor(
private val configurationDataSource: ConfigurationDataSource,
private val artifactsConfig: ArtifactsConfig,
private val repositoryDataSource: RepositoryDataSource,
private val dependencyResolutionService: GradleProvider<DefaultDependencyResolutionService>
private val dependencyResolutionService: GradleProvider<DefaultDependencyResolutionService>,
private val androidVariantsExtractor: AndroidVariantsExtractor
) : DependenciesDataSource {

private val configurationScopes by lazy { grazelExtension.configurationScopes() }
Expand Down Expand Up @@ -174,10 +179,12 @@ internal class DefaultDependenciesDataSource @Inject constructor(
.toMap()
}

private fun Project.resolvableConfigurations(): Sequence<Configuration> {
return configurationDataSource
.resolvedConfigurations(this, *configurationScopes)
}
private fun Project.buildGraphTypes() =
configurationScopes.flatMap { configurationScope ->
androidVariantsExtractor.getVariants(this).map { variant ->
BuildGraphType(configurationScope, variant)
}
}

/**
* Given a group, name and version will update version with following properties
Expand Down Expand Up @@ -228,7 +235,12 @@ internal class DefaultDependenciesDataSource @Inject constructor(
// Filter out configurations we are interested in.
val configurations = projects
.asSequence()
.flatMap { configurationDataSource.configurations(it, *configurationScopes) }
.flatMap { project ->
configurationDataSource.configurations(
project,
*configurationScopes
)
}
.toList()

// Calculate all the external artifacts
Expand All @@ -243,7 +255,12 @@ internal class DefaultDependenciesDataSource @Inject constructor(
// (Perf fix) - collecting all projects' forced modules is costly, hence take the first sub project
// TODO Provide option to consider all forced versions backed by a flag.
val forcedVersions = sequenceOf(rootProject.subprojects.first())
.flatMap { configurationDataSource.configurations(it, *configurationScopes) }
.flatMap { project ->
configurationDataSource.configurations(
project,
*configurationScopes
)
}
.let(::collectForcedVersions)

return (DEFAULT_MAVEN_ARTIFACTS + externalArtifacts + forcedVersions)
Expand Down Expand Up @@ -290,14 +307,25 @@ internal class DefaultDependenciesDataSource @Inject constructor(

override fun mavenDependencies(
project: Project,
vararg scopes: ConfigurationScope
): Sequence<Dependency> = declaredDependencies(project, *scopes)
.map { it.second }
.filter { it.group != null && !DEP_GROUP_EMBEDDED_BY_RULES.contains(it.group) }
.filter {
val artifact = MavenArtifact(it.group, it.name)
!artifact.isExcluded && !artifact.isIgnored
}.filter { it !is ProjectDependency }
vararg buildGraphTypes: BuildGraphType
): Sequence<Dependency> =
declaredDependencies(project, *buildGraphTypes.map { it.configurationScope }.toTypedArray())
.filter { (configuration, _) ->
if (buildGraphTypes.isEmpty()) {
true
} else {
configurationDataSource.isThisConfigurationBelongsToThisVariants(
*buildGraphTypes.map { it.variant }.toTypedArray(),
configuration = configuration
)
}
}
.map { it.second }
.filter { it.group != null && !DEP_GROUP_EMBEDDED_BY_RULES.contains(it.group) }
.filter {
val artifact = MavenArtifact(it.group, it.name)
!artifact.isExcluded && !artifact.isIgnored
}.filter { it !is ProjectDependency }

override fun projectDependencies(
project: Project, vararg scopes: ConfigurationScope
Expand Down Expand Up @@ -343,7 +371,10 @@ internal class DefaultDependenciesDataSource @Inject constructor(
private fun Project.externalResolvedDependencies() = dependencyResolutionService.get()
.resolve(
project = this,
configurations = resolvableConfigurations()
configurations = configurationDataSource.resolvedConfigurations(
this,
*buildGraphTypes().toTypedArray()
)
)

/**
Expand All @@ -362,7 +393,10 @@ internal class DefaultDependenciesDataSource @Inject constructor(
* @return Sequence of [DefaultResolvedDependency] in the first level
*/
private fun Project.firstLevelModuleDependencies(): Sequence<DefaultResolvedDependency> {
return resolvableConfigurations()
return configurationDataSource.resolvedConfigurations(
this,
*buildGraphTypes().toTypedArray()
)
.map { it.resolvedConfiguration.lenientConfiguration }
.flatMap {
try {
Expand Down
Loading