Fixed KT-2001 Create warning when Kotlin runtime is outdated relative to plugin

#KT-2001 fixed
This commit is contained in:
Evgeny Gerashchenko
2012-05-23 16:25:29 +04:00
parent ba435d3777
commit e2d4578c3e
@@ -0,0 +1,166 @@
package org.jetbrains.jet.plugin;/*
* Copyright 2010-2012 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.
*/
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;
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 javax.swing.event.HyperlinkEvent;
import java.io.File;
import java.io.IOException;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
/**
* @author Evgeny Gerashchenko
* @since 5/22/12
*/
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) {
super(project);
}
@Override
public void projectOpened() {
if (ApplicationManager.getApplication().isInternal()) return;
String runtimeVersion = getRuntimeVersion();
final String pluginVersion = 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
// user already clicked suppress
if (pluginVersion.equals(PropertiesComponent.getInstance(myProject).getValue(SUPPRESSED_PROPERTY_NAME))) return;
boolean isRuntimeOutdated = "snapshot".equals(runtimeVersion)
|| UNKNOWN_VERSION.equals(runtimeVersion)
|| runtimeVersion.startsWith("internal-") != pluginVersion.startsWith("internal-")
|| VersionComparatorUtil.compare(pluginVersion, runtimeVersion) > 0;
if (!isRuntimeOutdated) return;
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);
Notifications.Bus.notify(new Notification("Outdated Kotlin Runtime", "Outdated Kotlin Runtime",
message,
NotificationType.WARNING, new NotificationListener() {
@Override
public void hyperlinkUpdate(@NotNull Notification notification, @NotNull HyperlinkEvent event) {
if (event.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {
if ("update".equals(event.getDescription())) {
updateRuntime();
}
else if ("ignore".equals(event.getDescription())) {
PropertiesComponent.getInstance(myProject).setValue(SUPPRESSED_PROPERTY_NAME, pluginVersion);
}
else {
throw new AssertionError();
}
notification.expire();
}
}
}), myProject);
}
private void updateRuntime() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
File runtimePath = PathUtil.getDefaultRuntimePath();
if (runtimePath == null) {
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();
}
}