From 94907d384405241a20964ce33bb136287523b691 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Mon, 11 Jul 2022 20:34:08 +0300 Subject: [PATCH 1/3] Required libraries can be installed silently #492 --- .../plugin/ui/GenerateTestsDialogWindow.kt | 51 ++-------- .../plugin/util/UtProjectModelModifier.kt | 96 +++++++++++++++++++ .../src/main/resources/META-INF/plugin.xml | 1 + 3 files changed, 103 insertions(+), 45 deletions(-) create mode 100644 utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt index 3edbecac89..9a1394a941 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/ui/GenerateTestsDialogWindow.kt @@ -178,15 +178,11 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m // Configure notification urls callbacks TestsReportNotifier.urlOpeningListener.callbacks[TestReportUrlOpeningListener.mockitoSuffix]?.plusAssign { - if (createMockFrameworkNotificationDialog() == Messages.YES) { - configureMockFramework() - } + configureMockFramework() } TestsReportNotifier.urlOpeningListener.callbacks[TestReportUrlOpeningListener.mockitoInlineSuffix]?.plusAssign { - if (createStaticsMockingNotificationDialog() == Messages.YES) { - configureStaticMocking() - } + configureStaticMocking() } init() @@ -610,29 +606,21 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m //region configure frameworks private fun configureTestFrameworkIfRequired() { - val frameworkNotInstalled = !testFrameworks.item.isInstalled - - if (frameworkNotInstalled && createTestFrameworkNotificationDialog() == Messages.YES) { + if (!testFrameworks.item.isInstalled) { configureTestFramework() } - model.hasTestFrameworkConflict = TestFramework.allItems.count { it.isInstalled } > 1 + model.hasTestFrameworkConflict = TestFramework.allItems.count { it.isInstalled } > 1 } private fun configureMockFrameworkIfRequired() { - val frameworkNotInstalled = - mockStrategies.item != MockStrategyApi.NO_MOCKS && !MOCKITO.isInstalled - - if (frameworkNotInstalled && createMockFrameworkNotificationDialog() == Messages.YES) { + if (mockStrategies.item != MockStrategyApi.NO_MOCKS && !MOCKITO.isInstalled) { configureMockFramework() } } private fun configureStaticMockingIfRequired() { - val frameworkNotConfigured = - staticsMocking.item != NoStaticMocking && !staticsMocking.item.isConfigured - - if (frameworkNotConfigured && createStaticsMockingNotificationDialog() == Messages.YES) { + if (staticsMocking.item != NoStaticMocking && !staticsMocking.item.isConfigured) { configureStaticMocking() } } @@ -655,15 +643,6 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m .onError { selectedTestFramework.isInstalled = false } } - private fun createTestFrameworkNotificationDialog() = Messages.showYesNoDialog( - """Selected test framework ${testFrameworks.item.displayName} is not installed into current module. - |Would you like to install it now?""".trimMargin(), - title, - "Yes", - "No", - Messages.getQuestionIcon(), - ) - private fun configureMockFramework() { val selectedMockFramework = MOCKITO @@ -740,24 +719,6 @@ class GenerateTestsDialogWindow(val model: GenerateTestsModel) : DialogWrapper(m } } - private fun createMockFrameworkNotificationDialog() = Messages.showYesNoDialog( - """Mock framework ${MOCKITO.displayName} is not installed into current module. - |Would you like to install it now?""".trimMargin(), - title, - "Yes", - "No", - Messages.getQuestionIcon(), - ) - - private fun createStaticsMockingNotificationDialog() = Messages.showYesNoDialog( - """A framework ${MOCKITO.displayName} is not configured to mock static methods. - |Would you like to configure it now?""".trimMargin(), - title, - "Yes", - "No", - Messages.getQuestionIcon(), - ) - //endregion /** diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt new file mode 100644 index 0000000000..4cdf9d7443 --- /dev/null +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt @@ -0,0 +1,96 @@ +package org.utbot.intellij.plugin.util + +import com.intellij.codeInsight.daemon.impl.quickfix.LocateLibraryDialog +import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix +import com.intellij.ide.JavaUiBundle +import com.intellij.jarRepository.JarRepositoryManager +import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.openapi.roots.DependencyScope +import com.intellij.openapi.roots.ExternalLibraryDescriptor +import com.intellij.openapi.roots.ModuleRootModificationUtil +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.roots.impl.IdeaProjectModelModifier +import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar +import com.intellij.openapi.roots.libraries.LibraryUtil +import com.intellij.openapi.roots.libraries.ui.OrderRoot +import com.intellij.openapi.ui.Messages +import com.intellij.util.PathUtil +import com.intellij.util.containers.ContainerUtil +import java.util.stream.Collectors +import org.jetbrains.concurrency.Promise +import org.jetbrains.concurrency.rejectedPromise +import org.jetbrains.concurrency.resolvedPromise +import org.jetbrains.idea.maven.utils.library.RepositoryLibraryDescription +import org.jetbrains.idea.maven.utils.library.RepositoryLibraryProperties +import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor + +class UtProjectModelModifier(val project: Project) : IdeaProjectModelModifier(project) { + override fun addExternalLibraryDependency( + modules: Collection, + descriptor: ExternalLibraryDescriptor, + scope: DependencyScope + ): Promise { + val defaultRoots = descriptor.libraryClassesRoots + val classesRoots: List + val firstModule = ContainerUtil.getFirstItem(modules) + classesRoots = if (defaultRoots.isNotEmpty()) { + LocateLibraryDialog(firstModule!!, defaultRoots, descriptor.presentableName).showAndGetResult() + } else { + val version = descriptor.preferredVersion + val mavenCoordinates = descriptor.libraryGroupId + ":" + + descriptor.libraryArtifactId + ":" + + (version ?: RepositoryLibraryDescription.ReleaseVersionId) + + val libraryProperties = RepositoryLibraryProperties(JpsMavenRepositoryLibraryDescriptor(mavenCoordinates)) + val roots = JarRepositoryManager.loadDependenciesModal( + project, + libraryProperties, + false, + false, + null, + null + ) + if (roots.isEmpty()) { + @Suppress("SpellCheckingInspection") + Messages.showErrorDialog( + project, JavaUiBundle.message("dialog.mesage.0.was.not.loaded", descriptor.presentableName), + JavaUiBundle.message("dialog.title.failed.to.download.library") + ) + return rejectedPromise() + } + roots.stream() + .filter { root: OrderRoot -> root.type === OrderRootType.CLASSES } + .map { root: OrderRoot -> + PathUtil.getLocalPath( + root.file + ) + } + .collect(Collectors.toList()) + } + if (classesRoots.isNotEmpty()) { + val libraryName = if (classesRoots.size > 1) descriptor.presentableName else null + val urls = OrderEntryFix.refreshAndConvertToUrls(classesRoots) + if (modules.size == 1) { + ModuleRootModificationUtil.addModuleLibrary(firstModule!!, libraryName, urls, emptyList(), scope) + } else { + WriteAction.run { + val library = + LibraryUtil.createLibrary( + LibraryTablesRegistrar.getInstance().getLibraryTable(project), descriptor.presentableName + ) + val model = library.modifiableModel + for (url in urls) { + model.addRoot(url!!, OrderRootType.CLASSES) + } + model.commit() + for (module in modules) { + ModuleRootModificationUtil.addDependency(module!!, library, scope, false) + } + } + } + } + return resolvedPromise() + } +} \ No newline at end of file diff --git a/utbot-intellij/src/main/resources/META-INF/plugin.xml b/utbot-intellij/src/main/resources/META-INF/plugin.xml index f349c1a191..87742b96f5 100644 --- a/utbot-intellij/src/main/resources/META-INF/plugin.xml +++ b/utbot-intellij/src/main/resources/META-INF/plugin.xml @@ -33,6 +33,7 @@ + From 3ca852dbbaaeff1ba91b331bf2878837001434b0 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Wed, 13 Jul 2022 15:25:36 +0300 Subject: [PATCH 2/3] Required libraries can be installed silently #492 After-review cleanup --- .../plugin/util/UtProjectModelModifier.kt | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt index 4cdf9d7443..1d2fbfb01f 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt @@ -28,34 +28,33 @@ import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor class UtProjectModelModifier(val project: Project) : IdeaProjectModelModifier(project) { override fun addExternalLibraryDependency( - modules: Collection, + modules: Collection, descriptor: ExternalLibraryDescriptor, scope: DependencyScope ): Promise { val defaultRoots = descriptor.libraryClassesRoots - val classesRoots: List - val firstModule = ContainerUtil.getFirstItem(modules) - classesRoots = if (defaultRoots.isNotEmpty()) { - LocateLibraryDialog(firstModule!!, defaultRoots, descriptor.presentableName).showAndGetResult() + val firstModule = ContainerUtil.getFirstItem(modules) ?: return rejectedPromise() + val classesRoots = if (defaultRoots.isNotEmpty()) { + LocateLibraryDialog( + firstModule, + defaultRoots, + descriptor.presentableName + ).showAndGetResult() } else { - val version = descriptor.preferredVersion - val mavenCoordinates = descriptor.libraryGroupId + ":" + - descriptor.libraryArtifactId + ":" + - (version ?: RepositoryLibraryDescription.ReleaseVersionId) - - val libraryProperties = RepositoryLibraryProperties(JpsMavenRepositoryLibraryDescriptor(mavenCoordinates)) + val libraryProperties = RepositoryLibraryProperties(JpsMavenRepositoryLibraryDescriptor(descriptor.mavenCoordinates())) val roots = JarRepositoryManager.loadDependenciesModal( project, libraryProperties, - false, - false, - null, - null + /* loadSources = */ false, + /* loadJavadoc = */ false, + /* copyTo = */ null, + /* repositories = */ null ) if (roots.isEmpty()) { @Suppress("SpellCheckingInspection") Messages.showErrorDialog( - project, JavaUiBundle.message("dialog.mesage.0.was.not.loaded", descriptor.presentableName), + project, + JavaUiBundle.message("dialog.mesage.0.was.not.loaded", descriptor.presentableName), JavaUiBundle.message("dialog.title.failed.to.download.library") ) return rejectedPromise() @@ -73,7 +72,7 @@ class UtProjectModelModifier(val project: Project) : IdeaProjectModelModifier(pr val libraryName = if (classesRoots.size > 1) descriptor.presentableName else null val urls = OrderEntryFix.refreshAndConvertToUrls(classesRoots) if (modules.size == 1) { - ModuleRootModificationUtil.addModuleLibrary(firstModule!!, libraryName, urls, emptyList(), scope) + ModuleRootModificationUtil.addModuleLibrary(firstModule, libraryName, urls, emptyList(), scope) } else { WriteAction.run { val library = @@ -86,11 +85,15 @@ class UtProjectModelModifier(val project: Project) : IdeaProjectModelModifier(pr } model.commit() for (module in modules) { - ModuleRootModificationUtil.addDependency(module!!, library, scope, false) + ModuleRootModificationUtil.addDependency(module, library, scope, false) } } } } return resolvedPromise() } + + private fun ExternalLibraryDescriptor.mavenCoordinates() : String { + return "$libraryGroupId:$libraryArtifactId:${preferredVersion ?: RepositoryLibraryDescription.ReleaseVersionId}" + } } \ No newline at end of file From 2682b488597ad4c56fb42932065959816ea93325 Mon Sep 17 00:00:00 2001 From: "Vassiliy.Kudryashov" Date: Wed, 13 Jul 2022 16:58:47 +0300 Subject: [PATCH 3/3] Required libraries can be installed silently #492 After-review cleanup 2 --- .../plugin/util/UtProjectModelModifier.kt | 62 +++++++------------ 1 file changed, 24 insertions(+), 38 deletions(-) diff --git a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt index 1d2fbfb01f..1def29ff4d 100644 --- a/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt +++ b/utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/util/UtProjectModelModifier.kt @@ -2,7 +2,6 @@ package org.utbot.intellij.plugin.util import com.intellij.codeInsight.daemon.impl.quickfix.LocateLibraryDialog import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix -import com.intellij.ide.JavaUiBundle import com.intellij.jarRepository.JarRepositoryManager import com.intellij.openapi.application.WriteAction import com.intellij.openapi.module.Module @@ -14,13 +13,9 @@ import com.intellij.openapi.roots.OrderRootType import com.intellij.openapi.roots.impl.IdeaProjectModelModifier import com.intellij.openapi.roots.libraries.LibraryTablesRegistrar import com.intellij.openapi.roots.libraries.LibraryUtil -import com.intellij.openapi.roots.libraries.ui.OrderRoot -import com.intellij.openapi.ui.Messages import com.intellij.util.PathUtil import com.intellij.util.containers.ContainerUtil -import java.util.stream.Collectors import org.jetbrains.concurrency.Promise -import org.jetbrains.concurrency.rejectedPromise import org.jetbrains.concurrency.resolvedPromise import org.jetbrains.idea.maven.utils.library.RepositoryLibraryDescription import org.jetbrains.idea.maven.utils.library.RepositoryLibraryProperties @@ -31,9 +26,9 @@ class UtProjectModelModifier(val project: Project) : IdeaProjectModelModifier(pr modules: Collection, descriptor: ExternalLibraryDescriptor, scope: DependencyScope - ): Promise { + ): Promise? { val defaultRoots = descriptor.libraryClassesRoots - val firstModule = ContainerUtil.getFirstItem(modules) ?: return rejectedPromise() + val firstModule = ContainerUtil.getFirstItem(modules) ?: return null val classesRoots = if (defaultRoots.isNotEmpty()) { LocateLibraryDialog( firstModule, @@ -41,51 +36,42 @@ class UtProjectModelModifier(val project: Project) : IdeaProjectModelModifier(pr descriptor.presentableName ).showAndGetResult() } else { - val libraryProperties = RepositoryLibraryProperties(JpsMavenRepositoryLibraryDescriptor(descriptor.mavenCoordinates())) val roots = JarRepositoryManager.loadDependenciesModal( project, - libraryProperties, + RepositoryLibraryProperties(JpsMavenRepositoryLibraryDescriptor(descriptor.mavenCoordinates())), /* loadSources = */ false, /* loadJavadoc = */ false, /* copyTo = */ null, /* repositories = */ null ) if (roots.isEmpty()) { - @Suppress("SpellCheckingInspection") - Messages.showErrorDialog( - project, - JavaUiBundle.message("dialog.mesage.0.was.not.loaded", descriptor.presentableName), - JavaUiBundle.message("dialog.title.failed.to.download.library") - ) - return rejectedPromise() + return null } - roots.stream() - .filter { root: OrderRoot -> root.type === OrderRootType.CLASSES } - .map { root: OrderRoot -> - PathUtil.getLocalPath( - root.file - ) - } - .collect(Collectors.toList()) + roots.filter { orderRoot -> orderRoot.type === OrderRootType.CLASSES } + .map { PathUtil.getLocalPath(it.file) }.toList() } if (classesRoots.isNotEmpty()) { - val libraryName = if (classesRoots.size > 1) descriptor.presentableName else null val urls = OrderEntryFix.refreshAndConvertToUrls(classesRoots) if (modules.size == 1) { - ModuleRootModificationUtil.addModuleLibrary(firstModule, libraryName, urls, emptyList(), scope) + ModuleRootModificationUtil.addModuleLibrary( + firstModule, + if (classesRoots.size > 1) descriptor.presentableName else null, + urls, + emptyList(), + scope + ) } else { WriteAction.run { - val library = - LibraryUtil.createLibrary( - LibraryTablesRegistrar.getInstance().getLibraryTable(project), descriptor.presentableName - ) - val model = library.modifiableModel - for (url in urls) { - model.addRoot(url!!, OrderRootType.CLASSES) - } - model.commit() - for (module in modules) { - ModuleRootModificationUtil.addDependency(module, library, scope, false) + LibraryUtil.createLibrary( + LibraryTablesRegistrar.getInstance().getLibraryTable(project), + descriptor.presentableName + ).let { + val model = it.modifiableModel + urls.forEach { url -> model.addRoot(url, OrderRootType.CLASSES) } + model.commit() + modules.forEach { module -> + ModuleRootModificationUtil.addDependency(module, it, scope, false) + } } } } @@ -93,7 +79,7 @@ class UtProjectModelModifier(val project: Project) : IdeaProjectModelModifier(pr return resolvedPromise() } - private fun ExternalLibraryDescriptor.mavenCoordinates() : String { + private fun ExternalLibraryDescriptor.mavenCoordinates(): String { return "$libraryGroupId:$libraryArtifactId:${preferredVersion ?: RepositoryLibraryDescription.ReleaseVersionId}" } } \ No newline at end of file