Gradle: Respect 'implement' when collecting transitive dependencies of

IDEA module

This covers the cases when module is transitively reachable via
sequence of "compile"/"implement" dependencies
with at least one "implement" present (cases when module is transitively
reachable via "compile" only are handled automatically)

 #KT-16926 Fixed
This commit is contained in:
Alexey Sedunov
2017-10-03 19:43:13 +03:00
parent 69e5f11889
commit 3df43ccc6a
2 changed files with 92 additions and 15 deletions
@@ -183,4 +183,71 @@ class MultiplatformProjectImportingTest : GradleImportingTestCase() {
assertModuleModuleDepScope("js-app_main", "common-lib_main", DependencyScope.COMPILE)
assertModuleModuleDepScope("js-app_main", "js-lib_main", DependencyScope.COMPILE)
}
@Test
fun testDependenciesReachableViaImpl() {
createProjectSubFile(
"settings.gradle",
"include ':common-lib1', ':common-lib2', ':jvm-lib1', ':jvm-lib2', ':jvm-app'"
)
val kotlinVersion = "1.1.0"
createProjectSubFile("build.gradle", """
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
}
}
project('common-lib1') {
apply plugin: 'kotlin-platform-common'
}
project('common-lib2') {
apply plugin: 'kotlin-platform-common'
}
project('jvm-lib1') {
apply plugin: 'kotlin-platform-jvm'
dependencies {
implement project(':common-lib1')
}
}
project('jvm-lib2') {
apply plugin: 'kotlin-platform-jvm'
dependencies {
implement project(':common-lib2')
compile project(':jvm-lib1')
}
}
project('jvm-app') {
apply plugin: 'kotlin-platform-jvm'
dependencies {
compile project(':jvm-lib2')
}
}
""")
importProject()
assertModuleModuleDepScope("jvm-app_main", "jvm-lib2_main", DependencyScope.COMPILE)
assertModuleModuleDepScope("jvm-app_main", "jvm-lib1_main", DependencyScope.COMPILE)
assertModuleModuleDepScope("jvm-app_main", "common-lib1_main", DependencyScope.COMPILE)
assertModuleModuleDepScope("jvm-app_main", "common-lib2_main", DependencyScope.COMPILE)
assertModuleModuleDepScope("jvm-app_test", "jvm-lib2_main", DependencyScope.COMPILE)
assertModuleModuleDepScope("jvm-app_test", "jvm-lib1_main", DependencyScope.COMPILE)
assertModuleModuleDepScope("jvm-app_test", "common-lib1_test", DependencyScope.COMPILE)
assertModuleModuleDepScope("jvm-app_test", "common-lib2_test", DependencyScope.COMPILE)
}
}
@@ -96,34 +96,44 @@ class KotlinGradleModelBuilder : AbstractKotlinGradleModelBuilder() {
return implementsProjectDependency?.dependencyProject
}
private val Project.isCommon get() = plugins.hasPlugin(kotlinPlatformCommonPluginId)
private fun transitiveCommonDependencies(startingProject: Project): Set<String> {
val toProcess = LinkedList<Project>()
toProcess.add(startingProject)
val toProcess = LinkedList<Pair<Project, Boolean>>()
toProcess.add(startingProject to false)
val processed = HashSet<String>()
val result = HashSet<String>()
result.add(startingProject.pathOrName())
while (toProcess.isNotEmpty()) {
val project = toProcess.pollFirst()
processed.add(project.path)
fun enqueueDependencies(project: Project, isReachableViaImpl: Boolean, collectImpls: Boolean) {
val isCommonProject = project.isCommon
if (isCommonProject && collectImpls) return
if (!project.plugins.hasPlugin(kotlinPlatformCommonPluginId)) continue
result.add(project.pathOrName())
val compileConfiguration = project.configurations.findByName("compile") ?: continue
val configName = if (collectImpls) "implement" else "compile"
val compileConfiguration = project.configurations.findByName(configName) ?: return
val dependencies = compileConfiguration
.dependencies
.filterIsInstance<ProjectDependency>()
.map { it.dependencyProject }
for (dep in dependencies) {
if (dep.path !in processed) {
toProcess.add(dep)
}
if (dep.path in processed) continue
if (!dep.isCommon && (collectImpls || isCommonProject)) continue
toProcess.add(dep to (isReachableViaImpl || collectImpls))
}
}
while (toProcess.isNotEmpty()) {
val (project, isReachableViaImpl) = toProcess.pollFirst()
processed.add(project.path)
if (isReachableViaImpl) {
result.add(project.pathOrName())
}
enqueueDependencies(project, isReachableViaImpl, false)
enqueueDependencies(project, isReachableViaImpl, true)
}
return result
}
@@ -196,7 +206,7 @@ class KotlinGradleModelBuilder : AbstractKotlinGradleModelBuilder() {
val platform = platformPluginId ?: pluginToPlatform.entries.singleOrNull { project.plugins.findPlugin(it.key) != null }?.value
val implementedProject = getImplements(project)
val transitiveCommon = implementedProject?.let { transitiveCommonDependencies(it) } ?: emptySet()
val transitiveCommon = transitiveCommonDependencies(project)
return KotlinGradleModelImpl(
kotlinPluginId != null || platformPluginId != null,