Rewrite configureModuleWithLibrary() based on LibraryJarDescriptor

Also remove duplicated logic for identifying Kotlin libraries.
This commit is contained in:
Dmitry Jemerov
2017-04-03 11:47:28 +02:00
parent 06e8f8e5be
commit f9aff3be13
10 changed files with 120 additions and 281 deletions
@@ -53,7 +53,7 @@ object JsLibraryStdDetectionUtil {
return JarUtil.getJarAttribute(VfsUtilCore.virtualToIoFile(jar), Attributes.Name.IMPLEMENTATION_VERSION) return JarUtil.getJarAttribute(VfsUtilCore.virtualToIoFile(jar), Attributes.Name.IMPLEMENTATION_VERSION)
} }
private fun getJsStdLibJar(classesRoots: List<VirtualFile>): VirtualFile? { fun getJsStdLibJar(classesRoots: List<VirtualFile>): VirtualFile? {
for (root in classesRoots) { for (root in classesRoots) {
if (root.fileSystem.protocol !== StandardFileSystems.JAR_PROTOCOL) continue if (root.fileSystem.protocol !== StandardFileSystems.JAR_PROTOCOL) continue
@@ -18,12 +18,10 @@ package org.jetbrains.kotlin.idea.configuration
import com.intellij.openapi.extensions.Extensions import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.module.Module import com.intellij.openapi.module.Module
import com.intellij.openapi.module.impl.scopes.LibraryScope
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.roots.libraries.Library
import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
import org.jetbrains.kotlin.idea.versions.getKotlinJvmRuntimeMarkerClass import org.jetbrains.kotlin.idea.versions.isKotlinJavaRuntime
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.PathUtil
@@ -71,14 +69,8 @@ open class KotlinJavaModuleConfigurator internal constructor() : KotlinWithLibra
LibraryJarDescriptor.RUNTIME_SRC_JAR, LibraryJarDescriptor.RUNTIME_SRC_JAR,
LibraryJarDescriptor.TEST_JAR) LibraryJarDescriptor.TEST_JAR)
override fun isKotlinLibrary(project: Project, library: Library): Boolean { override val libraryMatcher: (Library) -> Boolean
if (super.isKotlinLibrary(project, library)) { get() = ::isKotlinJavaRuntime
return true
}
val scope = LibraryScope(project, library)
return getKotlinJvmRuntimeMarkerClass(project, scope) != null
}
companion object { companion object {
val NAME = "java" val NAME = "java"
@@ -17,9 +17,12 @@
package org.jetbrains.kotlin.idea.configuration; package org.jetbrains.kotlin.idea.configuration;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.libraries.Library;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.framework.JSLibraryStdDescription; import org.jetbrains.kotlin.idea.framework.JSLibraryStdDescription;
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor; import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor;
import org.jetbrains.kotlin.idea.versions.OutdatedKotlinRuntimeCheckerKt;
import org.jetbrains.kotlin.js.JavaScript; import org.jetbrains.kotlin.js.JavaScript;
import org.jetbrains.kotlin.js.resolve.JsPlatform; import org.jetbrains.kotlin.js.resolve.JsPlatform;
import org.jetbrains.kotlin.resolve.TargetPlatform; import org.jetbrains.kotlin.resolve.TargetPlatform;
@@ -97,6 +100,12 @@ public class KotlinJsModuleConfigurator extends KotlinWithLibraryConfigurator {
LibraryJarDescriptor.JS_STDLIB_SRC_JAR); LibraryJarDescriptor.JS_STDLIB_SRC_JAR);
} }
@NotNull
@Override
protected Function1<Library, Boolean> getLibraryMatcher() {
return OutdatedKotlinRuntimeCheckerKt::isKotlinJsRuntime;
}
KotlinJsModuleConfigurator() { KotlinJsModuleConfigurator() {
} }
} }
@@ -23,18 +23,18 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.* import com.intellij.openapi.roots.*
import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainer
import com.intellij.openapi.roots.ui.configuration.projectRoot.LibrariesContainerFactory
import com.intellij.openapi.ui.Messages import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.Ref import com.intellij.openapi.vfs.JarFileSystem
import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VfsUtilCore import com.intellij.openapi.vfs.VfsUtilCore
import com.intellij.util.Processor
import org.jetbrains.annotations.Contract import org.jetbrains.annotations.Contract
import org.jetbrains.kotlin.idea.KotlinPluginUtil import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.framework.ui.CreateLibraryDialogWithModules import org.jetbrains.kotlin.idea.framework.ui.CreateLibraryDialogWithModules
import org.jetbrains.kotlin.idea.framework.ui.FileUIUtils import org.jetbrains.kotlin.idea.framework.ui.FileUIUtils
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
import org.jetbrains.kotlin.idea.versions.findKotlinRuntimeLibrary
import java.io.File import java.io.File
import java.util.* import java.util.*
@@ -114,122 +114,60 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
) { ) {
val project = module.project val project = module.project
val files = existingJarFiles val library = getKotlinLibrary(module) ?: createNewLibrary(project, collector)
val libraryState = getLibraryState(project)
val dirToCopyJar = getPathToCopyFileTo(project, OrderRootType.CLASSES, defaultPath, pathFromDialog)
val runtimeState = getJarState(project, files.getRuntimeDestination(dirToCopyJar), OrderRootType.CLASSES, pathFromDialog == null)
configureModuleWithLibraryClasses(module, libraryState, runtimeState, dirToCopyJar, collector) for (descriptor in libraryJarDescriptors) {
val dirToCopyJar = getPathToCopyFileTo(project, descriptor.orderRootType, defaultPath, pathFromDialog)
val runtimeState = getJarState(project,
File(dirToCopyJar, descriptor.jarName),
descriptor.orderRootType, pathFromDialog == null)
val library = getKotlinLibrary(project) ?: return configureLibraryJar(module, library, runtimeState, dirToCopyJar, descriptor, collector)
val dirToCopySourcesJar = getPathToCopyFileTo(project, OrderRootType.SOURCES, defaultPath, pathFromDialog)
val sourcesState = getJarState(project, files.getRuntimeSourcesDestination(dirToCopySourcesJar), OrderRootType.SOURCES,
pathFromDialog == null)
configureModuleWithLibrarySources(library, sourcesState, dirToCopySourcesJar, collector)
}
fun configureModuleWithLibraryClasses(
module: Module,
libraryState: LibraryState,
jarState: FileState,
dirToCopyJarTo: String,
collector: NotificationMessageCollector
) {
val project = module.project
val files = existingJarFiles
val runtimeJar = files.runtimeJar
val reflectJar = files.reflectJar
when (libraryState) {
KotlinWithLibraryConfigurator.LibraryState.LIBRARY -> when (jarState) {
KotlinWithLibraryConfigurator.FileState.EXISTS -> {
}
KotlinWithLibraryConfigurator.FileState.COPY -> {
copyFileToDir(runtimeJar, dirToCopyJarTo, collector)
if (reflectJar != null) {
copyFileToDir(reflectJar, dirToCopyJarTo, collector)
}
}
KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY -> {
throw IllegalStateException(
"Kotlin library exists, so path to copy should be hidden in configuration dialog and jar should be copied using path in library table")
}
}
KotlinWithLibraryConfigurator.LibraryState.NON_CONFIGURED_LIBRARY -> when (jarState) {
KotlinWithLibraryConfigurator.FileState.EXISTS -> {
addJarsToExistingLibrary(
project, files.getRuntimeDestination(dirToCopyJarTo), files.getReflectDestination(dirToCopyJarTo), collector
)
}
KotlinWithLibraryConfigurator.FileState.COPY -> {
val copiedRuntimeJar = copyFileToDir(runtimeJar, dirToCopyJarTo, collector)
val copiedReflectJar = copyFileToDir(reflectJar, dirToCopyJarTo, collector)
addJarsToExistingLibrary(project, copiedRuntimeJar!!, copiedReflectJar, collector)
}
KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY -> {
addJarsToExistingLibrary(project, runtimeJar, reflectJar, collector)
}
}
KotlinWithLibraryConfigurator.LibraryState.NEW_LIBRARY -> when (jarState) {
KotlinWithLibraryConfigurator.FileState.EXISTS -> {
addJarsToNewLibrary(
project, files.getRuntimeDestination(dirToCopyJarTo), files.getReflectDestination(dirToCopyJarTo), collector
)
}
KotlinWithLibraryConfigurator.FileState.COPY -> {
val copiedRuntimeJar = copyFileToDir(runtimeJar, dirToCopyJarTo, collector)
val copiedReflectJar = copyFileToDir(reflectJar, dirToCopyJarTo, collector)
addJarsToNewLibrary(project, copiedRuntimeJar!!, copiedReflectJar, collector)
}
KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY -> {
addJarsToNewLibrary(project, runtimeJar, reflectJar, collector)
}
}
} }
addLibraryToModuleIfNeeded(module, collector)
} }
protected fun configureModuleWithLibrarySources( fun configureLibraryJar(
module: Module,
library: Library, library: Library,
jarState: FileState, jarState: FileState,
dirToCopyJarTo: String?, dirToCopyJarTo: String,
libraryJarDescriptor: LibraryJarDescriptor,
collector: NotificationMessageCollector collector: NotificationMessageCollector
) { ) {
val files = existingJarFiles val jarFile = if (jarState == KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY)
val runtimeSourcesJar = files.runtimeSourcesJar libraryJarDescriptor.getPathInPlugin()
when (jarState) { else
KotlinWithLibraryConfigurator.FileState.EXISTS -> { File(dirToCopyJarTo, libraryJarDescriptor.jarName)
if (dirToCopyJarTo != null) {
addSourcesToLibraryIfNeeded(library, files.getRuntimeSourcesDestination(dirToCopyJarTo), collector) if (jarState == KotlinWithLibraryConfigurator.FileState.COPY) {
} copyFileToDir(libraryJarDescriptor.getPathInPlugin(), dirToCopyJarTo, collector)
}
KotlinWithLibraryConfigurator.FileState.COPY -> {
assert(dirToCopyJarTo != null) { "Path to copy should be non-null" }
val file = copyFileToDir(runtimeSourcesJar, dirToCopyJarTo!!, collector)
addSourcesToLibraryIfNeeded(library, file!!, collector)
}
KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY -> {
addSourcesToLibraryIfNeeded(library, runtimeSourcesJar, collector)
}
} }
val jarVFile = LocalFileSystem.getInstance().findFileByIoFile(jarFile)
if (jarVFile == null) {
collector.addMessage("Can't find library JAR file " + jarFile)
return
}
val jarRoot = JarFileSystem.getInstance().getJarRootForLocalFile(jarVFile)
if (jarRoot == null) {
collector.addMessage("Couldn't configure library; JAR file $jarVFile may be corrupted")
return
}
if (jarRoot !in library.getFiles(libraryJarDescriptor.orderRootType)) {
val model = library.modifiableModel
model.addRoot(jarRoot, libraryJarDescriptor.orderRootType)
ApplicationManager.getApplication().runWriteAction { model.commit() }
collector.addMessage("Added $jarFile to library configuration")
}
addLibraryToModuleIfNeeded(module, library, collector)
} }
fun getKotlinLibrary(project: Project): Library? { fun getKotlinLibrary(project: Project): Library? {
val librariesContainer = LibrariesContainerFactory.createContainer(project) return LibraryTablesRegistrar.getInstance().getLibraryTable(project).libraries.firstOrNull(this::isKotlinLibrary) ?:
for (library in librariesContainer.getLibraries(LibrariesContainer.LibraryLevel.PROJECT)) { LibraryTablesRegistrar.getInstance().libraryTable.libraries.firstOrNull(this::isKotlinLibrary)
if (isKotlinLibrary(project, library)) {
return library
}
}
for (library in librariesContainer.getLibraries(LibrariesContainer.LibraryLevel.GLOBAL)) {
if (isKotlinLibrary(project, library)) {
return library
}
}
return null
} }
@Contract("!null, _, _ -> !null") @Contract("!null, _, _ -> !null")
@@ -247,12 +185,10 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
return getPathFromLibrary(getKotlinLibrary(project), type) return getPathFromLibrary(getKotlinLibrary(project), type)
} }
private fun addLibraryToModuleIfNeeded(module: Module, collector: NotificationMessageCollector) { private fun addLibraryToModuleIfNeeded(module: Module, library: Library, collector: NotificationMessageCollector) {
val expectedDependencyScope = getDependencyScope(module) val expectedDependencyScope = getDependencyScope(module)
val kotlinLibrary = getKotlinLibrary(module) val kotlinLibrary = getKotlinLibrary(module)
if (kotlinLibrary == null) { if (kotlinLibrary == null) {
val library = getKotlinLibrary(module.project) ?: error("Kotlin project library should exists")
ModuleRootModificationUtil.addDependency(module, library, expectedDependencyScope, false) ModuleRootModificationUtil.addDependency(module, library, expectedDependencyScope, false)
collector.addMessage(library.name + " library was added to module " + module.name) collector.addMessage(library.name + " library was added to module " + module.name)
} }
@@ -271,44 +207,17 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
} }
} }
private fun addJarsToExistingLibrary(project: Project, runtimeJar: File, reflectJar: File?, collector: NotificationMessageCollector) { fun createNewLibrary(
val library = getKotlinLibrary(project) ?: error("Kotlin library should present, instead createNewLibrary should be invoked")
val model = library.modifiableModel
model.addRoot(VfsUtil.getUrlForLibraryRoot(runtimeJar), OrderRootType.CLASSES)
if (reflectJar != null) {
model.addRoot(VfsUtil.getUrlForLibraryRoot(reflectJar), OrderRootType.CLASSES)
}
ApplicationManager.getApplication().runWriteAction { model.commit() }
collector.addMessage(library.name!! + " library was configured")
}
private fun addJarsToNewLibrary(
project: Project, project: Project,
runtimeJar: File,
reflectJar: File?,
collector: NotificationMessageCollector collector: NotificationMessageCollector
) { ): Library {
val table = LibraryTablesRegistrar.getInstance().getLibraryTable(project) val table = LibraryTablesRegistrar.getInstance().getLibraryTable(project)
val library = Ref<Library>() val library = runWriteAction {
ApplicationManager.getApplication().runWriteAction { table.createLibrary(libraryName)
library.set(table.createLibrary(libraryName))
val model = library.get().modifiableModel
model.addRoot(VfsUtil.getUrlForLibraryRoot(runtimeJar), OrderRootType.CLASSES)
if (reflectJar != null) {
model.addRoot(VfsUtil.getUrlForLibraryRoot(reflectJar), OrderRootType.CLASSES)
}
model.commit()
} }
collector.addMessage(library.get().name!! + " library was created") collector.addMessage(library.name!! + " library was created")
} return library!!
private fun isProjectLibraryWithoutPathsPresent(project: Project): Boolean {
val library = getKotlinLibrary(project)
return library != null && library.getUrls(OrderRootType.CLASSES).size == 0
} }
private fun isProjectLibraryPresent(project: Project): Boolean { private fun isProjectLibraryPresent(project: Project): Boolean {
@@ -316,33 +225,13 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
return library != null && library.getUrls(OrderRootType.CLASSES).size > 0 return library != null && library.getUrls(OrderRootType.CLASSES).size > 0
} }
private fun getKotlinLibrary(module: Module): Library? { protected abstract val libraryMatcher: (Library) -> Boolean
val result = Ref.create<Library>(null)
OrderEnumerator.orderEntries(module).forEachLibrary(Processor<Library> { library -> fun getKotlinLibrary(module: Module): Library? {
if (isKotlinLibrary(module.project, library)) { return findKotlinRuntimeLibrary(module, this::isKotlinLibrary)
result.set(library)
return@Processor false
}
true
})
return result.get()
} }
protected open fun isKotlinLibrary(project: Project, library: Library): Boolean { private fun isKotlinLibrary(library: Library) = library.name == libraryName || libraryMatcher(library)
if (libraryName == library.name) {
return true
}
val fileName = existingJarFiles.runtimeJar.name
for (root in library.getFiles(OrderRootType.CLASSES)) {
if (root.name == fileName) {
return true
}
}
return false
}
protected fun needToChooseJarPath(project: Project): Boolean { protected fun needToChooseJarPath(project: Project): Boolean {
val defaultPath = getDefaultPathToJarFile(project) val defaultPath = getDefaultPathToJarFile(project)
@@ -363,22 +252,6 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
DO_NOT_COPY DO_NOT_COPY
} }
enum class LibraryState {
LIBRARY,
NON_CONFIGURED_LIBRARY,
NEW_LIBRARY
}
fun getLibraryState(project: Project): LibraryState {
if (isProjectLibraryPresent(project)) {
return LibraryState.LIBRARY
}
else if (isProjectLibraryWithoutPathsPresent(project)) {
return LibraryState.NON_CONFIGURED_LIBRARY
}
return LibraryState.NEW_LIBRARY
}
protected fun getJarState( protected fun getJarState(
project: Project, project: Project,
targetFile: File, targetFile: File,
@@ -415,13 +288,6 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
return defaultDir return defaultDir
} }
protected fun assertFileExists(file: File): File {
if (!file.exists()) {
showError("Couldn't find file: " + file.path)
}
return file
}
abstract val libraryJarDescriptors: List<LibraryJarDescriptor> abstract val libraryJarDescriptors: List<LibraryJarDescriptor>
companion object { companion object {
@@ -449,26 +315,6 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
return parentDir return parentDir
} }
protected fun addSourcesToLibraryIfNeeded(
library: Library,
file: File,
collector: NotificationMessageCollector
): Boolean {
val librarySourceRoots = library.getUrls(OrderRootType.SOURCES)
val librarySourceRoot = VfsUtil.getUrlForLibraryRoot(file)
for (sourceRoot in librarySourceRoots) {
if (sourceRoot == librarySourceRoot) return false
}
val model = library.modifiableModel
model.addRoot(librarySourceRoot, OrderRootType.SOURCES)
ApplicationManager.getApplication().runWriteAction { model.commit() }
collector.addMessage("Source root '" + librarySourceRoot + "' was added to " + library.name + " library")
return true
}
private fun findLibraryOrderEntry(orderEntries: Array<OrderEntry>, library: Library): LibraryOrderEntry? { private fun findLibraryOrderEntry(orderEntries: Array<OrderEntry>, library: Library): LibraryOrderEntry? {
for (orderEntry in orderEntries) { for (orderEntry in orderEntries) {
if (orderEntry is LibraryOrderEntry && library == orderEntry.library) { if (orderEntry is LibraryOrderEntry && library == orderEntry.library) {
@@ -49,7 +49,6 @@ import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.utils.PathUtil
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.io.File import java.io.File
@@ -119,7 +118,7 @@ abstract class AddKotlinLibQuickFix(element: KtElement, val libraryJarDescriptor
protected abstract fun getLibraryDescriptor(module: Module): MavenExternalLibraryDescriptor protected abstract fun getLibraryDescriptor(module: Module): MavenExternalLibraryDescriptor
fun libraryPath(): String = libraryJarDescriptor.jarName fun libraryPath(): String = libraryJarDescriptor.jarName
fun getLibFile(): File = libraryJarDescriptor.getPath(PathUtil.getKotlinPathsForIdeaPlugin()) fun getLibFile(): File = libraryJarDescriptor.getPathInPlugin()
fun hasLibJarInLibrary(library: Library): Boolean = libraryJarDescriptor.findExistingJar(library) != null fun hasLibJarInLibrary(library: Library): Boolean = libraryJarDescriptor.findExistingJar(library) != null
class MavenExternalLibraryDescriptor(groupId: String, artifactId: String, version: String) : class MavenExternalLibraryDescriptor(groupId: String, artifactId: String, version: String) :
@@ -171,7 +171,7 @@ fun checkUpdateRuntime(project: Project, requiredVersion: ApiVersion): Boolean {
} }
if (modulesWithOutdatedRuntime.isNotEmpty()) { if (modulesWithOutdatedRuntime.isNotEmpty()) {
if (!askUpdateRuntime(project, requiredVersion, if (!askUpdateRuntime(project, requiredVersion,
modulesWithOutdatedRuntime.mapNotNull(::findKotlinRuntimeLibrary))) return false modulesWithOutdatedRuntime.mapNotNull { findKotlinRuntimeLibrary(it) })) return false
} }
return true return true
} }
@@ -120,8 +120,7 @@ private fun updateJar(
} }
val oldUrl = fileToReplace?.url val oldUrl = fileToReplace?.url
val paths = PathUtil.getKotlinPathsForIdeaPlugin() val jarPath: File = libraryJarDescriptor.getPathInPlugin()
val jarPath: File = libraryJarDescriptor.getPath(paths)
if (!jarPath.exists()) { if (!jarPath.exists()) {
showRuntimeJarNotFoundDialog(project, libraryJarDescriptor.jarName) showRuntimeJarNotFoundDialog(project, libraryJarDescriptor.jarName)
@@ -185,6 +184,8 @@ enum class LibraryJarDescriptor(val jarName: String,
if (isExternalLibrary(library)) return null if (isExternalLibrary(library)) return null
return LibraryUtils.getJarFile(Arrays.asList(*library.getFiles(orderRootType)), jarName) return LibraryUtils.getJarFile(Arrays.asList(*library.getFiles(orderRootType)), jarName)
} }
fun getPathInPlugin() = getPath(PathUtil.getKotlinPathsForIdeaPlugin())
} }
fun bundledRuntimeVersion(): String { fun bundledRuntimeVersion(): String {
@@ -26,14 +26,12 @@ import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.LibraryOrderEntry import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.libraries.Library import com.intellij.openapi.roots.libraries.Library
import com.intellij.util.PathUtil.getLocalFile import com.intellij.util.PathUtil.getLocalFile
import com.intellij.util.text.VersionComparatorUtil import com.intellij.util.text.VersionComparatorUtil
import org.jetbrains.kotlin.idea.KotlinPluginUtil import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider import org.jetbrains.kotlin.idea.framework.*
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider
import org.jetbrains.kotlin.idea.framework.getLibraryProperties
import org.jetbrains.kotlin.idea.framework.isDetected
import org.jetbrains.kotlin.idea.util.application.runWriteAction import org.jetbrains.kotlin.idea.util.application.runWriteAction
import java.io.IOException import java.io.IOException
import javax.swing.event.HyperlinkEvent import javax.swing.event.HyperlinkEvent
@@ -74,13 +72,21 @@ private fun getKotlinLibraryVersionProperties(library: Library) =
getLibraryProperties(JavaRuntimePresentationProvider.getInstance(), library) ?: getLibraryProperties(JavaRuntimePresentationProvider.getInstance(), library) ?:
getLibraryProperties(JSLibraryStdPresentationProvider.getInstance(), library) getLibraryProperties(JSLibraryStdPresentationProvider.getInstance(), library)
fun findKotlinRuntimeLibrary(module: Module): Library? { fun findKotlinRuntimeLibrary(module: Module, predicate: (Library) -> Boolean = ::isKotlinRuntime): Library? {
val orderEntries = ModuleRootManager.getInstance(module).orderEntries.filterIsInstance<LibraryOrderEntry>() val orderEntries = ModuleRootManager.getInstance(module).orderEntries.filterIsInstance<LibraryOrderEntry>()
return orderEntries.asSequence() return orderEntries.asSequence()
.mapNotNull { it.library } .mapNotNull { it.library }
.firstOrNull { getKotlinLibraryVersionProperties(it) != null } .firstOrNull(predicate)
} }
fun isKotlinRuntime(library: Library) = isKotlinJavaRuntime(library) || isKotlinJsRuntime(library)
fun isKotlinJavaRuntime(library: Library) =
JavaRuntimeDetectionUtil.getRuntimeJar(library.getFiles(OrderRootType.CLASSES).asList()) != null
fun isKotlinJsRuntime(library: Library) =
JsLibraryStdDetectionUtil.getJsStdLibJar(library.getFiles(OrderRootType.CLASSES).asList()) != null
fun collectModulesWithOutdatedRuntime(libraries: List<VersionedLibrary>): List<Module> = fun collectModulesWithOutdatedRuntime(libraries: List<VersionedLibrary>): List<Module> =
libraries.flatMap { it.usedInModules } libraries.flatMap { it.usedInModules }
@@ -20,10 +20,12 @@ import com.intellij.openapi.application.PathMacros;
import com.intellij.openapi.module.Module; import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.FileUtilRt; import com.intellij.openapi.util.io.FileUtilRt;
import com.intellij.testFramework.PlatformTestCase; import com.intellij.testFramework.PlatformTestCase;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor;
import org.jetbrains.kotlin.utils.PathUtil; import org.jetbrains.kotlin.utils.PathUtil;
import java.io.File; import java.io.File;
@@ -32,7 +34,6 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import static org.jetbrains.kotlin.idea.configuration.KotlinWithLibraryConfigurator.FileState; import static org.jetbrains.kotlin.idea.configuration.KotlinWithLibraryConfigurator.FileState;
import static org.jetbrains.kotlin.idea.configuration.KotlinWithLibraryConfigurator.LibraryState;
public abstract class AbstractConfigureKotlinTest extends PlatformTestCase { public abstract class AbstractConfigureKotlinTest extends PlatformTestCase {
private static final String BASE_PATH = "idea/testData/configuration/"; private static final String BASE_PATH = "idea/testData/configuration/";
@@ -53,16 +54,22 @@ public abstract class AbstractConfigureKotlinTest extends PlatformTestCase {
private static void configure( private static void configure(
@NotNull List<Module> modules, @NotNull List<Module> modules,
@NotNull FileState runtimeState, @NotNull FileState runtimeState,
@NotNull LibraryState libraryState,
@NotNull KotlinWithLibraryConfigurator configurator, @NotNull KotlinWithLibraryConfigurator configurator,
@NotNull String jarFromDist, @NotNull String jarFromDist,
@NotNull String jarFromTemp @NotNull String jarFromTemp
) { ) {
Project project = modules.iterator().next().getProject(); Project project = modules.iterator().next().getProject();
NotificationMessageCollector collector = NotificationMessageCollectorKt.createConfigureKotlinNotificationCollector(project); NotificationMessageCollector collector = NotificationMessageCollectorKt.createConfigureKotlinNotificationCollector(project);
for (Module module : modules) { for (Module module : modules) {
Library library = configurator.getKotlinLibrary(module);
if (library == null) {
library = configurator.createNewLibrary(project, collector);
}
String pathToJar = getPathToJar(runtimeState, jarFromDist, jarFromTemp); String pathToJar = getPathToJar(runtimeState, jarFromDist, jarFromTemp);
configurator.configureModuleWithLibraryClasses(module, libraryState, runtimeState, pathToJar, collector); for (LibraryJarDescriptor descriptor : configurator.getLibraryJarDescriptors()) {
configurator.configureLibraryJar(module, library, runtimeState, pathToJar, descriptor, collector);
}
} }
collector.showNotification(); collector.showNotification();
} }
@@ -80,14 +87,14 @@ public abstract class AbstractConfigureKotlinTest extends PlatformTestCase {
return jarFromDist; return jarFromDist;
} }
protected static void configure(@NotNull Module module, @NotNull FileState jarState, @NotNull LibraryState libraryState, @NotNull KotlinProjectConfigurator configurator) { protected static void configure(@NotNull Module module, @NotNull FileState jarState, @NotNull KotlinProjectConfigurator configurator) {
if (configurator instanceof KotlinJavaModuleConfigurator) { if (configurator instanceof KotlinJavaModuleConfigurator) {
configure(Collections.singletonList(module), jarState, libraryState, configure(Collections.singletonList(module), jarState,
(KotlinWithLibraryConfigurator) configurator, (KotlinWithLibraryConfigurator) configurator,
getPathToExistentRuntimeJar(), getPathToNonexistentRuntimeJar()); getPathToExistentRuntimeJar(), getPathToNonexistentRuntimeJar());
} }
if (configurator instanceof KotlinJsModuleConfigurator) { if (configurator instanceof KotlinJsModuleConfigurator) {
configure(Collections.singletonList(module), jarState, libraryState, configure(Collections.singletonList(module), jarState,
(KotlinWithLibraryConfigurator) configurator, (KotlinWithLibraryConfigurator) configurator,
getPathToExistentJsJar(), getPathToNonexistentJsJar()); getPathToExistentJsJar(), getPathToNonexistentJsJar());
} }
@@ -174,20 +181,19 @@ public abstract class AbstractConfigureKotlinTest extends PlatformTestCase {
} }
} }
protected void doTestOneJavaModule(@NotNull FileState jarState, @NotNull LibraryState libraryState) { protected void doTestOneJavaModule(@NotNull FileState jarState) {
doTestOneModule(jarState, libraryState, JAVA_CONFIGURATOR); doTestOneModule(jarState, JAVA_CONFIGURATOR);
} }
protected void doTestOneJsModule(@NotNull FileState jarState, @NotNull LibraryState libraryState) { protected void doTestOneJsModule(@NotNull FileState jarState) {
doTestOneModule(jarState, libraryState, JS_CONFIGURATOR); doTestOneModule(jarState, JS_CONFIGURATOR);
} }
private void doTestOneModule(@NotNull FileState jarState, @NotNull LibraryState libraryState, @NotNull KotlinWithLibraryConfigurator configurator) { private void doTestOneModule(@NotNull FileState jarState, @NotNull KotlinWithLibraryConfigurator configurator) {
Module module = getModule(); Module module = getModule();
assertEquals("Library state loaded from project files should be " + libraryState, libraryState, configurator.getLibraryState(module.getProject()));
assertNotConfigured(module, configurator); assertNotConfigured(module, configurator);
configure(module, jarState, libraryState, configurator); configure(module, jarState, configurator);
assertProperlyConfigured(module, configurator); assertProperlyConfigured(module, configurator);
} }
@@ -34,37 +34,27 @@ import java.util.Collections;
public class ConfigureKotlinTest extends AbstractConfigureKotlinTest { public class ConfigureKotlinTest extends AbstractConfigureKotlinTest {
public void testNewLibrary_copyJar() { public void testNewLibrary_copyJar() {
doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.COPY, KotlinWithLibraryConfigurator.LibraryState.NEW_LIBRARY); doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.COPY);
} }
public void testNewLibrary_doNotCopyJar() { public void testNewLibrary_doNotCopyJar() {
doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY, KotlinWithLibraryConfigurator.LibraryState.NEW_LIBRARY); doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY);
}
public void testLibrary_doNotCopyJar() {
try {
doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY, KotlinWithLibraryConfigurator.LibraryState.LIBRARY);
}
catch (IllegalStateException e) {
return;
}
fail("Test should throw IllegalStateException");
} }
public void testLibraryWithoutPaths_jarExists() { public void testLibraryWithoutPaths_jarExists() {
doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.EXISTS, KotlinWithLibraryConfigurator.LibraryState.NON_CONFIGURED_LIBRARY); doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.EXISTS);
} }
public void testNewLibrary_jarExists() { public void testNewLibrary_jarExists() {
doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.EXISTS, KotlinWithLibraryConfigurator.LibraryState.NEW_LIBRARY); doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.EXISTS);
} }
public void testLibraryWithoutPaths_copyJar() { public void testLibraryWithoutPaths_copyJar() {
doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.COPY, KotlinWithLibraryConfigurator.LibraryState.NON_CONFIGURED_LIBRARY); doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.COPY);
} }
public void testLibraryWithoutPaths_doNotCopyJar() { public void testLibraryWithoutPaths_doNotCopyJar() {
doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY, KotlinWithLibraryConfigurator.LibraryState.NON_CONFIGURED_LIBRARY); doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY);
} }
@SuppressWarnings("ConstantConditions") @SuppressWarnings("ConstantConditions")
@@ -72,12 +62,12 @@ public class ConfigureKotlinTest extends AbstractConfigureKotlinTest {
Module[] modules = getModules(); Module[] modules = getModules();
for (Module module : modules) { for (Module module : modules) {
if (module.getName().equals("module1")) { if (module.getName().equals("module1")) {
configure(module, KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY, KotlinWithLibraryConfigurator.LibraryState.NEW_LIBRARY, JAVA_CONFIGURATOR); configure(module, KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY, JAVA_CONFIGURATOR);
assertConfigured(module, JAVA_CONFIGURATOR); assertConfigured(module, JAVA_CONFIGURATOR);
} }
else if (module.getName().equals("module2")) { else if (module.getName().equals("module2")) {
assertNotConfigured(module, JAVA_CONFIGURATOR); assertNotConfigured(module, JAVA_CONFIGURATOR);
configure(module, KotlinWithLibraryConfigurator.FileState.EXISTS, KotlinWithLibraryConfigurator.LibraryState.LIBRARY, JAVA_CONFIGURATOR); configure(module, KotlinWithLibraryConfigurator.FileState.EXISTS, JAVA_CONFIGURATOR);
assertConfigured(module, JAVA_CONFIGURATOR); assertConfigured(module, JAVA_CONFIGURATOR);
} }
} }
@@ -107,37 +97,27 @@ public class ConfigureKotlinTest extends AbstractConfigureKotlinTest {
} }
public void testNewLibrary_jarExists_js() { public void testNewLibrary_jarExists_js() {
doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.EXISTS, KotlinWithLibraryConfigurator.LibraryState.NEW_LIBRARY); doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.EXISTS);
} }
public void testNewLibrary_copyJar_js() { public void testNewLibrary_copyJar_js() {
doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.COPY, KotlinWithLibraryConfigurator.LibraryState.NEW_LIBRARY); doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.COPY);
} }
public void testNewLibrary_doNotCopyJar_js() { public void testNewLibrary_doNotCopyJar_js() {
doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY, KotlinWithLibraryConfigurator.LibraryState.NEW_LIBRARY); doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY);
}
public void testJsLibrary_doNotCopyJar() {
try {
doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY, KotlinWithLibraryConfigurator.LibraryState.LIBRARY);
}
catch (IllegalStateException e) {
return;
}
fail("Test should throw IllegalStateException");
} }
public void testJsLibraryWithoutPaths_jarExists() { public void testJsLibraryWithoutPaths_jarExists() {
doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.EXISTS, KotlinWithLibraryConfigurator.LibraryState.NON_CONFIGURED_LIBRARY); doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.EXISTS);
} }
public void testJsLibraryWithoutPaths_copyJar() { public void testJsLibraryWithoutPaths_copyJar() {
doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.COPY, KotlinWithLibraryConfigurator.LibraryState.NON_CONFIGURED_LIBRARY); doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.COPY);
} }
public void testJsLibraryWithoutPaths_doNotCopyJar() { public void testJsLibraryWithoutPaths_doNotCopyJar() {
doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY, KotlinWithLibraryConfigurator.LibraryState.NON_CONFIGURED_LIBRARY); doTestOneJsModule(KotlinWithLibraryConfigurator.FileState.DO_NOT_COPY);
} }
public void testProjectWithoutFacetWithRuntime106WithoutLanguageLevel() { public void testProjectWithoutFacetWithRuntime106WithoutLanguageLevel() {