Common library-related logic is extracted from UI classes to a util class
This commit is contained in:
@@ -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);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+37
-141
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user