Skip to content

Commit

Permalink
Propagate 'implement' dependencies from Gradle to IDEA project model
Browse files Browse the repository at this point in the history
  • Loading branch information
yole authored and AlexeyTsvetkov committed Dec 22, 2016
1 parent 9b4b796 commit 514fc02
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .idea/artifacts/KotlinPlugin.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions idea/idea.iml
Expand Up @@ -58,5 +58,6 @@
<orderEntry type="module" module-name="noarg-ide" scope="TEST" />
<orderEntry type="module" module-name="sam-with-receiver-ide" scope="TEST" />
<orderEntry type="module" module-name="descriptors" />
<orderEntry type="module" module-name="kotlin-gradle-tooling" />
</component>
</module>
13 changes: 13 additions & 0 deletions idea/kotlin-gradle-tooling/kotlin-gradle-tooling.iml
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="gradle-and-groovy-plugin" level="project" />
<orderEntry type="library" name="kotlin-runtime" level="project" />
</component>
</module>
49 changes: 49 additions & 0 deletions idea/kotlin-gradle-tooling/src/KotlinGradleModelBuilder.kt
@@ -0,0 +1,49 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.gradle

import org.gradle.api.Project
import org.gradle.api.artifacts.ProjectDependency
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
import java.io.Serializable
import java.lang.Exception

interface KotlinGradleModel : Serializable {
val implements: String?
}

class KotlinGradleModelImpl(override val implements: String?) : KotlinGradleModel

class KotlinGradleModelBuilder : ModelBuilderService {
override fun getErrorMessageBuilder(project: Project, e: Exception): ErrorMessageBuilder {
return ErrorMessageBuilder.create(project, e, "Gradle import errors").withDescription("Unable to build Kotlin project configuration")
}

override fun canBuild(modelName: String?): Boolean = modelName == KotlinGradleModel::class.java.name

override fun buildAll(modelName: String?, project: Project): Any {
val implementsConfiguration = project.configurations.findByName("implement")
if (implementsConfiguration != null) {
val implementsProjectDependency = implementsConfiguration.dependencies.filterIsInstance<ProjectDependency>().firstOrNull()
if (implementsProjectDependency != null) {
return KotlinGradleModelImpl(implementsProjectDependency.dependencyProject.path)
}
}
return KotlinGradleModelImpl(null)
}
}
@@ -0,0 +1 @@
org.jetbrains.kotlin.gradle.KotlinGradleModelBuilder
1 change: 1 addition & 0 deletions idea/src/META-INF/gradle.xml
Expand Up @@ -2,6 +2,7 @@
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<frameworkSupport implementation="org.jetbrains.kotlin.idea.configuration.GradleKotlinJavaFrameworkSupportProvider"/>
<pluginDescriptions implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradlePluginDescription"/>
<projectResolve implementation="org.jetbrains.kotlin.idea.configuration.KotlinGradleProjectResolverExtension"/>
</extensions>

<extensionPoints>
Expand Down
@@ -0,0 +1,89 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* 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 org.jetbrains.kotlin.idea.configuration

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.ModuleDependencyData
import com.intellij.openapi.externalSystem.model.project.ProjectData
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.roots.DependencyScope
import org.gradle.tooling.model.idea.IdeaModule
import org.jetbrains.kotlin.gradle.KotlinGradleModel
import org.jetbrains.kotlin.gradle.KotlinGradleModelBuilder
import org.jetbrains.plugins.gradle.model.ExternalProject
import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension
import org.jetbrains.plugins.gradle.service.project.GradleProjectResolverUtil.getModuleId

class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() {
override fun getToolingExtensionsClasses(): Set<Class<out Any>> {
return setOf(KotlinGradleModelBuilder::class.java, Unit::class.java)
}

override fun getExtraProjectModelClasses(): Set<Class<out Any>> {
return setOf(KotlinGradleModel::class.java)
}

override fun populateModuleDependencies(gradleModule: IdeaModule,
ideModule: DataNode<ModuleData>,
ideProject: DataNode<ProjectData>) {
val gradleModel = resolverCtx.getExtraProject(gradleModule, KotlinGradleModel::class.java) ?: return
gradleModel.implements?.let { implementsModuleId ->
val targetModule = findModule(ideProject, implementsModuleId) ?: return
if (resolverCtx.isResolveModulePerSourceSet) {
populateSourceSetDependencies(gradleModule, ideModule, targetModule)
}
else {
addDependency(ideModule, targetModule)
}
}

super.populateModuleDependencies(gradleModule, ideModule, ideProject)
}

private fun addDependency(ideModule: DataNode<out ModuleData>, targetModule: DataNode<out ModuleData>) {
val moduleDependencyData = ModuleDependencyData(ideModule.data, targetModule.data)
moduleDependencyData.scope = DependencyScope.COMPILE
moduleDependencyData.isExported = false
ideModule.createChild(ProjectKeys.MODULE_DEPENDENCY, moduleDependencyData)
}

private fun findModule(ideProject: DataNode<ProjectData>, moduleId: String): DataNode<ModuleData>? {
return ideProject.children.find { (it.data as? ModuleData)?.id == moduleId } as DataNode<ModuleData>?
}

private fun populateSourceSetDependencies(gradleModule: IdeaModule,
fromModule: DataNode<ModuleData>,
targetModule: DataNode<ModuleData>) {
val fromSourceSets = ExternalSystemApiUtil.findAll(fromModule, GradleSourceSetData.KEY)
.associateBy { it.data.id }
val targetSourceSets = ExternalSystemApiUtil.findAll(targetModule, GradleSourceSetData.KEY)
.associateBy { it.data.id.substringAfterLast(':') }

val externalProject = resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java) ?: return
for (sourceSet in externalProject.sourceSets.values) {
if (sourceSet == null || sourceSet.sources.isEmpty()) continue

val moduleId = getModuleId(externalProject, sourceSet)
val fromModuleDataNode = (if (fromSourceSets.isEmpty()) fromModule else fromSourceSets[moduleId]) ?: continue
val targetModuleDataNode = (if (targetSourceSets.isEmpty()) targetModule else targetSourceSets[sourceSet.name]) ?: continue
addDependency(fromModuleDataNode, targetModuleDataNode)
}
}
}

0 comments on commit 514fc02

Please sign in to comment.