OutdatedKotlinRuntimeNotification: J2K and cleanup
This commit is contained in:
@@ -25,6 +25,7 @@ import com.intellij.openapi.roots.LibraryOrderEntry
|
||||
import com.intellij.openapi.roots.ModuleRootManager
|
||||
import com.intellij.openapi.roots.ProjectFileIndex
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.ui.Messages
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.JarFileSystem
|
||||
@@ -45,7 +46,6 @@ import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider
|
||||
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider
|
||||
import org.jetbrains.kotlin.idea.framework.LibraryPresentationProviderUtil
|
||||
import org.jetbrains.kotlin.idea.project.ProjectStructureUtil
|
||||
import org.jetbrains.kotlin.idea.versions.OutdatedKotlinRuntimeNotification.showRuntimeJarNotFoundDialog
|
||||
import org.jetbrains.kotlin.serialization.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.utils.KotlinJavascriptMetadataUtils
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
@@ -122,7 +122,7 @@ private fun updateJar(
|
||||
}
|
||||
|
||||
if (!jarPath.exists()) {
|
||||
showRuntimeJarNotFoundDialog(project, libraryJarDescriptor.jarName).run()
|
||||
showRuntimeJarNotFoundDialog(project, libraryJarDescriptor.jarName)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -258,3 +258,9 @@ private fun <T> collectAllKeys(id: ID<T, Void>, modules: List<Module>): Collecti
|
||||
|
||||
return allKeys
|
||||
}
|
||||
|
||||
fun showRuntimeJarNotFoundDialog(project: Project, jarName: String) {
|
||||
Messages.showErrorDialog(project,
|
||||
jarName + " is not found. Make sure plugin is properly installed.",
|
||||
"No Runtime Found")
|
||||
}
|
||||
|
||||
+142
-229
@@ -14,263 +14,176 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.idea.versions;
|
||||
package org.jetbrains.kotlin.idea.versions
|
||||
|
||||
import com.google.common.collect.Collections2;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.intellij.framework.library.LibraryVersionProperties;
|
||||
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.project.Project;
|
||||
import com.intellij.openapi.roots.libraries.Library;
|
||||
import com.intellij.openapi.startup.StartupManager;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.text.VersionComparatorUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUtil;
|
||||
import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider;
|
||||
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider;
|
||||
import org.jetbrains.kotlin.idea.framework.LibraryPresentationProviderUtil;
|
||||
import com.google.common.collect.Lists
|
||||
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.project.Project
|
||||
import com.intellij.openapi.roots.libraries.Library
|
||||
import com.intellij.openapi.startup.StartupManager
|
||||
import com.intellij.util.PathUtil.getLocalFile
|
||||
import com.intellij.util.text.VersionComparatorUtil
|
||||
import org.jetbrains.kotlin.idea.KotlinPluginUtil
|
||||
import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider
|
||||
import org.jetbrains.kotlin.idea.framework.JavaRuntimePresentationProvider
|
||||
import org.jetbrains.kotlin.idea.framework.LibraryPresentationProviderUtil
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import java.io.IOException
|
||||
import javax.swing.event.HyperlinkEvent
|
||||
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
class OutdatedKotlinRuntimeNotification(project: Project) : AbstractProjectComponent(project) {
|
||||
|
||||
import static com.intellij.util.PathUtil.getLocalFile;
|
||||
private data class VersionedLibrary(val library: Library, val version: String?)
|
||||
|
||||
public class OutdatedKotlinRuntimeNotification extends AbstractProjectComponent {
|
||||
private static final String SUPPRESSED_PROPERTY_NAME = "oudtdated.runtime.suppressed.plugin.version";
|
||||
private static final String OUTDATED_RUNTIME_GROUP_DISPLAY_ID = "Outdated Kotlin Runtime";
|
||||
override fun projectOpened() {
|
||||
StartupManager.getInstance(myProject).registerPostStartupActivity(Runnable {
|
||||
val pluginVersion = KotlinPluginUtil.getPluginVersion()
|
||||
if ("@snapshot@" == pluginVersion) return@Runnable // plugin is run from sources, can't compare versions
|
||||
|
||||
public OutdatedKotlinRuntimeNotification(Project project) {
|
||||
super(project);
|
||||
}
|
||||
// user already clicked suppress
|
||||
if (pluginVersion == PropertiesComponent.getInstance(myProject).getValue(SUPPRESSED_PROPERTY_NAME)) return@Runnable
|
||||
|
||||
private static class VersionedLibrary extends Pair<Library, String> {
|
||||
public VersionedLibrary(@NotNull Library library, @Nullable String version) {
|
||||
super(library, version);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Library getLibrary() {
|
||||
return first;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getVersion() {
|
||||
return second;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void projectOpened() {
|
||||
StartupManager.getInstance(myProject).registerPostStartupActivity(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final String pluginVersion = KotlinPluginUtil.getPluginVersion();
|
||||
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;
|
||||
|
||||
Collection<VersionedLibrary> versionedOutdatedLibraries = findOutdatedKotlinLibraries(myProject);
|
||||
if (versionedOutdatedLibraries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Collection<Library> outdatedLibraries = extractLibraries(versionedOutdatedLibraries);
|
||||
|
||||
String message;
|
||||
if (versionedOutdatedLibraries.size() == 1) {
|
||||
VersionedLibrary versionedLibrary = versionedOutdatedLibraries.iterator().next();
|
||||
|
||||
String version = versionedLibrary.getVersion();
|
||||
String readableVersion = version == null ? "unknown" : version;
|
||||
String libraryName = versionedLibrary.getLibrary().getName();
|
||||
|
||||
message = String.format(
|
||||
"<p>Your version of Kotlin runtime in '%s' library is %s, while plugin version is %s.</p>" +
|
||||
"<p>Runtime library should be updated to avoid compatibility problems.</p>" +
|
||||
"<p><a href=\"update\">Update Runtime</a> <a href=\"ignore\">Ignore</a></p>",
|
||||
libraryName,
|
||||
readableVersion,
|
||||
pluginVersion);
|
||||
}
|
||||
else {
|
||||
String libraryNames = StringUtil.join(outdatedLibraries, new Function<Library, String>() {
|
||||
@Override
|
||||
public String fun(Library library) {
|
||||
return library.getName();
|
||||
}
|
||||
}, ", ");
|
||||
|
||||
message = String.format(
|
||||
"<p>Version of Kotlin runtime is outdated in several libraries (%s). Plugin version is %s.</p>" +
|
||||
"<p>Runtime libraries should be updated to avoid compatibility problems.</p>" +
|
||||
"<p><a href=\"update\">Update All</a> <a href=\"ignore\">Ignore</a></p>",
|
||||
libraryNames,
|
||||
pluginVersion);
|
||||
}
|
||||
|
||||
|
||||
Notifications.Bus.notify(new Notification(OUTDATED_RUNTIME_GROUP_DISPLAY_ID, "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())) {
|
||||
Collection<VersionedLibrary> versionedOutdatedLibraries = findOutdatedKotlinLibraries(myProject);
|
||||
Collection<Library> outdatedLibraries = extractLibraries(versionedOutdatedLibraries);
|
||||
KotlinRuntimeLibraryUtilKt.updateLibraries(myProject, outdatedLibraries);
|
||||
suggestDeleteKotlinJsIfNeeded(outdatedLibraries);
|
||||
}
|
||||
else if ("ignore".equals(event.getDescription())) {
|
||||
PropertiesComponent.getInstance(myProject).setValue(SUPPRESSED_PROPERTY_NAME, pluginVersion);
|
||||
}
|
||||
else {
|
||||
throw new AssertionError();
|
||||
}
|
||||
notification.expire();
|
||||
}
|
||||
}
|
||||
}), myProject);
|
||||
val versionedOutdatedLibraries = findOutdatedKotlinLibraries(myProject)
|
||||
if (versionedOutdatedLibraries.isEmpty()) {
|
||||
return@Runnable
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void deleteKotlinJs() {
|
||||
ApplicationManager.getApplication().invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
VirtualFile kotlinJsFile = myProject.getBaseDir().findFileByRelativePath("script/kotlin.js");
|
||||
if (kotlinJsFile == null) return;
|
||||
val message: String = if (versionedOutdatedLibraries.size == 1) {
|
||||
val versionedLibrary = versionedOutdatedLibraries.first()
|
||||
|
||||
VirtualFile fileToDelete = getLocalFile(kotlinJsFile);
|
||||
try {
|
||||
VirtualFile parent = fileToDelete.getParent();
|
||||
fileToDelete.delete(this);
|
||||
parent.refresh(false, true);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
Notifications.Bus.notify(
|
||||
new Notification(OUTDATED_RUNTIME_GROUP_DISPLAY_ID, "Error", "Could not delete 'script/kotlin.js': " + ex.getMessage(), NotificationType.ERROR));
|
||||
}
|
||||
}
|
||||
});
|
||||
val version = versionedLibrary.version
|
||||
val readableVersion = version ?: "unknown"
|
||||
val libraryName = versionedLibrary.library.name
|
||||
|
||||
"<p>Your version of Kotlin runtime in '$libraryName' library is $readableVersion, while plugin version is $pluginVersion.</p>" +
|
||||
"<p>Runtime library should be updated to avoid compatibility problems.</p>" +
|
||||
"<p><a href=\"update\">Update Runtime</a> <a href=\"ignore\">Ignore</a></p>"
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
val libraryNames = versionedOutdatedLibraries.joinToString { it.library.name!! }
|
||||
|
||||
private void suggestDeleteKotlinJsIfNeeded(Collection<Library> outdatedLibraries) {
|
||||
VirtualFile kotlinJsFile = myProject.getBaseDir().findFileByRelativePath("script/kotlin.js");
|
||||
if (kotlinJsFile == null) return;
|
||||
|
||||
boolean addNotification = false;
|
||||
for(Library library : outdatedLibraries) {
|
||||
if (LibraryPresentationProviderUtil.isDetected(JSLibraryStdPresentationProvider.getInstance(), library)) {
|
||||
VirtualFile jsStdlibJar = JSLibraryStdPresentationProvider.getJsStdLibJar(library);
|
||||
assert jsStdlibJar != null : "jslibFile should not be null";
|
||||
|
||||
if (jsStdlibJar.findFileByRelativePath("kotlin.js") == null) {
|
||||
addNotification = true;
|
||||
break;
|
||||
}
|
||||
"<p>Version of Kotlin runtime is outdated in several libraries ($libraryNames). Plugin version is $pluginVersion.</p>" +
|
||||
"<p>Runtime libraries should be updated to avoid compatibility problems.</p>" +
|
||||
"<p><a href=\"update\">Update All</a> <a href=\"ignore\">Ignore</a></p>"
|
||||
}
|
||||
}
|
||||
if (!addNotification) return;
|
||||
|
||||
String message = String.format(
|
||||
"<p>File 'script/kotlin.js' was probably created by an older version of the Kotlin plugin.</p>" +
|
||||
"<p>The new Kotlin plugin copies an up-to-date version of this file to the output directory automatically, so the old version of it can be deleted.</p>" +
|
||||
"<p><a href=\"delete\">Delete this file</a> <a href=\"ignore\">Ignore</a></p>");
|
||||
|
||||
Notifications.Bus.notify(new Notification(OUTDATED_RUNTIME_GROUP_DISPLAY_ID, "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 ("delete".equals(event.getDescription())) {
|
||||
deleteKotlinJs();
|
||||
Notifications.Bus.notify(Notification(OUTDATED_RUNTIME_GROUP_DISPLAY_ID, "Outdated Kotlin Runtime", message,
|
||||
NotificationType.WARNING, NotificationListener { notification, event ->
|
||||
if (event.eventType == HyperlinkEvent.EventType.ACTIVATED) {
|
||||
if ("update" == event.description) {
|
||||
val outdatedLibraries = findOutdatedKotlinLibraries(myProject).map { it.library }
|
||||
updateLibraries(myProject, outdatedLibraries)
|
||||
suggestDeleteKotlinJsIfNeeded(outdatedLibraries)
|
||||
}
|
||||
else if ("ignore".equals(event.getDescription())) {
|
||||
// pass
|
||||
else if ("ignore" == event.description) {
|
||||
PropertiesComponent.getInstance(myProject).setValue(SUPPRESSED_PROPERTY_NAME, pluginVersion)
|
||||
}
|
||||
else {
|
||||
throw new AssertionError();
|
||||
throw AssertionError()
|
||||
}
|
||||
notification.expire();
|
||||
notification.expire()
|
||||
}
|
||||
}), myProject)
|
||||
})
|
||||
}
|
||||
|
||||
private fun deleteKotlinJs() {
|
||||
ApplicationManager.getApplication().invokeLater {
|
||||
runWriteAction {
|
||||
val kotlinJsFile = myProject.baseDir.findFileByRelativePath("script/kotlin.js") ?: return@runWriteAction
|
||||
|
||||
val fileToDelete = getLocalFile(kotlinJsFile)
|
||||
try {
|
||||
val parent = fileToDelete.parent
|
||||
fileToDelete.delete(this)
|
||||
parent.refresh(false, true)
|
||||
}
|
||||
catch (ex: IOException) {
|
||||
Notifications.Bus.notify(
|
||||
Notification(OUTDATED_RUNTIME_GROUP_DISPLAY_ID, "Error", "Could not delete 'script/kotlin.js': " + ex.message, NotificationType.ERROR))
|
||||
}
|
||||
}
|
||||
}), myProject);
|
||||
}
|
||||
}
|
||||
|
||||
private static Collection<Library> extractLibraries(Collection<VersionedLibrary> libraries) {
|
||||
return Collections2.transform(libraries, new com.google.common.base.Function<VersionedLibrary, Library>() {
|
||||
@Override
|
||||
public Library apply(@Nullable VersionedLibrary versionedLibrary) {
|
||||
assert versionedLibrary != null;
|
||||
return versionedLibrary.getLibrary();
|
||||
}
|
||||
});
|
||||
}
|
||||
private fun suggestDeleteKotlinJsIfNeeded(outdatedLibraries: Collection<Library>) {
|
||||
myProject.baseDir.findFileByRelativePath("script/kotlin.js") ?: return
|
||||
|
||||
@NotNull
|
||||
private static Collection<VersionedLibrary> findOutdatedKotlinLibraries(@NotNull Project project) {
|
||||
List<VersionedLibrary> outdatedLibraries = Lists.newArrayList();
|
||||
var addNotification = false
|
||||
for (library in outdatedLibraries) {
|
||||
if (LibraryPresentationProviderUtil.isDetected(JSLibraryStdPresentationProvider.getInstance(), library)) {
|
||||
val jsStdlibJar = JSLibraryStdPresentationProvider.getJsStdLibJar(library)
|
||||
assert(jsStdlibJar != null) { "jslibFile should not be null" }
|
||||
|
||||
for (Library library : KotlinRuntimeLibraryUtilKt.findKotlinLibraries(project)) {
|
||||
LibraryVersionProperties libraryVersionProperties =
|
||||
LibraryPresentationProviderUtil.getLibraryProperties(JavaRuntimePresentationProvider.getInstance(), library);
|
||||
if (libraryVersionProperties == null) {
|
||||
libraryVersionProperties =
|
||||
LibraryPresentationProviderUtil.getLibraryProperties(JSLibraryStdPresentationProvider.getInstance(), library);
|
||||
}
|
||||
if (libraryVersionProperties == null) {
|
||||
continue;
|
||||
}
|
||||
String libraryVersion = libraryVersionProperties.getVersionString();
|
||||
|
||||
String runtimeVersion = KotlinRuntimeLibraryUtilKt.bundledRuntimeVersion();
|
||||
|
||||
boolean isOutdated = isRuntimeOutdated(libraryVersion, runtimeVersion);
|
||||
|
||||
if (isOutdated) {
|
||||
outdatedLibraries.add(new VersionedLibrary(library, libraryVersion));
|
||||
if (jsStdlibJar!!.findFileByRelativePath("kotlin.js") == null) {
|
||||
addNotification = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!addNotification) return
|
||||
|
||||
return outdatedLibraries;
|
||||
}
|
||||
val message = "<p>File 'script/kotlin.js' was probably created by an older version of the Kotlin plugin.</p>" +
|
||||
"<p>The new Kotlin plugin copies an up-to-date version of this file to the output directory automatically, so the old version of it can be deleted.</p>" +
|
||||
"<p><a href=\"delete\">Delete this file</a> <a href=\"ignore\">Ignore</a></p>"
|
||||
|
||||
public static boolean isRuntimeOutdated(String libraryVersion, String runtimeVersion) {
|
||||
return libraryVersion == null
|
||||
|| libraryVersion.startsWith("internal-") != runtimeVersion.startsWith("internal-")
|
||||
|| VersionComparatorUtil.compare(runtimeVersion, libraryVersion) > 0;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Runnable showRuntimeJarNotFoundDialog(@NotNull final Project project, final @NotNull String jarName) {
|
||||
return new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Messages.showErrorDialog(project,
|
||||
jarName + " is not found. Make sure plugin is properly installed.",
|
||||
"No Runtime Found");
|
||||
Notifications.Bus.notify(Notification(OUTDATED_RUNTIME_GROUP_DISPLAY_ID, "Outdated Kotlin Runtime", message,
|
||||
NotificationType.WARNING, NotificationListener { notification, event ->
|
||||
if (event.eventType == HyperlinkEvent.EventType.ACTIVATED) {
|
||||
if ("delete" == event.description) {
|
||||
deleteKotlinJs()
|
||||
}
|
||||
else if ("ignore" == event.description) {
|
||||
// pass
|
||||
}
|
||||
else {
|
||||
throw AssertionError()
|
||||
}
|
||||
notification.expire()
|
||||
}
|
||||
};
|
||||
}), myProject)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val SUPPRESSED_PROPERTY_NAME = "oudtdated.runtime.suppressed.plugin.version"
|
||||
private val OUTDATED_RUNTIME_GROUP_DISPLAY_ID = "Outdated Kotlin Runtime"
|
||||
|
||||
private fun findOutdatedKotlinLibraries(project: Project): Collection<VersionedLibrary> {
|
||||
val outdatedLibraries = Lists.newArrayList<VersionedLibrary>()
|
||||
|
||||
for (library in findKotlinLibraries(project)) {
|
||||
var libraryVersionProperties = LibraryPresentationProviderUtil.getLibraryProperties(JavaRuntimePresentationProvider.getInstance(), library)
|
||||
if (libraryVersionProperties == null) {
|
||||
libraryVersionProperties = LibraryPresentationProviderUtil.getLibraryProperties(JSLibraryStdPresentationProvider.getInstance(), library)
|
||||
}
|
||||
if (libraryVersionProperties == null) {
|
||||
continue
|
||||
}
|
||||
val libraryVersion = libraryVersionProperties.versionString
|
||||
|
||||
val runtimeVersion = bundledRuntimeVersion()
|
||||
|
||||
val isOutdated = isRuntimeOutdated(libraryVersion, runtimeVersion)
|
||||
|
||||
if (isOutdated) {
|
||||
outdatedLibraries.add(VersionedLibrary(library, libraryVersion))
|
||||
}
|
||||
}
|
||||
|
||||
return outdatedLibraries
|
||||
}
|
||||
|
||||
fun isRuntimeOutdated(libraryVersion: String?, runtimeVersion: String): Boolean {
|
||||
return libraryVersion == null || libraryVersion.startsWith("internal-") != runtimeVersion.startsWith("internal-") ||
|
||||
VersionComparatorUtil.compare(runtimeVersion, libraryVersion) > 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user