Common library-related logic is extracted from UI classes to a util class

This commit is contained in:
Andrey Breslav
2013-01-24 16:09:10 +04:00
parent 41dd4b29ae
commit fb80e64e6b
5 changed files with 310 additions and 230 deletions
@@ -17,6 +17,9 @@
package org.jetbrains.jet.plugin;
import com.google.common.collect.Lists;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
@@ -72,4 +75,11 @@ public class JetPluginUtil {
}
return libraryScope == ((NamespaceDescriptor) declaration).getMemberScope();
}
@NotNull
public static String getPluginVersion() {
IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginId.getId("org.jetbrains.kotlin"));
assert plugin != null : "How can it be? Kotlin plugin is available, but its component is running. Complete nonsense.";
return plugin.getVersion();
}
}
@@ -52,7 +52,7 @@ public class AbsentJdkAnnotationsNotifications extends EditorNotifications.Provi
GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(false);
if (JavaPsiFacade.getInstance(project).findClass("jet.JetObject", scope) == null) return null;
if (ConfigureKotlinLibraryNotificationProvider.jdkAnnotationsArePresent(module)) return null;
if (KotlinRuntimeLibraryUtil.jdkAnnotationsArePresent(module)) return null;
Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
if (sdk == null) return null;
@@ -62,7 +62,7 @@ public class AbsentJdkAnnotationsNotifications extends EditorNotifications.Provi
panel.createActionLabel("Set up Kotlin JDK annotations", new Runnable() {
@Override
public void run() {
ConfigureKotlinLibraryNotificationProvider.addJdkAnnotations(module);
KotlinRuntimeLibraryUtil.addJdkAnnotations(module);
}
});
@@ -28,46 +28,24 @@ import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.progress.ProcessCanceledException;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.roots.AnnotationOrderRootType;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.EditorNotificationPanel;
import com.intellij.ui.EditorNotifications;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.plugin.JetFileType;
import org.jetbrains.jet.utils.PathUtil;
import javax.swing.*;
import java.io.File;
import java.io.IOException;
import static org.jetbrains.jet.plugin.project.JsModuleDetector.isJsModule;
public class ConfigureKotlinLibraryNotificationProvider extends EditorNotifications.Provider<EditorNotificationPanel> {
private static final Key<EditorNotificationPanel> KEY = Key.create("configure.kotlin.library");
public static final String LIBRARY_NAME = "KotlinRuntime";
public static final String KOTLIN_RUNTIME_JAR = "kotlin-runtime.jar";
private final Project myProject;
public ConfigureKotlinLibraryNotificationProvider(Project project) {
@@ -90,7 +68,7 @@ public class ConfigureKotlinLibraryNotificationProvider extends EditorNotificati
final Module module = ModuleUtilCore.findModuleForFile(file, myProject);
if (module == null) return null;
if (!isModuleAlreadyConfigured(module)) {
if (!KotlinRuntimeLibraryUtil.isModuleAlreadyConfigured(module)) {
return createNotificationPanel(module);
}
}
@@ -104,57 +82,6 @@ public class ConfigureKotlinLibraryNotificationProvider extends EditorNotificati
return null;
}
private Library findOrCreateRuntimeLibrary() {
LibraryTable table = ProjectLibraryTable.getInstance(myProject);
Library kotlinRuntime = table.getLibraryByName(LIBRARY_NAME);
if (kotlinRuntime != null) {
for (VirtualFile root : kotlinRuntime.getFiles(OrderRootType.CLASSES)) {
if (root.getName().equals(KOTLIN_RUNTIME_JAR)) {
return kotlinRuntime;
}
}
}
File runtimePath = PathUtil.getKotlinPathsForIdeaPlugin().getRuntimePath();
if (!runtimePath.exists()) {
Messages.showErrorDialog(myProject, "kotlin-runtime.jar is not found. Make sure plugin is properly installed.",
"No Runtime Found");
return null;
}
ChoosePathDialog dlg = new ChoosePathDialog(myProject);
dlg.show();
if (!dlg.isOK()) return null;
String path = dlg.getPath();
final File targetJar = new File(path, "kotlin-runtime.jar");
try {
FileUtil.copy(runtimePath, targetJar);
VirtualFile jarVfs = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(targetJar);
if (jarVfs != null) {
jarVfs.refresh(false, false);
}
}
catch (IOException e) {
Messages.showErrorDialog(myProject, "Error copying jar: " + e.getLocalizedMessage(), "Error Copying File");
return null;
}
if (kotlinRuntime == null) {
kotlinRuntime = table.createLibrary("KotlinRuntime");
}
final Library finalKotlinRuntime = kotlinRuntime;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
public void run() {
Library.ModifiableModel model = finalKotlinRuntime.getModifiableModel();
model.addRoot(VfsUtil.getUrlForLibraryRoot(targetJar), OrderRootType.CLASSES);
model.addRoot(VfsUtil.getUrlForLibraryRoot(targetJar) + "src", OrderRootType.SOURCES);
model.commit();
}
});
return kotlinRuntime;
}
private EditorNotificationPanel createNotificationPanel(final Module module) {
final EditorNotificationPanel answer = new EditorNotificationPanel();
@@ -163,7 +90,7 @@ public class ConfigureKotlinLibraryNotificationProvider extends EditorNotificati
answer.createActionLabel("Set up module '" + module.getName() + "' as JVM Kotlin module", new Runnable() {
@Override
public void run() {
setUpKotlinRuntime(module);
setUpJavaModule(module);
}
});
@@ -177,6 +104,18 @@ public class ConfigureKotlinLibraryNotificationProvider extends EditorNotificati
return answer;
}
private void setUpJavaModule(Module module) {
Library library = KotlinRuntimeLibraryUtil.findOrCreateRuntimeLibrary(myProject, new UiFindRuntimeLibraryHandler());
if (library == null) return;
KotlinRuntimeLibraryUtil.setUpKotlinRuntimeLibrary(module, library, new Runnable() {
@Override
public void run() {
updateNotifications();
}
});
}
private void setUpJSModule(@NotNull Module module) {
JsModuleSetUp.doSetUpModule(module, new Runnable() {
@Override
@@ -186,56 +125,6 @@ public class ConfigureKotlinLibraryNotificationProvider extends EditorNotificati
});
}
private void setUpKotlinRuntime(@NotNull final Module module) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
Library library = findOrCreateRuntimeLibrary();
if (library != null) {
ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
if (model.findLibraryOrderEntry(library) == null) {
model.addLibraryEntry(library);
model.commit();
}
else {
model.dispose();
}
updateNotifications();
}
if (!jdkAnnotationsArePresent(module)) {
addJdkAnnotations(module);
}
}
});
}
/* package */ static void addJdkAnnotations(Module module) {
Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
assert sdk != null;
File annotationsIoFile = PathUtil.getKotlinPathsForIdeaPlugin().getJdkAnnotationsPath();
if (annotationsIoFile.exists()) {
VirtualFile jdkAnnotationsJar = LocalFileSystem.getInstance().findFileByIoFile(annotationsIoFile);
if (jdkAnnotationsJar != null) {
SdkModificator modificator = sdk.getSdkModificator();
modificator.addRoot(JarFileSystem.getInstance().getJarRootForLocalFile(jdkAnnotationsJar),
AnnotationOrderRootType.getInstance());
modificator.commitChanges();
}
}
}
/* package */ static boolean jdkAnnotationsArePresent(Module module) {
Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
if (sdk == null) return false;
return ContainerUtil.exists(sdk.getRootProvider().getFiles(AnnotationOrderRootType.getInstance()),
new Condition<VirtualFile>() {
@Override
public boolean value(VirtualFile file) {
return PathUtil.JDK_ANNOTATIONS_JAR.equals(file.getName());
}
});
}
private void updateNotifications() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
@@ -245,22 +134,6 @@ public class ConfigureKotlinLibraryNotificationProvider extends EditorNotificati
});
}
private boolean isModuleAlreadyConfigured(Module module) {
return isMavenModule(module) || isJsModule(module) || isWithJavaModule(module);
}
private boolean isWithJavaModule(Module module) {
// Can find a reference to kotlin class in module scope
GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(false);
return (JavaPsiFacade.getInstance(myProject).findClass(JvmStdlibNames.JET_OBJECT.getFqName().getFqName(), scope) != null);
}
private static boolean isMavenModule(@NotNull Module module) {
// This constant could be acquired from MavenProjectsManager, but we don't want to depend on the Maven plugin...
// See MavenProjectsManager.isMavenizedModule()
return "true".equals(module.getOptionValue("org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule"));
}
private static class ChoosePathDialog extends DialogWrapper {
private final Project myProject;
private TextFieldWithBrowseButton myPathField;
@@ -293,4 +166,27 @@ public class ConfigureKotlinLibraryNotificationProvider extends EditorNotificati
return myPathField.getText();
}
}
private class UiFindRuntimeLibraryHandler extends KotlinRuntimeLibraryUtil.FindRuntimeLibraryHandler {
@Override
public void runtimePathDoesNotExist(@NotNull File path) {
Messages.showErrorDialog(myProject,
"kotlin-runtime.jar is not found at " + path + ". Make sure plugin is properly installed.",
"No Runtime Found");
}
@Override
public File getRuntimeJarPath() {
ChoosePathDialog dlg = new ChoosePathDialog(myProject);
dlg.show();
if (!dlg.isOK()) return null;
String path = dlg.getPath();
return new File(path, "kotlin-runtime.jar");
}
@Override
public void ioExceptionOnCopyingJar(@NotNull IOException e) {
Messages.showErrorDialog(myProject, "Error copying jar: " + e.getLocalizedMessage(), "Error Copying File");
}
}
}
@@ -0,0 +1,247 @@
/*
* Copyright 2010-2013 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.jet.plugin.quickfix;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkModificator;
import com.intellij.openapi.roots.AnnotationOrderRootType;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.util.Condition;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VfsUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.impl.elements.ManifestFileUtil;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames;
import org.jetbrains.jet.utils.PathUtil;
import java.io.File;
import java.io.IOException;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import static org.jetbrains.jet.plugin.project.JsModuleDetector.isJsModule;
public class KotlinRuntimeLibraryUtil {
public static final String LIBRARY_NAME = "KotlinRuntime";
public static final String KOTLIN_RUNTIME_JAR = "kotlin-runtime.jar";
public static final String UNKNOWN_VERSION = "UNKNOWN";
private KotlinRuntimeLibraryUtil() {}
public static void addJdkAnnotations(@NotNull Module module) {
Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
assert sdk != null;
File annotationsIoFile = PathUtil.getKotlinPathsForIdeaPlugin().getJdkAnnotationsPath();
if (annotationsIoFile.exists()) {
VirtualFile jdkAnnotationsJar = LocalFileSystem.getInstance().findFileByIoFile(annotationsIoFile);
if (jdkAnnotationsJar != null) {
SdkModificator modificator = sdk.getSdkModificator();
modificator.addRoot(JarFileSystem.getInstance().getJarRootForLocalFile(jdkAnnotationsJar),
AnnotationOrderRootType.getInstance());
modificator.commitChanges();
}
}
}
public static boolean jdkAnnotationsArePresent(@NotNull Module module) {
Sdk sdk = ModuleRootManager.getInstance(module).getSdk();
if (sdk == null) return false;
return ContainerUtil.exists(sdk.getRootProvider().getFiles(AnnotationOrderRootType.getInstance()),
new Condition<VirtualFile>() {
@Override
public boolean value(VirtualFile file) {
return PathUtil.JDK_ANNOTATIONS_JAR.equals(file.getName());
}
});
}
public static boolean isModuleAlreadyConfigured(Module module) {
return isMavenModule(module) || isJsModule(module) || isWithJavaModule(module);
}
private static boolean isMavenModule(@NotNull Module module) {
// This constant could be acquired from MavenProjectsManager, but we don't want to depend on the Maven plugin...
// See MavenProjectsManager.isMavenizedModule()
return "true".equals(module.getOptionValue("org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule"));
}
private static boolean isWithJavaModule(Module module) {
// Can find a reference to kotlin class in module scope
GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(false);
return (JavaPsiFacade.getInstance(module.getProject()).findClass(JvmStdlibNames.JET_OBJECT.getFqName().getFqName(), scope) != null);
}
static void setUpKotlinRuntimeLibrary(
@NotNull final Module module,
@NotNull final Library library,
@NotNull final Runnable afterSetUp
) {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
ModifiableRootModel model = ModuleRootManager.getInstance(module).getModifiableModel();
if (model.findLibraryOrderEntry(library) == null) {
model.addLibraryEntry(library);
model.commit();
}
else {
model.dispose();
}
afterSetUp.run();
if (!jdkAnnotationsArePresent(module)) {
addJdkAnnotations(module);
}
}
});
}
@Nullable
static Library findOrCreateRuntimeLibrary(@NotNull Project project, @NotNull FindRuntimeLibraryHandler handler) {
LibraryTable table = ProjectLibraryTable.getInstance(project);
Library kotlinRuntime = table.getLibraryByName(LIBRARY_NAME);
if (kotlinRuntime != null) {
for (VirtualFile root : kotlinRuntime.getFiles(OrderRootType.CLASSES)) {
if (root.getName().equals(KOTLIN_RUNTIME_JAR)) {
return kotlinRuntime;
}
}
}
File runtimePath = PathUtil.getKotlinPathsForIdeaPlugin().getRuntimePath();
if (!runtimePath.exists()) {
handler.runtimePathDoesNotExist(runtimePath);
return null;
}
final File targetJar = handler.getRuntimeJarPath();
if (targetJar == null) return null;
try {
FileUtil.copy(runtimePath, targetJar);
VirtualFile jarVfs = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(targetJar);
if (jarVfs != null) {
jarVfs.refresh(false, false);
}
}
catch (IOException e) {
handler.ioExceptionOnCopyingJar(e);
return null;
}
if (kotlinRuntime == null) {
kotlinRuntime = table.createLibrary("KotlinRuntime");
}
final Library finalKotlinRuntime = kotlinRuntime;
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
Library.ModifiableModel model = finalKotlinRuntime.getModifiableModel();
model.addRoot(VfsUtil.getUrlForLibraryRoot(targetJar), OrderRootType.CLASSES);
model.addRoot(VfsUtil.getUrlForLibraryRoot(targetJar) + "src", OrderRootType.SOURCES);
model.commit();
}
});
return kotlinRuntime;
}
public static void updateRuntime(
@NotNull final Project project,
@NotNull final Runnable jarNotFoundHandler
) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
File runtimePath = PathUtil.getKotlinPathsForIdeaPlugin().getRuntimePath();
if (!runtimePath.exists()) {
jarNotFoundHandler.run();
return;
}
VirtualFile runtimeJar = getKotlinRuntimeJar(project);
assert runtimeJar != null;
VirtualFile jarFile = JarFileSystem.getInstance().getVirtualFileForJar(runtimeJar);
if (jarFile != null) {
runtimeJar = jarFile;
}
try {
FileUtil.copy(runtimePath, new File(runtimeJar.getPath()));
}
catch (IOException e) {
throw new AssertionError(e);
}
runtimeJar.refresh(true, true);
}
});
}
@Nullable
public static String getRuntimeVersion(@NotNull Project project) {
VirtualFile kotlinRuntimeJar = getKotlinRuntimeJar(project);
if (kotlinRuntimeJar == null) return null;
VirtualFile manifestFile = kotlinRuntimeJar.findFileByRelativePath(JarFile.MANIFEST_NAME);
if (manifestFile != null) {
Attributes attributes = ManifestFileUtil.readManifest(manifestFile).getMainAttributes();
if (attributes.containsKey(Attributes.Name.IMPLEMENTATION_VERSION)) {
return attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
}
}
return UNKNOWN_VERSION;
}
@Nullable
private static VirtualFile getKotlinRuntimeJar(@NotNull Project project) {
LibraryTable table = ProjectLibraryTable.getInstance(project);
Library kotlinRuntime = table.getLibraryByName(LIBRARY_NAME);
if (kotlinRuntime != null) {
for (VirtualFile root : kotlinRuntime.getFiles(OrderRootType.CLASSES)) {
if (root.getName().equals(KOTLIN_RUNTIME_JAR)) {
return root;
}
}
}
return null;
}
public static abstract class FindRuntimeLibraryHandler {
@Nullable
public abstract File getRuntimeJarPath();
public void runtimePathDoesNotExist(@NotNull File path) {
}
public void ioExceptionOnCopyingJar(@NotNull IOException e) {
}
}
}
@@ -14,8 +14,6 @@ package org.jetbrains.jet.plugin.versions;/*
* limitations under the License.
*/
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
@@ -23,31 +21,16 @@ import com.intellij.notification.NotificationType;
import com.intellij.notification.Notifications;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.components.AbstractProjectComponent;
import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.OrderRootType;
import com.intellij.openapi.roots.impl.libraries.ProjectLibraryTable;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.LibraryTable;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.packaging.impl.elements.ManifestFileUtil;
import com.intellij.util.text.VersionComparatorUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.plugin.quickfix.ConfigureKotlinLibraryNotificationProvider;
import org.jetbrains.jet.utils.PathUtil;
import org.jetbrains.jet.plugin.JetPluginUtil;
import org.jetbrains.jet.plugin.quickfix.KotlinRuntimeLibraryUtil;
import javax.swing.event.HyperlinkEvent;
import java.io.File;
import java.io.IOException;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
public class OutdatedKotlinRuntimeNotification extends AbstractProjectComponent {
private static final String UNKNOWN_VERSION = "UNKNOWN";
private static final String SUPPRESSED_PROPERTY_NAME = "oudtdated.runtime.suppressed.plugin.version";
public OutdatedKotlinRuntimeNotification(final Project project) {
@@ -57,8 +40,8 @@ public class OutdatedKotlinRuntimeNotification extends AbstractProjectComponent
@Override
public void projectOpened() {
if (ApplicationManager.getApplication().isInternal()) return;
String runtimeVersion = getRuntimeVersion();
final String pluginVersion = getPluginVersion();
String runtimeVersion = KotlinRuntimeLibraryUtil.getRuntimeVersion(myProject);
final String pluginVersion = JetPluginUtil.getPluginVersion();
if (runtimeVersion == null) return; // runtime is not present in project
if ("@snapshot@".equals(pluginVersion)) return; // plugin is run from sources, can't compare versions
@@ -66,7 +49,7 @@ public class OutdatedKotlinRuntimeNotification extends AbstractProjectComponent
if (pluginVersion.equals(PropertiesComponent.getInstance(myProject).getValue(SUPPRESSED_PROPERTY_NAME))) return;
boolean isRuntimeOutdated = "snapshot".equals(runtimeVersion)
|| UNKNOWN_VERSION.equals(runtimeVersion)
|| KotlinRuntimeLibraryUtil.UNKNOWN_VERSION.equals(runtimeVersion)
|| runtimeVersion.startsWith("internal-") != pluginVersion.startsWith("internal-")
|| VersionComparatorUtil.compare(pluginVersion, runtimeVersion) > 0;
@@ -75,7 +58,7 @@ public class OutdatedKotlinRuntimeNotification extends AbstractProjectComponent
String message = String.format("<p>Your version of Kotlin runtime library is %s, while plugin version is %s." +
" Runtime library should be updated to avoid compatibility problems.</p>" +
"<p><a href=\"update\">Update Runtime</a> <a href=\"ignore\">Ignore</a></p>",
UNKNOWN_VERSION.equals(runtimeVersion) ? "older than 0.1.2296" : runtimeVersion, pluginVersion);
KotlinRuntimeLibraryUtil.UNKNOWN_VERSION.equals(runtimeVersion) ? "older than 0.1.2296" : runtimeVersion, pluginVersion);
Notifications.Bus.notify(new Notification("Outdated Kotlin Runtime", "Outdated Kotlin Runtime",
message,
NotificationType.WARNING, new NotificationListener() {
@@ -83,7 +66,14 @@ public class OutdatedKotlinRuntimeNotification extends AbstractProjectComponent
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
if ("update".equals(event.getDescription())) {
updateRuntime();
KotlinRuntimeLibraryUtil.updateRuntime(myProject, new Runnable() {
@Override
public void run() {
Messages.showErrorDialog(myProject,
"kotlin-runtime.jar is not found. Make sure plugin is properly installed.",
"No Runtime Found");
}
});
}
else if ("ignore".equals(event.getDescription())) {
PropertiesComponent.getInstance(myProject).setValue(SUPPRESSED_PROPERTY_NAME, pluginVersion);
@@ -95,68 +85,5 @@ public class OutdatedKotlinRuntimeNotification extends AbstractProjectComponent
}
}
}), myProject);
}
private void updateRuntime() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
File runtimePath = PathUtil.getKotlinPathsForIdeaPlugin().getRuntimePath();
if (!runtimePath.exists()) {
Messages.showErrorDialog(myProject, "kotlin-runtime.jar is not found. Make sure plugin is properly installed.",
"No Runtime Found");
return;
}
VirtualFile runtimeJar = getKotlinRuntimeJar();
assert runtimeJar != null;
VirtualFile jarFile = JarFileSystem.getInstance().getVirtualFileForJar(runtimeJar);
if (jarFile != null) {
runtimeJar = jarFile;
}
try {
FileUtil.copy(runtimePath, new File(runtimeJar.getPath()));
}
catch (IOException e) {
throw new AssertionError(e);
}
runtimeJar.refresh(true, true);
}
});
}
@Nullable
private String getRuntimeVersion() {
VirtualFile kotlinRuntimeJar = getKotlinRuntimeJar();
if (kotlinRuntimeJar == null) return null;
VirtualFile manifestFile = kotlinRuntimeJar.findFileByRelativePath(JarFile.MANIFEST_NAME);
if (manifestFile != null) {
Attributes attributes = ManifestFileUtil.readManifest(manifestFile).getMainAttributes();
if (attributes.containsKey(Attributes.Name.IMPLEMENTATION_VERSION)) {
return attributes.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
}
}
return UNKNOWN_VERSION;
}
@Nullable
private VirtualFile getKotlinRuntimeJar() {
LibraryTable table = ProjectLibraryTable.getInstance(myProject);
Library kotlinRuntime = table.getLibraryByName(ConfigureKotlinLibraryNotificationProvider.LIBRARY_NAME);
if (kotlinRuntime != null) {
for (VirtualFile root : kotlinRuntime.getFiles(OrderRootType.CLASSES)) {
if (root.getName().equals(ConfigureKotlinLibraryNotificationProvider.KOTLIN_RUNTIME_JAR)) {
return root;
}
}
}
return null;
}
@NotNull
private static String getPluginVersion() {
IdeaPluginDescriptor plugin = PluginManager.getPlugin(PluginId.getId("org.jetbrains.kotlin"));
assert plugin != null : "How can it be? Kotlin plugin is available, but its component is running. Complete nonsense.";
return plugin.getVersion();
}
}