Fix the way how script SDK is found in IDE

This commit is contained in:
Natalia Selezneva
2018-03-29 10:48:00 +03:00
parent 8d9f539c79
commit 429e0afe2a
4 changed files with 146 additions and 12 deletions
@@ -369,7 +369,7 @@ private class LibrarySourceScope(project: Project, private val library: Library)
}
//TODO: (module refactoring) android sdk has modified scope
private class SdkScope(project: Project, private val sdk: Sdk) :
private class SdkScope(project: Project, val sdk: Sdk) :
LibraryScopeBase(project, sdk.rootProvider.getFiles(OrderRootType.CLASSES), arrayOf<VirtualFile>()) {
override fun equals(other: Any?) = other is SdkScope && sdk == other.sdk
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import java.io.File
import kotlin.script.experimental.dependencies.ScriptDependencies
class ScriptModuleSearchScope(val scriptFile: VirtualFile, baseScope: GlobalSearchScope) : DelegatingGlobalSearchScope(baseScope) {
@@ -61,8 +62,9 @@ fun findJdk(dependencies: ScriptDependencies?, project: Project): Sdk? {
null
}
return allJdks.find { javaHome != null && it.homePath == javaHome } ?: ProjectRootManager.getInstance(project).projectSdk
?: allJdks.firstOrNull()
return allJdks.find { javaHome != null && File(it.homePath).canonicalPath == javaHome }
?: ProjectRootManager.getInstance(project).projectSdk
?: allJdks.firstOrNull()
}
sealed class ScriptDependenciesInfo(val project: Project) : IdeaModuleInfo, BinaryModuleInfo {
@@ -24,6 +24,11 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.projectRoots.JavaSdk
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.projectRoots.ex.PathUtilEx
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
import org.jetbrains.kotlin.idea.caches.project.getScriptRelatedModuleInfo
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
@@ -223,7 +228,9 @@ class BundledKotlinScriptDependenciesResolver(private val project: Project) : De
scriptContents: ScriptContents,
environment: Environment
): DependenciesResolver.ResolveResult {
val javaHome = getScriptSDK(project)
val virtualFile = scriptContents.file?.let { VfsUtil.findFileByIoFile(it, true) }
val javaHome = getScriptSDK(project, virtualFile)
val dependencies = ScriptDependencies(
javaHome = javaHome?.let(::File),
classpath = with(PathUtil.kotlinPathsForIdeaPlugin) {
@@ -237,8 +244,18 @@ class BundledKotlinScriptDependenciesResolver(private val project: Project) : De
return dependencies.asSuccess()
}
private fun getScriptSDK(project: Project): String? {
val jdk = ProjectJdkTable.getInstance().allJdks.firstOrNull { sdk -> sdk.sdkType is JavaSdk } ?: PathUtilEx.getAnyJdk(project)
private fun getScriptSDK(project: Project, virtualFile: VirtualFile?): String? {
if (virtualFile != null) {
val dependentModuleSourceInfo = getScriptRelatedModuleInfo(project, virtualFile)
val sdk = dependentModuleSourceInfo?.dependencies()?.filterIsInstance<SdkInfo>()?.singleOrNull()?.sdk
if (sdk != null) {
return sdk.homePath
}
}
val jdk = ProjectRootManager.getInstance(project).projectSdk
?: ProjectJdkTable.getInstance().allJdks.firstOrNull { sdk -> sdk.sdkType is JavaSdk }
?: PathUtilEx.getAnyJdk(project)
return jdk?.homePath
}
}
@@ -18,20 +18,29 @@ package org.jetbrains.kotlin.idea.caches.resolve
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.StdModuleTypes
import com.intellij.openapi.projectRoots.ProjectJdkTable
import com.intellij.openapi.roots.DependencyScope
import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.ProjectRootManager
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess
import com.intellij.testFramework.ModuleTestCase
import com.intellij.testFramework.PlatformTestCase
import com.intellij.testFramework.PsiTestUtil
import com.intellij.testFramework.UsefulTestCase
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
import org.jetbrains.kotlin.idea.caches.project.*
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
import org.jetbrains.kotlin.idea.framework.JSLibraryKind
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase.*
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.test.util.addDependency
import org.jetbrains.kotlin.test.util.jarRoot
import org.jetbrains.kotlin.test.util.projectLibrary
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.junit.Assert
class IdeaModuleInfoTest : ModuleTestCase() {
@@ -319,12 +328,108 @@ class IdeaModuleInfoTest : ModuleTestCase() {
stdlibJs.classes.assertAdditionalLibraryDependencies(stdlibCommon.classes)
}
fun testScriptDependenciesForModule() {
val a = module("a")
val b = module("b")
with(createFileInModule(a, "script.kts").moduleInfo) {
dependencies().contains(a.production)
dependencies().contains(a.test)
!dependencies().contains(b.production)
dependencies().firstIsInstance<ScriptDependenciesInfo.ForFile>()
}
}
override fun setUp() {
super.setUp()
VfsRootAccess.allowRootAccess("C:/Work/Projects/kotlin/")
}
fun testScriptDependenciesForProject() {
val a = module("a")
val script = createFileInProject("script.kts").moduleInfo
!script.dependencies().contains(a.production)
!script.dependencies().contains(a.test)
script.dependencies().firstIsInstance<ScriptDependenciesInfo.ForFile>()
}
fun testSdkForScript() {
runWriteAction {
ProjectJdkTable.getInstance().addJdk(mockJdk6())
ProjectJdkTable.getInstance().addJdk(mockJdk9())
}
with(createFileInProject("script.kts").moduleInfo) {
dependencies().filterIsInstance<SdkInfo>().single { it.sdk == mockJdk6() }
}
}
fun testSdkForScriptProjectSdk() {
runWriteAction {
ProjectJdkTable.getInstance().addJdk(mockJdk6())
ProjectJdkTable.getInstance().addJdk(mockJdk9())
ProjectRootManager.getInstance(project).projectSdk = mockJdk9()
}
with(createFileInProject("script.kts").moduleInfo) {
dependencies().filterIsInstance<SdkInfo>().single { it.sdk == mockJdk9() }
}
}
fun testSdkForScriptModuleSdk() {
val a = module("a")
runWriteAction {
ProjectJdkTable.getInstance().addJdk(mockJdk6())
ProjectJdkTable.getInstance().addJdk(mockJdk9())
ProjectRootManager.getInstance(project).projectSdk = mockJdk6()
with(ModuleRootManager.getInstance(a).modifiableModel) {
sdk = mockJdk9()
commit()
}
}
with(createFileInModule(a, "script.kts").moduleInfo) {
dependencies().filterIsInstance<SdkInfo>().first { it.sdk == mockJdk9() }
}
}
private fun createFileInModule(module: Module, fileName: String, inTests: Boolean = false): VirtualFile {
val fileToCopyIO = createTempFile(fileName, "")
for (contentEntry in ModuleRootManager.getInstance(module).contentEntries) {
for (sourceFolder in contentEntry.sourceFolders) {
if (((!inTests && !sourceFolder.isTestSource) || (inTests && sourceFolder.isTestSource)) && sourceFolder.file != null) {
return runWriteAction {
PlatformTestCase.getVirtualFile(fileToCopyIO).copy(this, sourceFolder.file!!, fileName)
}
}
}
}
error("Couldn't find source folder in ${module.name}")
}
private fun createFileInProject(fileName: String): VirtualFile {
return runWriteAction {
PlatformTestCase.getVirtualFile(createTempFile(fileName, "")).copy(this, project.baseDir, fileName)
}
}
private fun Module.addDependency(
other: Module,
dependencyScope: DependencyScope = DependencyScope.COMPILE,
exported: Boolean = false
) = ModuleRootModificationUtil.addDependency(this, other, dependencyScope, exported)
private val VirtualFile.moduleInfo: IdeaModuleInfo
get() = getModuleInfoByVirtualFile(project, this)!!
private val Module.production: ModuleProductionSourceInfo
get() = productionSourceInfo()!!
@@ -361,13 +466,23 @@ class IdeaModuleInfoTest : ModuleTestCase() {
UsefulTestCase.assertSameElements(this.getDependentModules(), expected.toList())
}
private fun stdlibCommon(): Library = projectLibrary("kotlin-stdlib-common",
ForTestCompileRuntime.stdlibCommonForTests().jarRoot,
kind = CommonLibraryKind)
private fun stdlibCommon(): Library = projectLibrary(
"kotlin-stdlib-common",
ForTestCompileRuntime.stdlibCommonForTests().jarRoot,
kind = CommonLibraryKind
)
private fun stdlibJvm(): Library = projectLibrary("kotlin-stdlib", ForTestCompileRuntime.runtimeJarForTests().jarRoot)
private fun stdlibJs(): Library = projectLibrary("kotlin-stdlib-js",
ForTestCompileRuntime.runtimeJarForTests().jarRoot,
kind = JSLibraryKind)
private fun stdlibJs(): Library = projectLibrary(
"kotlin-stdlib-js",
ForTestCompileRuntime.runtimeJarForTests().jarRoot,
kind = JSLibraryKind
)
override fun tearDown() {
clearSdkTable(testRootDisposable)
super.tearDown()
}
}