Correctly propagate dependencies in multiplatform projects with Android
This commit is contained in:
@@ -14,7 +14,7 @@ dependencies {
|
||||
|
||||
compile(ideaSdkDeps("openapi", "idea"))
|
||||
compile(ideaPluginDeps("gradle-tooling-api", plugin = "gradle"))
|
||||
compile(ideaPluginDeps("android", "android-common", "sdklib", "sdk-common", "layoutlib-api", plugin = "android"))
|
||||
compile(ideaPluginDeps("android", "android-common", "sdklib", "sdk-common", "sdk-tools", "layoutlib-api", plugin = "android"))
|
||||
compile(preloadedDeps("dx", subdir = "android-5.0/lib"))
|
||||
|
||||
testCompile(projectDist(":kotlin-test:kotlin-test-jvm"))
|
||||
|
||||
+25
-1
@@ -34,8 +34,12 @@ package org.jetbrains.kotlin.android.configure
|
||||
|
||||
import com.android.tools.idea.gradle.project.sync.idea.data.service.AndroidProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import org.gradle.tooling.model.idea.IdeaProject
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.KotlinGradleModelFacade
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.findModulesByNames
|
||||
|
||||
class AndroidGradleModelFacade : KotlinGradleModelFacade {
|
||||
override fun getResolvedKotlinStdlibVersionByModuleData(moduleData: DataNode<*>, libraryIds: List<String>): String? {
|
||||
@@ -51,4 +55,24 @@ class AndroidGradleModelFacade : KotlinGradleModelFacade {
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDependencyModules(ideModule: DataNode<ModuleData>, gradleIdeaProject: IdeaProject): Collection<DataNode<ModuleData>> {
|
||||
val ideProject = ideModule.parent as DataNode<ProjectData>
|
||||
ExternalSystemApiUtil.find(ideModule, AndroidProjectKeys.JAVA_MODULE_MODEL)?.let { javaModuleModel ->
|
||||
val moduleNames = javaModuleModel.data.javaModuleDependencies.map { it.moduleName }
|
||||
return findModulesByNames(moduleNames, gradleIdeaProject, ideProject)
|
||||
}
|
||||
ExternalSystemApiUtil.find(ideModule, AndroidProjectKeys.ANDROID_MODEL)?.let { androidModel ->
|
||||
val libraries = androidModel.data.mainArtifact.dependencies.javaLibraries
|
||||
val projects = androidModel.data.mainArtifact.dependencies.projects
|
||||
val projectIds = libraries.mapNotNull { it.project } + projects
|
||||
return projectIds.mapNotNullTo(LinkedHashSet()) { projectId ->
|
||||
ExternalSystemApiUtil.findFirstRecursively(ideProject) {
|
||||
(it.data as? ModuleData)?.id == projectId
|
||||
} as DataNode<ModuleData>?
|
||||
}
|
||||
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
+3
-13
@@ -26,10 +26,10 @@ import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.util.Key
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import org.gradle.tooling.model.idea.IdeaModule
|
||||
import org.gradle.tooling.model.idea.IdeaModuleDependency
|
||||
import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet
|
||||
import org.jetbrains.kotlin.gradle.KotlinGradleModel
|
||||
import org.jetbrains.kotlin.gradle.KotlinGradleModelBuilder
|
||||
import org.jetbrains.kotlin.idea.inspections.gradle.getDependencyModules
|
||||
import org.jetbrains.kotlin.psi.NotNullableUserDataProperty
|
||||
import org.jetbrains.kotlin.psi.UserDataProperty
|
||||
import org.jetbrains.plugins.gradle.model.ExternalProjectDependency
|
||||
@@ -81,10 +81,7 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension()
|
||||
|
||||
val gradleIdeaProject = gradleModule.project
|
||||
|
||||
fun DataNode<out ModuleData>.getGradleModule() =
|
||||
if (this != ideModule) gradleIdeaProject.modules.firstOrNull { it.gradleProject.path == data.id } else gradleModule
|
||||
|
||||
fun DataNode<out ModuleData>.getDependencies(): Set<DataNode<out ModuleData>> {
|
||||
fun DataNode<out ModuleData>.getDependencies(): Collection<DataNode<out ModuleData>> {
|
||||
if (useModulePerSourceSet()) {
|
||||
if (sourceSetByName == null) return emptySet()
|
||||
val externalSourceSet = sourceSetByName[data.id]?.second ?: return emptySet()
|
||||
@@ -110,14 +107,7 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension()
|
||||
}
|
||||
}
|
||||
|
||||
val dependencies = getGradleModule()?.dependencies
|
||||
return dependencies?.mapNotNullTo(LinkedHashSet()) {
|
||||
val targetModuleName = (it as? IdeaModuleDependency)?.targetModuleName ?: return@mapNotNullTo null
|
||||
val targetGradleModule = gradleIdeaProject.modules.firstOrNull { it.name == targetModuleName } ?: return@mapNotNullTo null
|
||||
ExternalSystemApiUtil.findFirstRecursively(ideProject) {
|
||||
(it.data as? ModuleData)?.id == targetGradleModule.gradleProject.path
|
||||
} as DataNode<ModuleData>?
|
||||
} ?: emptySet()
|
||||
return getDependencyModules(ideModule, gradleIdeaProject)
|
||||
}
|
||||
|
||||
fun addTransitiveDependenciesOnImplementedModules() {
|
||||
|
||||
+33
-1
@@ -17,9 +17,14 @@
|
||||
package org.jetbrains.kotlin.idea.inspections.gradle
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.externalSystem.model.DataNode
|
||||
import com.intellij.openapi.externalSystem.model.ProjectKeys
|
||||
import com.intellij.openapi.externalSystem.model.project.ModuleData
|
||||
import com.intellij.openapi.externalSystem.model.project.ProjectData
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import org.gradle.tooling.model.idea.IdeaModuleDependency
|
||||
import org.gradle.tooling.model.idea.IdeaProject
|
||||
|
||||
interface KotlinGradleModelFacade {
|
||||
companion object {
|
||||
@@ -27,6 +32,7 @@ interface KotlinGradleModelFacade {
|
||||
}
|
||||
|
||||
fun getResolvedKotlinStdlibVersionByModuleData(moduleData: DataNode<*>, libraryIds: List<String>): String?
|
||||
fun getDependencyModules(ideModule: DataNode<ModuleData>, gradleIdeaProject: IdeaProject): Collection<DataNode<ModuleData>>
|
||||
}
|
||||
|
||||
class DefaultGradleModelFacade : KotlinGradleModelFacade {
|
||||
@@ -41,4 +47,30 @@ class DefaultGradleModelFacade : KotlinGradleModelFacade {
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getDependencyModules(ideModule: DataNode<ModuleData>, gradleIdeaProject: IdeaProject): Collection<DataNode<ModuleData>> {
|
||||
val ideProject = ideModule.parent as DataNode<ProjectData>
|
||||
val gradleModule = gradleIdeaProject.modules.firstOrNull { it.gradleProject.path == ideModule.data.id }
|
||||
val dependencyModuleNames = gradleModule?.dependencies?.mapNotNull { (it as? IdeaModuleDependency)?.targetModuleName } ?: return emptyList()
|
||||
return findModulesByNames(dependencyModuleNames, gradleIdeaProject, ideProject)
|
||||
}
|
||||
}
|
||||
|
||||
fun getDependencyModules(moduleData: DataNode<ModuleData>, gradleIdeaProject: IdeaProject): Collection<DataNode<ModuleData>> {
|
||||
for (modelFacade in Extensions.getExtensions(KotlinGradleModelFacade.EP_NAME)) {
|
||||
val dependencies = modelFacade.getDependencyModules(moduleData, gradleIdeaProject)
|
||||
if (dependencies.isNotEmpty()) {
|
||||
return dependencies
|
||||
}
|
||||
}
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
fun findModulesByNames(dependencyModuleNames: List<String>, gradleIdeaProject: IdeaProject, ideProject: DataNode<ProjectData>): LinkedHashSet<DataNode<ModuleData>> {
|
||||
return dependencyModuleNames.mapNotNullTo(LinkedHashSet()) { targetModuleName ->
|
||||
val targetGradleModule = gradleIdeaProject.modules.firstOrNull { it.name == targetModuleName } ?: return@mapNotNullTo null
|
||||
ExternalSystemApiUtil.findFirstRecursively(ideProject) {
|
||||
(it.data as? ModuleData)?.id == targetGradleModule.gradleProject.path
|
||||
} as DataNode<ModuleData>?
|
||||
}
|
||||
}
|
||||
|
||||
+92
@@ -17,8 +17,10 @@
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import org.jetbrains.kotlin.idea.codeInsight.gradle.GradleImportingTestCase
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
class MultiplatformProjectImportingTest : GradleImportingTestCase() {
|
||||
@Test
|
||||
@@ -385,4 +387,94 @@ class MultiplatformProjectImportingTest : GradleImportingTestCase() {
|
||||
assertModuleModuleDepScope("project3_custom", "project1_custom", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("project3_custom", "project2_main", DependencyScope.COMPILE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTransitiveImplementWithAndroid() {
|
||||
createProjectSubFile(
|
||||
"settings.gradle",
|
||||
"include ':project1', ':project2', ':project3'"
|
||||
)
|
||||
|
||||
val kotlinVersion = "1.1.51"
|
||||
|
||||
createProjectSubFile("build.gradle", """
|
||||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven { url 'https://maven.google.com' }
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion")
|
||||
classpath 'com.android.tools.build:gradle:2.3.3'
|
||||
}
|
||||
}
|
||||
|
||||
project('project1') {
|
||||
apply plugin: 'kotlin-platform-common'
|
||||
|
||||
sourceSets {
|
||||
custom
|
||||
}
|
||||
}
|
||||
|
||||
project('project2') {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin-platform-jvm'
|
||||
|
||||
sourceSets {
|
||||
custom
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implement project(':project1')
|
||||
}
|
||||
}
|
||||
|
||||
project('project3') {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
sourceSets {
|
||||
custom
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.1"
|
||||
defaultConfig {
|
||||
applicationId "org.jetbrains.kotlin"
|
||||
minSdkVersion 18
|
||||
targetSdkVersion 26
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile project(':project2')
|
||||
customCompile project(':project2')
|
||||
testCompile(project(':project2').sourceSets.test.output)
|
||||
}
|
||||
}
|
||||
""")
|
||||
createProjectSubFile("local.properties", """
|
||||
sdk.dir=/${StringUtil.escapeBackSlashes(File(homePath).parent + "/dependencies/androidSDK")}
|
||||
""")
|
||||
|
||||
|
||||
importProject()
|
||||
|
||||
assertModuleModuleDepScope("project3", "project2", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("project3", "project1", DependencyScope.COMPILE)
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user