From b6f3baa4851bc35171f7176f1ef15e78fcf53d4b Mon Sep 17 00:00:00 2001 From: "Natalia.Ukhorskaya" Date: Thu, 3 Oct 2013 09:48:09 +0400 Subject: [PATCH] Update sources when updating kotlin runtime --- .../KotlinJavaModuleConfigurator.java | 50 ++++++++ .../KotlinWithLibraryConfigurator.java | 14 ++- .../versions/KotlinRuntimeLibraryUtil.java | 112 +++++++++--------- .../OutdatedKotlinRuntimeNotification.java | 84 +++---------- ...edAbiVersionNotificationPanelProvider.java | 35 ++++-- 5 files changed, 155 insertions(+), 140 deletions(-) diff --git a/idea/src/org/jetbrains/jet/plugin/configuration/KotlinJavaModuleConfigurator.java b/idea/src/org/jetbrains/jet/plugin/configuration/KotlinJavaModuleConfigurator.java index e10ac059249..1e0bcc0394b 100644 --- a/idea/src/org/jetbrains/jet/plugin/configuration/KotlinJavaModuleConfigurator.java +++ b/idea/src/org/jetbrains/jet/plugin/configuration/KotlinJavaModuleConfigurator.java @@ -1,13 +1,16 @@ package org.jetbrains.jet.plugin.configuration; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.impl.scopes.LibraryScope; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.OrderRootType; import com.intellij.openapi.roots.libraries.Library; +import com.intellij.openapi.vfs.VfsUtil; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.plugin.framework.JavaRuntimeLibraryDescription; +import org.jetbrains.jet.plugin.framework.JavaRuntimePresentationProvider; import org.jetbrains.jet.plugin.framework.KotlinFrameworkDetector; import org.jetbrains.jet.plugin.framework.ui.CreateJavaLibraryDialogWithModules; import org.jetbrains.jet.plugin.versions.KotlinRuntimeLibraryUtil; @@ -16,6 +19,8 @@ import org.jetbrains.jet.utils.PathUtil; import java.io.File; import java.util.List; +import static org.jetbrains.jet.plugin.configuration.ConfigureKotlinInProjectUtils.showInfoNotification; + public class KotlinJavaModuleConfigurator extends KotlinWithLibraryConfigurator { public static final String NAME = "java"; @@ -94,6 +99,51 @@ public class KotlinJavaModuleConfigurator extends KotlinWithLibraryConfigurator return assertFileExists(getKotlinPaths().getRuntimeSourcesPath()); } + public void copySourcesToPathFromLibrary(@NotNull Library library) { + String dirToJarFromLibrary = getPathFromLibrary(library, OrderRootType.SOURCES); + assert dirToJarFromLibrary != null : "Directory to file from library should be non null"; + + copyFileToDir(getExistedSourcesJarFile(), dirToJarFromLibrary); + } + + public boolean changeOldSourcesPathIfNeeded(@NotNull Library library) { + if (!removeOldSourcesRootIfNeeded(library)) { + return false; + } + + String parentDir = getPathFromLibrary(library, OrderRootType.CLASSES); + assert parentDir != null : "Parent dir for classes jar should exists for Kotlin library"; + + return addSourcesToLibraryIfNeeded(library, getFileInDir(getSourcesJarName(), parentDir)); + } + + private static boolean removeOldSourcesRootIfNeeded(@NotNull Library library) { + VirtualFile runtimeJarPath = JavaRuntimePresentationProvider.getRuntimeJar(library); + if (runtimeJarPath == null) { + return false; + } + + String oldLibrarySourceRoot = runtimeJarPath.getUrl() + "src"; + + String[] librarySourceRoots = library.getUrls(OrderRootType.SOURCES); + for (String sourceRoot : librarySourceRoots) { + if (sourceRoot.equals(oldLibrarySourceRoot)) { + final Library.ModifiableModel model = library.getModifiableModel(); + model.removeRoot(oldLibrarySourceRoot, OrderRootType.SOURCES); + ApplicationManager.getApplication().runWriteAction(new Runnable() { + @Override + public void run() { + model.commit(); + } + }); + + showInfoNotification("Source root '" + oldLibrarySourceRoot + "' was removed for " + library.getName() + " library"); + return true; + } + } + return false; + } + @Override protected boolean isKotlinLibrary(@NotNull Project project, @NotNull Library library) { if (super.isKotlinLibrary(project, library)) { diff --git a/idea/src/org/jetbrains/jet/plugin/configuration/KotlinWithLibraryConfigurator.java b/idea/src/org/jetbrains/jet/plugin/configuration/KotlinWithLibraryConfigurator.java index 4d92cd719b2..ea7aaaa5ceb 100644 --- a/idea/src/org/jetbrains/jet/plugin/configuration/KotlinWithLibraryConfigurator.java +++ b/idea/src/org/jetbrains/jet/plugin/configuration/KotlinWithLibraryConfigurator.java @@ -4,7 +4,6 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.*; -import com.intellij.openapi.roots.impl.OrderEntryUtil; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.roots.libraries.LibraryTable; import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar; @@ -192,7 +191,11 @@ public abstract class KotlinWithLibraryConfigurator implements KotlinProjectConf @Nullable protected String getPathFromLibrary(@NotNull Project project, @NotNull OrderRootType type) { - Library library = getKotlinLibrary(project); + return getPathFromLibrary(getKotlinLibrary(project), type); + } + + @Nullable + protected static String getPathFromLibrary(@Nullable Library library, @NotNull OrderRootType type) { if (library == null) return null; String[] libraryFiles = library.getUrls(type); @@ -209,11 +212,11 @@ public abstract class KotlinWithLibraryConfigurator implements KotlinProjectConf return parentDir; } - private static void addSourcesToLibraryIfNeeded(@NotNull Library library, @NotNull File file) { + protected static boolean addSourcesToLibraryIfNeeded(@NotNull Library library, @NotNull File file) { String[] librarySourceRoots = library.getUrls(OrderRootType.SOURCES); String librarySourceRoot = VfsUtil.getUrlForLibraryRoot(file); for (String sourceRoot : librarySourceRoots) { - if (sourceRoot.equals(librarySourceRoot)) return; + if (sourceRoot.equals(librarySourceRoot)) return false; } final Library.ModifiableModel model = library.getModifiableModel(); @@ -226,7 +229,8 @@ public abstract class KotlinWithLibraryConfigurator implements KotlinProjectConf } }); - showInfoNotification(library.getName() + " library was configured"); + showInfoNotification("Source root '" + librarySourceRoot + "' was added to " + library.getName() + " library"); + return true; } private void addLibraryToModuleIfNeeded(Module module) { diff --git a/idea/src/org/jetbrains/jet/plugin/versions/KotlinRuntimeLibraryUtil.java b/idea/src/org/jetbrains/jet/plugin/versions/KotlinRuntimeLibraryUtil.java index 16c03f6d667..b2ed9acf0e6 100644 --- a/idea/src/org/jetbrains/jet/plugin/versions/KotlinRuntimeLibraryUtil.java +++ b/idea/src/org/jetbrains/jet/plugin/versions/KotlinRuntimeLibraryUtil.java @@ -19,16 +19,15 @@ package org.jetbrains.jet.plugin.versions; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.module.Module; +import com.intellij.openapi.module.ModuleManager; 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.ModuleRootManager; -import com.intellij.openapi.roots.OrderRootType; -import com.intellij.openapi.roots.ProjectFileIndex; +import com.intellij.openapi.roots.*; import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.io.FileUtil; @@ -50,12 +49,14 @@ import org.jetbrains.jet.lang.resolve.name.FqName; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.plugin.configuration.ConfigureKotlinInProjectUtils; import org.jetbrains.jet.plugin.configuration.KotlinJavaModuleConfigurator; +import org.jetbrains.jet.plugin.framework.JavaRuntimePresentationProvider; import org.jetbrains.jet.utils.KotlinPaths; import org.jetbrains.jet.utils.PathUtil; import java.io.File; import java.io.IOException; import java.util.Collection; +import java.util.List; import java.util.Set; import static com.intellij.util.PathUtil.getLocalFile; @@ -160,17 +161,36 @@ public class KotlinRuntimeLibraryUtil { return null; } - public static void updateRuntime(@NotNull final Project project) { + public static void updateLibraries( + @NotNull final Project project, + @NotNull final Collection libraries + ) { ApplicationManager.getApplication().invokeLater(new Runnable() { @Override public void run() { - updateJar(project, LibraryJarDescriptor.RUNTIME_JAR); - updateJar(project, LibraryJarDescriptor.RUNTIME_SRC_JAR); + KotlinJavaModuleConfigurator configurator = (KotlinJavaModuleConfigurator) + ConfigureKotlinInProjectUtils.getConfiguratorByName(KotlinJavaModuleConfigurator.NAME); + assert configurator != null : "Configurator with given name doesn't exists: " + KotlinJavaModuleConfigurator.NAME; + + for (Library library : libraries) { + updateJar(project, JavaRuntimePresentationProvider.getRuntimeJar(library), LibraryJarDescriptor.RUNTIME_JAR); + + if (configurator.changeOldSourcesPathIfNeeded(library)) { + configurator.copySourcesToPathFromLibrary(library); + } + else { + updateJar(project, JavaRuntimePresentationProvider.getRuntimeSrcJar(library), LibraryJarDescriptor.RUNTIME_SRC_JAR); + } + } } }); } - private static void updateJar(@NotNull Project project, @NotNull LibraryJarDescriptor libraryJarDescriptor) { + private static void updateJar(@NotNull Project project, @Nullable VirtualFile fileToReplace, @NotNull LibraryJarDescriptor libraryJarDescriptor) { + if (fileToReplace == null && !libraryJarDescriptor.shouldExists) { + return; + } + KotlinPaths paths = PathUtil.getKotlinPathsForIdeaPlugin(); File runtimePath = null; switch (libraryJarDescriptor) { @@ -183,22 +203,38 @@ public class KotlinRuntimeLibraryUtil { return; } - VirtualFile jar = null; - switch (libraryJarDescriptor) { - case RUNTIME_JAR: jar = getKotlinRuntimeJar(project); break; - case RUNTIME_SRC_JAR: jar = getKotlinRuntimeSourcesJar(project); break; - } - - if (jar == null && !libraryJarDescriptor.shouldExists) { - return; - } - - VirtualFile localJar = getLocalJar(jar); + VirtualFile localJar = getLocalJar(fileToReplace); assert localJar != null; replaceFile(runtimePath, localJar); } + @NotNull + public static Collection findKotlinLibraries(@NotNull Project project) { + Set libraries = Sets.newHashSet(); + + for (Module module : ModuleManager.getInstance(project).getModules()) { + ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); + + for (OrderEntry entry : moduleRootManager.getOrderEntries()) { + if (entry instanceof LibraryOrderEntry) { + LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry) entry; + Library library = libraryOrderEntry.getLibrary(); + + if (library == null) { + continue; + } + + libraries.add(library); + + // TODO: search js libraries as well + } + } + } + + return libraries; + } + private enum LibraryJarDescriptor { RUNTIME_JAR(PathUtil.KOTLIN_JAVA_RUNTIME_JAR, true), RUNTIME_SRC_JAR(PathUtil.KOTLIN_JAVA_RUNTIME_SRC_JAR, false); @@ -213,43 +249,7 @@ public class KotlinRuntimeLibraryUtil { } @Nullable - private static VirtualFile getKotlinRuntimeJar(@NotNull Project project) { - PsiClass markerClass = getKotlinRuntimeMarkerClass(ProjectScope.getAllScope(project)); - if (markerClass == null) return null; - - VirtualFile virtualFile = markerClass.getContainingFile().getVirtualFile(); - if (virtualFile == null) return null; - - ProjectFileIndex projectFileIndex = ProjectFileIndex.SERVICE.getInstance(project); - return projectFileIndex.getClassRootForFile(virtualFile); - } - - @Nullable - private static VirtualFile getKotlinRuntimeSourcesJar(@NotNull Project project) { - KotlinJavaModuleConfigurator configurator = (KotlinJavaModuleConfigurator) - ConfigureKotlinInProjectUtils.getConfiguratorByName(KotlinJavaModuleConfigurator.NAME); - assert configurator != null : "Configurator with given name doesn't exists: " + KotlinJavaModuleConfigurator.NAME; - - Library kotlinLibrary = configurator.getKotlinLibrary(project); - if (kotlinLibrary == null) return null; - - VirtualFile[] kotlinSourceFiles = kotlinLibrary.getFiles(OrderRootType.SOURCES); - - for (VirtualFile sourceFile : kotlinSourceFiles) { - if (sourceFile.getName().equals(PathUtil.KOTLIN_JAVA_RUNTIME_SRC_JAR)) { - return sourceFile; - } - } - return null; - } - - @Nullable - public static VirtualFile getLocalKotlinRuntimeJar(@NotNull Project project) { - return getLocalJar(getKotlinRuntimeJar(project)); - } - - @Nullable - private static VirtualFile getLocalJar(@Nullable VirtualFile kotlinRuntimeJar) { + public static VirtualFile getLocalJar(@Nullable VirtualFile kotlinRuntimeJar) { if (kotlinRuntimeJar == null) return null; VirtualFile localJarFile = JarFileSystem.getInstance().getVirtualFileForJar(kotlinRuntimeJar); diff --git a/idea/src/org/jetbrains/jet/plugin/versions/OutdatedKotlinRuntimeNotification.java b/idea/src/org/jetbrains/jet/plugin/versions/OutdatedKotlinRuntimeNotification.java index 9c76957eab6..693ae034acd 100644 --- a/idea/src/org/jetbrains/jet/plugin/versions/OutdatedKotlinRuntimeNotification.java +++ b/idea/src/org/jetbrains/jet/plugin/versions/OutdatedKotlinRuntimeNotification.java @@ -26,18 +26,12 @@ 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.module.Module; -import com.intellij.openapi.module.ModuleManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.roots.LibraryOrderEntry; -import com.intellij.openapi.roots.ModuleRootManager; -import com.intellij.openapi.roots.OrderEntry; 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; @@ -45,10 +39,8 @@ import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.plugin.JetPluginUtil; import org.jetbrains.jet.plugin.framework.JavaRuntimePresentationProvider; import org.jetbrains.jet.plugin.framework.LibraryPresentationProviderUtil; -import org.jetbrains.jet.utils.PathUtil; import javax.swing.event.HyperlinkEvent; -import java.io.File; import java.util.Collection; import java.util.List; @@ -134,7 +126,7 @@ 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())) { - updateKotlinLibraries(outdatedLibraries); + KotlinRuntimeLibraryUtil.updateLibraries(myProject, outdatedLibraries); } else if ("ignore".equals(event.getDescription())) { PropertiesComponent.getInstance(myProject).setValue(SUPPRESSED_PROPERTY_NAME, pluginVersion); @@ -160,79 +152,31 @@ public class OutdatedKotlinRuntimeNotification extends AbstractProjectComponent }); } - private void updateKotlinLibraries(Collection libraries) { - File runtimePath = PathUtil.getKotlinPathsForIdeaPlugin().getRuntimePath(); - if (!runtimePath.exists()) { - showRuntimeJarNotFoundDialog(myProject, PathUtil.KOTLIN_JAVA_RUNTIME_JAR).run(); - return; - } - - for (Library library : libraries) { - VirtualFile libraryJar = JavaRuntimePresentationProvider.getRuntimeJar(library); - assert LibraryPresentationProviderUtil.isDetected(JavaRuntimePresentationProvider.getInstance(), library) && - libraryJar != null : "Only java runtime libraries are expected"; - - KotlinRuntimeLibraryUtil.replaceFile(runtimePath, libraryJar); - - VirtualFile libraryJarSrc = JavaRuntimePresentationProvider.getRuntimeSrcJar(library); - if (libraryJarSrc != null) { - File runtimeSrcPath = PathUtil.getKotlinPathsForIdeaPlugin().getRuntimeSourcesPath(); - if (!runtimeSrcPath.exists()) { - showRuntimeJarNotFoundDialog(myProject, PathUtil.KOTLIN_JAVA_RUNTIME_SRC_JAR).run(); - return; - } - KotlinRuntimeLibraryUtil.replaceFile(runtimeSrcPath, libraryJarSrc); - } - } - } - - private static Collection findOutdatedKotlinLibraries(Project project, String pluginVersion) { + @NotNull + private static Collection findOutdatedKotlinLibraries(@NotNull Project project, @NotNull String pluginVersion) { List outdatedLibraries = Lists.newArrayList(); - for (VersionedLibrary versionedLibrary : findKotlinLibraries(project)) { - String libraryVersion = versionedLibrary.getVersion(); + for (Library library : KotlinRuntimeLibraryUtil.findKotlinLibraries(project)) { + LibraryVersionProperties javaRuntimeProperties = + LibraryPresentationProviderUtil.getLibraryProperties(JavaRuntimePresentationProvider.getInstance(), library); + if (javaRuntimeProperties == null) { + continue; + } + String libraryVersion = javaRuntimeProperties.getVersionString(); boolean isOutdated = "snapshot".equals(libraryVersion) - || libraryVersion == null - || libraryVersion.startsWith("internal-") != pluginVersion.startsWith("internal-") - || VersionComparatorUtil.compare(pluginVersion, libraryVersion) > 0; + || libraryVersion == null + || libraryVersion.startsWith("internal-") != pluginVersion.startsWith("internal-") + || VersionComparatorUtil.compare(pluginVersion, libraryVersion) > 0; if (isOutdated) { - outdatedLibraries.add(versionedLibrary); + outdatedLibraries.add(new VersionedLibrary(library, libraryVersion)); } } return outdatedLibraries; } - private static Collection findKotlinLibraries(Project project) { - List libraries = Lists.newArrayList(); - - for (Module module : ModuleManager.getInstance(project).getModules()) { - ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module); - - for (OrderEntry entry : moduleRootManager.getOrderEntries()) { - if (entry instanceof LibraryOrderEntry) { - LibraryOrderEntry libraryOrderEntry = (LibraryOrderEntry) entry; - Library library = libraryOrderEntry.getLibrary(); - - if (library == null) { - continue; - } - - LibraryVersionProperties javaRuntimeProperties = LibraryPresentationProviderUtil.getLibraryProperties( - JavaRuntimePresentationProvider.getInstance(), library); - if (javaRuntimeProperties != null) { - libraries.add(new VersionedLibrary(library, javaRuntimeProperties.getVersionString())); - } - - // TODO: search js libraries as well - } - } - } - - return libraries; - } @NotNull public static Runnable showRuntimeJarNotFoundDialog(@NotNull final Project project, final @NotNull String jarName) { diff --git a/idea/src/org/jetbrains/jet/plugin/versions/UnsupportedAbiVersionNotificationPanelProvider.java b/idea/src/org/jetbrains/jet/plugin/versions/UnsupportedAbiVersionNotificationPanelProvider.java index b4ba7bcf91d..b5a075eef28 100644 --- a/idea/src/org/jetbrains/jet/plugin/versions/UnsupportedAbiVersionNotificationPanelProvider.java +++ b/idea/src/org/jetbrains/jet/plugin/versions/UnsupportedAbiVersionNotificationPanelProvider.java @@ -16,6 +16,8 @@ package org.jetbrains.jet.plugin.versions; +import com.google.common.base.Predicate; +import com.google.common.collect.Collections2; import com.intellij.ProjectTopics; import com.intellij.icons.AllIcons; import com.intellij.openapi.application.ApplicationManager; @@ -30,6 +32,7 @@ import com.intellij.openapi.project.IndexNotReadyException; import com.intellij.openapi.project.Project; import com.intellij.openapi.roots.ModuleRootAdapter; import com.intellij.openapi.roots.ModuleRootEvent; +import com.intellij.openapi.roots.libraries.Library; import com.intellij.openapi.ui.popup.JBPopupFactory; import com.intellij.openapi.ui.popup.ListPopup; import com.intellij.openapi.ui.popup.PopupStep; @@ -47,6 +50,7 @@ import org.jetbrains.jet.plugin.JetFileType; import org.jetbrains.jet.plugin.configuration.ConfigureKotlinInProjectUtils; import org.jetbrains.jet.plugin.configuration.KotlinJavaModuleConfigurator; import org.jetbrains.jet.plugin.configuration.KotlinProjectConfigurator; +import org.jetbrains.jet.plugin.framework.JavaRuntimePresentationProvider; import javax.swing.*; import java.awt.*; @@ -88,23 +92,36 @@ public class UnsupportedAbiVersionNotificationPanelProvider extends EditorNotifi return null; } - private EditorNotificationPanel doCreate(Collection badRoots) { + private EditorNotificationPanel doCreate(final Collection badRoots) { EditorNotificationPanel answer = new ErrorNotificationPanel(); - VirtualFile kotlinRuntimeJar = KotlinRuntimeLibraryUtil.getLocalKotlinRuntimeJar(project); - if (kotlinRuntimeJar != null && badRoots.contains(kotlinRuntimeJar)) { - int otherBadRootsCount = badRoots.size() - 1; - String kotlinRuntimeJarName = kotlinRuntimeJar.getPresentableName(); - String text = MessageFormat.format("Kotlin runtime library jar ''{0}'' " + + Collection kotlinLibraries = KotlinRuntimeLibraryUtil.findKotlinLibraries(project); + final Collection badRuntimeLibraries = Collections2.filter(kotlinLibraries, new Predicate() { + @Override + public boolean apply(@Nullable Library library) { + assert library != null : "library should be non null"; + VirtualFile runtimeJar = JavaRuntimePresentationProvider.getRuntimeJar(library); + return badRoots.contains(KotlinRuntimeLibraryUtil.getLocalJar(runtimeJar)); + } + }); + + if (!badRuntimeLibraries.isEmpty()) { + int otherBadRootsCount = badRoots.size() - badRuntimeLibraries.size(); + + String text = MessageFormat.format("{0,choice,0#|1#|1" + "{1,choice,0#|1# and one other jar|1< and {1} other jars} " + "{1,choice,0#has|0", - kotlinRuntimeJarName, + badRuntimeLibraries.size(), otherBadRootsCount); + + String actionLabelText = MessageFormat.format("Update {0,choice,0#|1#|1 0) {