Skip to content

Commit

Permalink
Flavors support (#30)
Browse files Browse the repository at this point in the history
* add flavors support

* fix variant filter

Co-authored-by: mohammad.khaleghi <mohammad.khaleghi@grabtaxi.com>
  • Loading branch information
mohamadk and mohammadkahelghi-grabtaxi committed Sep 15, 2022
1 parent d87731c commit 5157008
Show file tree
Hide file tree
Showing 63 changed files with 914 additions and 401 deletions.
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

0 comments on commit 5157008

Please sign in to comment.