Encapsulate library search in LibraryJarDescriptor

This commit is contained in:
Dmitry Jemerov
2017-03-31 18:46:13 +02:00
parent f9495aa0d7
commit 291e888802
8 changed files with 81 additions and 108 deletions
@@ -22,7 +22,7 @@ import com.intellij.openapi.module.impl.scopes.LibraryScope
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.libraries.Library
import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription
import org.jetbrains.kotlin.idea.framework.getRuntimeJar
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
import org.jetbrains.kotlin.idea.versions.getKotlinJvmRuntimeMarkerClass
import org.jetbrains.kotlin.resolve.TargetPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
@@ -65,8 +65,14 @@ open class KotlinJavaModuleConfigurator internal constructor() : KotlinWithLibra
)
}
override val libraryJarDescriptors: List<LibraryJarDescriptor>
get() = listOf(LibraryJarDescriptor.RUNTIME_JAR,
LibraryJarDescriptor.REFLECT_JAR,
LibraryJarDescriptor.RUNTIME_SRC_JAR,
LibraryJarDescriptor.TEST_JAR)
override fun getOldSourceRootUrl(library: Library): String? {
val runtimeJarPath = getRuntimeJar(library)
val runtimeJarPath = LibraryJarDescriptor.RUNTIME_JAR.findExistingJar(library)
return if (runtimeJarPath != null) runtimeJarPath.url + "src" else null
}
@@ -22,13 +22,16 @@ import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.framework.JSLibraryStdDescription;
import org.jetbrains.kotlin.idea.framework.KotlinLibraryUtilKt;
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor;
import org.jetbrains.kotlin.js.JavaScript;
import org.jetbrains.kotlin.js.resolve.JsPlatform;
import org.jetbrains.kotlin.resolve.TargetPlatform;
import org.jetbrains.kotlin.utils.KotlinPaths;
import org.jetbrains.kotlin.utils.PathUtil;
import java.util.Arrays;
import java.util.List;
public class KotlinJsModuleConfigurator extends KotlinWithLibraryConfigurator {
public static final String NAME = JavaScript.LOWER_NAME;
@@ -90,13 +93,20 @@ public class KotlinJsModuleConfigurator extends KotlinWithLibraryConfigurator {
);
}
@NotNull
@Override
public List<LibraryJarDescriptor> getLibraryJarDescriptors() {
return Arrays.asList(LibraryJarDescriptor.JS_STDLIB_JAR,
LibraryJarDescriptor.JS_STDLIB_SRC_JAR);
}
KotlinJsModuleConfigurator() {
}
@Nullable
@Override
protected String getOldSourceRootUrl(@NotNull Library library) {
VirtualFile jsStdLibJar = KotlinLibraryUtilKt.getJsStdLibJar(library);
VirtualFile jsStdLibJar = LibraryJarDescriptor.JS_STDLIB_JAR.findExistingJar(library);
return jsStdLibJar != null ? jsStdLibJar.getUrl() : null;
}
}
@@ -34,6 +34,7 @@ import org.jetbrains.annotations.Contract
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.framework.ui.CreateLibraryDialogWithModules
import org.jetbrains.kotlin.idea.framework.ui.FileUIUtils
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
import java.io.File
import java.util.*
@@ -456,6 +457,8 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
return false
}
abstract val libraryJarDescriptors: List<LibraryJarDescriptor>
companion object {
val DEFAULT_LIBRARY_DIR = "lib"
@@ -22,9 +22,6 @@ import com.intellij.openapi.roots.OrderRootType
import com.intellij.openapi.roots.libraries.Library
import com.intellij.openapi.roots.libraries.LibraryPresentationProvider
import com.intellij.openapi.roots.libraries.LibraryProperties
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.utils.LibraryUtils
import org.jetbrains.kotlin.utils.PathUtil
import java.util.*
fun <LP : LibraryProperties<out Any>> isDetected(provider: LibraryPresentationProvider<LP>, library: Library): Boolean {
@@ -39,42 +36,9 @@ fun <LP : LibraryProperties<out Any>> getLibraryProperties(provider: LibraryPres
private val MAVEN_SYSTEM_ID = ProjectSystemId("MAVEN")
val GRADLE_SYSTEM_ID = ProjectSystemId("GRADLE")
private fun isExternalLibrary(library: Library): Boolean {
fun isExternalLibrary(library: Library): Boolean {
return ExternalSystemApiUtil.isExternalSystemLibrary(library, ProjectSystemId.IDE) ||
ExternalSystemApiUtil.isExternalSystemLibrary(library, GRADLE_SYSTEM_ID) ||
ExternalSystemApiUtil.isExternalSystemLibrary(library, MAVEN_SYSTEM_ID)
}
fun getRuntimeJar(library: Library): VirtualFile? {
if (isExternalLibrary(library)) return null
return JavaRuntimeDetectionUtil.getRuntimeJar(Arrays.asList(*library.getFiles(OrderRootType.CLASSES)))
}
fun getReflectJar(library: Library): VirtualFile? {
if (isExternalLibrary(library)) return null
return LibraryUtils.getJarFile(Arrays.asList(*library.getFiles(OrderRootType.CLASSES)), PathUtil.KOTLIN_JAVA_REFLECT_JAR)
}
fun getRuntimeSrcJar(library: Library): VirtualFile? {
if (isExternalLibrary(library)) return null
return getRuntimeSrcJar(Arrays.asList(*library.getFiles(OrderRootType.SOURCES)))
}
fun getTestJar(library: Library): VirtualFile? {
if (isExternalLibrary(library)) return null
return LibraryUtils.getJarFile(Arrays.asList(*library.getFiles(OrderRootType.CLASSES)), PathUtil.KOTLIN_TEST_JAR)
}
fun getJsStdLibJar(library: Library): VirtualFile? {
if (isExternalLibrary(library)) return null
return LibraryUtils.getJarFile(Arrays.asList(*library.getFiles(OrderRootType.CLASSES)), PathUtil.JS_LIB_JAR_NAME)
}
fun getJsStdLibSrcJar(library: Library): VirtualFile? {
if (isExternalLibrary(library)) return null
return LibraryUtils.getJarFile(Arrays.asList(*library.getFiles(OrderRootType.SOURCES)), PathUtil.JS_LIB_SRC_JAR_NAME)
}
private fun getRuntimeSrcJar(classesRoots: List<VirtualFile>): VirtualFile? {
return LibraryUtils.getJarFile(classesRoots, PathUtil.KOTLIN_JAVA_RUNTIME_SRC_JAR)
}
@@ -39,12 +39,10 @@ import org.jetbrains.kotlin.idea.configuration.KotlinJavaModuleConfigurator
import org.jetbrains.kotlin.idea.configuration.KotlinProjectConfigurator
import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator
import org.jetbrains.kotlin.idea.configuration.createConfigureKotlinNotificationCollector
import org.jetbrains.kotlin.idea.framework.getReflectJar
import org.jetbrains.kotlin.idea.framework.getRuntimeJar
import org.jetbrains.kotlin.idea.framework.getTestJar
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.idea.quickfix.quickfixUtil.createIntentionForFirstParentOfType
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
import org.jetbrains.kotlin.idea.versions.findAllUsedLibraries
import org.jetbrains.kotlin.name.FqName
@@ -55,13 +53,10 @@ import org.jetbrains.kotlin.utils.PathUtil
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import java.io.File
class AddReflectionQuickFix(element: KtElement) : AddKotlinLibQuickFix(element) {
class AddReflectionQuickFix(element: KtElement) : AddKotlinLibQuickFix(element, LibraryJarDescriptor.REFLECT_JAR) {
override fun getText() = KotlinBundle.message("add.reflection.to.classpath")
override fun getFamilyName() = text
override fun libraryPath(): String = PathUtil.KOTLIN_JAVA_REFLECT_JAR
override fun getLibFile(): File = PathUtil.getKotlinPathsForIdeaPlugin().reflectPath
override fun hasLibJarInLibrary(library: Library): Boolean = getReflectJar(library) != null
override fun getLibraryDescriptor(module: Module) = MavenExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-reflect",
AddKotlinLibQuickFix.getKotlinStdlibVersion(module))
@@ -70,13 +65,10 @@ class AddReflectionQuickFix(element: KtElement) : AddKotlinLibQuickFix(element)
}
}
class AddTestLibQuickFix(element: KtElement) : AddKotlinLibQuickFix(element) {
class AddTestLibQuickFix(element: KtElement) : AddKotlinLibQuickFix(element, LibraryJarDescriptor.TEST_JAR) {
override fun getText() = KotlinBundle.message("add.test.to.classpath")
override fun getFamilyName() = text
override fun libraryPath(): String = PathUtil.KOTLIN_TEST_JAR
override fun getLibFile(): File = PathUtil.getKotlinPathsForIdeaPlugin().kotlinTestPath
override fun hasLibJarInLibrary(library: Library): Boolean = getTestJar(library) != null
override fun getLibraryDescriptor(module: Module) = MavenExternalLibraryDescriptor("org.jetbrains.kotlin", "kotlin-test",
AddKotlinLibQuickFix.getKotlinStdlibVersion(module))
@@ -123,12 +115,13 @@ class AddTestLibQuickFix(element: KtElement) : AddKotlinLibQuickFix(element) {
}
}
abstract class AddKotlinLibQuickFix(element: KtElement) : KotlinQuickFixAction<KtElement>(element) {
protected abstract fun libraryPath(): String
protected abstract fun getLibFile(): File
protected abstract fun hasLibJarInLibrary(library: Library): Boolean
abstract class AddKotlinLibQuickFix(element: KtElement, val libraryJarDescriptor: LibraryJarDescriptor) : KotlinQuickFixAction<KtElement>(element) {
protected abstract fun getLibraryDescriptor(module: Module): MavenExternalLibraryDescriptor
fun libraryPath(): String = libraryJarDescriptor.jarName
fun getLibFile(): File = libraryJarDescriptor.getPath(PathUtil.getKotlinPathsForIdeaPlugin())
fun hasLibJarInLibrary(library: Library): Boolean = libraryJarDescriptor.findExistingJar(library) != null
class MavenExternalLibraryDescriptor(groupId: String, artifactId: String, version: String) :
ExternalLibraryDescriptor(groupId, artifactId, version, version) {
override fun getLibraryClassesRoots(): List<String> = emptyList()
@@ -162,7 +155,7 @@ abstract class AddKotlinLibQuickFix(element: KtElement) : KotlinQuickFixAction<K
val collector = createConfigureKotlinNotificationCollector(project)
for (library in findAllUsedLibraries(project).keySet()) {
val runtimeJar = getRuntimeJar(library) ?: continue
val runtimeJar = LibraryJarDescriptor.RUNTIME_JAR.findExistingJar(library) ?: continue
if (hasLibJarInLibrary(library)) continue
val model = library.modifiableModel
@@ -45,7 +45,10 @@ import com.intellij.util.text.VersionComparatorUtil
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.configuration.*
import org.jetbrains.kotlin.idea.framework.*
import org.jetbrains.kotlin.idea.framework.JavaRuntimeDetectionUtil
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider
import org.jetbrains.kotlin.idea.framework.isDetected
import org.jetbrains.kotlin.idea.framework.isExternalLibrary
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.idea.util.projectStructure.allModules
import org.jetbrains.kotlin.idea.util.runWithAlternativeResolveEnabled
@@ -55,8 +58,11 @@ import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
import org.jetbrains.kotlin.utils.JsMetadataVersion
import org.jetbrains.kotlin.utils.KotlinPaths
import org.jetbrains.kotlin.utils.LibraryUtils
import org.jetbrains.kotlin.utils.PathUtil
import java.io.File
import java.util.*
fun getLibraryRootsWithAbiIncompatibleKotlinClasses(module: Module): Collection<BinaryVersionedFile<JvmMetadataVersion>> {
return getLibraryRootsWithAbiIncompatibleVersion(module, JvmMetadataVersion.INSTANCE, KotlinJvmMetadataVersionIndex)
@@ -90,27 +96,13 @@ fun updateLibraries(project: Project, libraries: Collection<Library>) {
val collector = createConfigureKotlinNotificationCollector(project)
for (library in libraries) {
if (isDetected(JavaRuntimePresentationProvider.getInstance(), library)) {
updateJar(project, library, getRuntimeJar(library), LibraryJarDescriptor.RUNTIME_JAR)
updateJar(project, library, getReflectJar(library), LibraryJarDescriptor.REFLECT_JAR)
updateJar(project, library,getTestJar(library), LibraryJarDescriptor.TEST_JAR)
val libraryJarDescriptors = if (isDetected(JavaRuntimePresentationProvider.getInstance(), library))
kJvmConfigurator.libraryJarDescriptors
else
kJsConfigurator.libraryJarDescriptors
if (kJvmConfigurator.changeOldSourcesPathIfNeeded(library, collector)) {
kJvmConfigurator.copySourcesToPathFromLibrary(library, collector)
}
else {
updateJar(project, library, getRuntimeSrcJar(library), LibraryJarDescriptor.RUNTIME_SRC_JAR)
}
}
else if (isDetected(JSLibraryStdPresentationProvider.getInstance(), library)) {
updateJar(project, library, getJsStdLibJar(library), LibraryJarDescriptor.JS_STDLIB_JAR)
if (kJsConfigurator.changeOldSourcesPathIfNeeded(library, collector)) {
kJsConfigurator.copySourcesToPathFromLibrary(library, collector)
}
else {
updateJar(project, library, getJsStdLibSrcJar(library), LibraryJarDescriptor.JS_STDLIB_SRC_JAR)
}
for (libraryJarDescriptor in libraryJarDescriptors) {
updateJar(project, library, libraryJarDescriptor)
}
}
@@ -120,23 +112,16 @@ fun updateLibraries(project: Project, libraries: Collection<Library>) {
private fun updateJar(
project: Project,
library: Library,
fileToReplace: VirtualFile?,
libraryJarDescriptor: LibraryJarDescriptor) {
val fileToReplace = libraryJarDescriptor.findExistingJar(library)
if (fileToReplace == null && !libraryJarDescriptor.shouldExist) {
return
}
val oldUrl = fileToReplace?.url
val paths = PathUtil.getKotlinPathsForIdeaPlugin()
val jarPath: File = when (libraryJarDescriptor) {
LibraryJarDescriptor.RUNTIME_JAR -> paths.stdlibPath
LibraryJarDescriptor.REFLECT_JAR -> paths.reflectPath
LibraryJarDescriptor.SCRIPT_RUNTIME_JAR -> paths.scriptRuntimePath
LibraryJarDescriptor.TEST_JAR -> paths.kotlinTestPath
LibraryJarDescriptor.RUNTIME_SRC_JAR -> paths.runtimeSourcesPath
LibraryJarDescriptor.JS_STDLIB_JAR -> paths.jsStdLibJarPath
LibraryJarDescriptor.JS_STDLIB_SRC_JAR -> paths.jsStdLibSrcJarPath
}
val jarPath: File = libraryJarDescriptor.getPath(paths)
if (!jarPath.exists()) {
showRuntimeJarNotFoundDialog(project, libraryJarDescriptor.jarName)
@@ -178,14 +163,28 @@ fun findAllUsedLibraries(project: Project): MultiMap<Library, Module> {
return libraries
}
private enum class LibraryJarDescriptor(val jarName: String, val shouldExist: Boolean) {
RUNTIME_JAR(PathUtil.KOTLIN_JAVA_STDLIB_JAR, true),
REFLECT_JAR(PathUtil.KOTLIN_JAVA_REFLECT_JAR, false),
SCRIPT_RUNTIME_JAR(PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR, true),
TEST_JAR(PathUtil.KOTLIN_TEST_JAR, false),
RUNTIME_SRC_JAR(PathUtil.KOTLIN_JAVA_RUNTIME_SRC_JAR, false),
JS_STDLIB_JAR(PathUtil.JS_LIB_JAR_NAME, true),
JS_STDLIB_SRC_JAR(PathUtil.JS_LIB_SRC_JAR_NAME, false)
enum class LibraryJarDescriptor(val jarName: String,
val orderRootType: OrderRootType,
val shouldExist: Boolean,
val getPath: (KotlinPaths) -> File) {
RUNTIME_JAR(PathUtil.KOTLIN_JAVA_STDLIB_JAR, OrderRootType.CLASSES, true, KotlinPaths::getStdlibPath) {
override fun findExistingJar(library: Library): VirtualFile? {
if (isExternalLibrary(library)) return null
return JavaRuntimeDetectionUtil.getRuntimeJar(Arrays.asList(*library.getFiles(OrderRootType.CLASSES)))
}
},
REFLECT_JAR(PathUtil.KOTLIN_JAVA_REFLECT_JAR, OrderRootType.CLASSES, false, KotlinPaths::getReflectPath),
SCRIPT_RUNTIME_JAR(PathUtil.KOTLIN_JAVA_SCRIPT_RUNTIME_JAR, OrderRootType.CLASSES, true, KotlinPaths::getScriptRuntimePath),
TEST_JAR(PathUtil.KOTLIN_TEST_JAR, OrderRootType.CLASSES, false, KotlinPaths::getKotlinTestPath),
RUNTIME_SRC_JAR(PathUtil.KOTLIN_JAVA_RUNTIME_SRC_JAR, OrderRootType.SOURCES, false, KotlinPaths::getRuntimeSourcesPath),
JS_STDLIB_JAR(PathUtil.JS_LIB_JAR_NAME, OrderRootType.CLASSES, true, KotlinPaths::getJsStdLibJarPath),
JS_STDLIB_SRC_JAR(PathUtil.JS_LIB_SRC_JAR_NAME, OrderRootType.SOURCES, false, KotlinPaths::getJsStdLibSrcJarPath);
open fun findExistingJar(library: Library): VirtualFile? {
if (isExternalLibrary(library)) return null
return LibraryUtils.getJarFile(Arrays.asList(*library.getFiles(orderRootType)), jarName)
}
}
fun bundledRuntimeVersion(): String {
@@ -30,7 +30,10 @@ import com.intellij.openapi.roots.libraries.Library
import com.intellij.util.PathUtil.getLocalFile
import com.intellij.util.text.VersionComparatorUtil
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.framework.*
import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider
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 java.io.IOException
import javax.swing.event.HyperlinkEvent
@@ -149,7 +152,7 @@ private fun suggestDeleteKotlinJsIfNeeded(project: Project, outdatedLibraries: C
var addNotification = false
for (library in outdatedLibraries) {
if (isDetected(JSLibraryStdPresentationProvider.getInstance(), library)) {
val jsStdlibJar = getJsStdLibJar(library)
val jsStdlibJar = LibraryJarDescriptor.JS_STDLIB_JAR.findExistingJar(library)
assert(jsStdlibJar != null) { "jslibFile should not be null" }
if (jsStdlibJar!!.findFileByRelativePath("kotlin.js") == null) {
@@ -47,10 +47,6 @@ import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.KotlinPluginUpdater
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.PluginUpdateStatus
import org.jetbrains.kotlin.idea.framework.getJsStdLibJar
import org.jetbrains.kotlin.idea.framework.getReflectJar
import org.jetbrains.kotlin.idea.framework.getRuntimeJar
import org.jetbrains.kotlin.idea.framework.getTestJar
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
@@ -88,8 +84,8 @@ class UnsupportedAbiVersionNotificationPanelProvider(private val project: Projec
val kotlinLibraries = findAllUsedLibraries(project).keySet()
val badRuntimeLibraries = kotlinLibraries.filter { library ->
val runtimeJar = getLocalJar(getRuntimeJar(library))
val jsLibJar = getLocalJar(getJsStdLibJar(library))
val runtimeJar = getLocalJar(LibraryJarDescriptor.RUNTIME_JAR.findExistingJar(library))
val jsLibJar = getLocalJar(LibraryJarDescriptor.JS_STDLIB_JAR.findExistingJar(library))
badRootFiles.contains(runtimeJar) || badRootFiles.contains(jsLibJar)
}
@@ -262,10 +258,9 @@ class UnsupportedAbiVersionNotificationPanelProvider(private val project: Projec
}
badRuntimeLibraries.forEach { library ->
addToBadRoots(getLocalJar(getRuntimeJar(library)))
addToBadRoots(getLocalJar(getJsStdLibJar(library)))
addToBadRoots(getLocalJar(getReflectJar(library)))
addToBadRoots(getLocalJar(getTestJar(library)))
for (descriptor in LibraryJarDescriptor.values()) {
addToBadRoots(getLocalJar(descriptor.findExistingJar(library)))
}
}
return badRootsInLibraries