From 3ac9a73b0a7ecd3751b905ffb2efe0d39ca3c5e0 Mon Sep 17 00:00:00 2001 From: azerr Date: Mon, 20 Nov 2023 17:25:38 +0100 Subject: [PATCH] fix: Connect Quarkus run configuration with Services view support Fixes #1265 Signed-off-by: azerr --- .../intellij/quarkus/QuarkusConstants.java | 3 + .../intellij/quarkus/QuarkusModuleUtil.java | 34 ++++++-- .../quarkus/run/QuarkusRunConfiguration.java | 34 ++++---- .../QuarkusRunDashboardCustomizer.java | 84 +++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 3 + 5 files changed, 130 insertions(+), 28 deletions(-) create mode 100644 src/main/java/com/redhat/devtools/intellij/quarkus/run/dashboard/QuarkusRunDashboardCustomizer.java diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusConstants.java b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusConstants.java index 5ce514de5..58a935e6e 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusConstants.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusConstants.java @@ -74,6 +74,9 @@ public class QuarkusConstants { public static final String QUARKUS_SCHEDULED_ANNOTATION = "io.quarkus.scheduler.Scheduled"; public static final String QUARKUS_CORE_PREFIX = "io.quarkus:quarkus-core:"; + + public static final String QUARKUS_VERTX_HTTP_PREFIX = "io.quarkus:quarkus-vertx-http:"; + public static final String QUARKUS_PREFIX = "quarkus"; public static final String QUARKUS_JAVADOC_PROPERTIES_FILE = "quarkus-javadoc.properties"; public static final String QUARKUS_EXTENSION_PROPERTIES = "META-INF/quarkus-extension.properties"; diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusModuleUtil.java b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusModuleUtil.java index 2700dfe65..348ef62ce 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusModuleUtil.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusModuleUtil.java @@ -39,38 +39,56 @@ public class QuarkusModuleUtil { private static final Logger LOGGER = LoggerFactory.getLogger(QuarkusModuleUtil.class); + private static final Pattern QUARKUS_CORE_PATTERN = Pattern.compile("quarkus-core-(\\d[a-zA-Z\\d-.]+?).jar"); + + public static final Pattern QUARKUS_STANDARD_VERSIONING = Pattern.compile("(\\d+).(\\d+).(\\d+)(.Final)?(-redhat-\\\\d+)?$"); + public static final Pattern APPLICATION_PROPERTIES = Pattern.compile("application(-.+)?\\.properties"); public static final Pattern MICROPROFILE_CONFIG_PROPERTIES = Pattern.compile("microprofile-config(-.+)?\\.properties"); public static final Pattern APPLICATION_YAML = Pattern.compile("application(-.+)?\\.ya?ml"); + /** * Check if the module is a Quarkus project. Should check if some class if present * but it seems PSI is not available when the module is added thus we rely on the - * library names. + * library names (io.quarkus:quarkus-core*). * * @param module the module to check - * @return yes if module is a Quarkus project + * @return true if module is a Quarkus project and false otherwise. */ public static boolean isQuarkusModule(Module module) { + return hasLibrary(module, QuarkusConstants.QUARKUS_CORE_PREFIX); + } + + /** + * Check if the module is a Quarkus Web Application project. Should check if some class if present + * but it seems PSI is not available when the module is added thus we rely on the + * library names (io.quarkus:quarkus-vertx-http:*). + * + * @param module the module to check + * @return true if module is a Quarkus project and false otherwise. + */ + public static boolean isQuarkusWebAppModule(Module module) { + return hasLibrary(module, QuarkusConstants.QUARKUS_VERTX_HTTP_PREFIX); + } + + private static boolean hasLibrary(Module module, String libraryNamePrefix) { OrderEnumerator libraries = ModuleRootManager.getInstance(module).orderEntries().librariesOnly(); return libraries.process(new RootPolicy() { @Override public Boolean visitLibraryOrderEntry(@NotNull LibraryOrderEntry libraryOrderEntry, Boolean value) { - return value || isQuarkusLibrary(libraryOrderEntry); + return value || isLibrary(libraryOrderEntry, libraryNamePrefix); } }, false); } - public static boolean isQuarkusLibrary(@NotNull LibraryOrderEntry libraryOrderEntry) { + private static boolean isLibrary(@NotNull LibraryOrderEntry libraryOrderEntry, String libraryNamePrefix) { return libraryOrderEntry.getLibraryName() != null && - libraryOrderEntry.getLibraryName().contains(QuarkusConstants.QUARKUS_CORE_PREFIX); + libraryOrderEntry.getLibraryName().contains(libraryNamePrefix); } - private static final Pattern QUARKUS_CORE_PATTERN = Pattern.compile("quarkus-core-(\\d[a-zA-Z\\d-.]+?).jar"); - public static final Pattern QUARKUS_STANDARD_VERSIONING = Pattern.compile("(\\d+).(\\d+).(\\d+)(.Final)?(-redhat-\\\\d+)?$"); - /** * Checks whether the quarkus version used in this module matches the given predicate. * If we're unable to detect the Quarkus version, this method always returns false. diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java index 37955c1e5..12df5bd32 100644 --- a/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/QuarkusRunConfiguration.java @@ -10,13 +10,7 @@ ******************************************************************************/ package com.redhat.devtools.intellij.quarkus.run; -import com.intellij.execution.DefaultExecutionTarget; -import com.intellij.execution.ExecutionException; -import com.intellij.execution.ExecutionManager; -import com.intellij.execution.ExecutionTarget; -import com.intellij.execution.Executor; -import com.intellij.execution.RunManager; -import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.*; import com.intellij.execution.configurations.ConfigurationFactory; import com.intellij.execution.configurations.ModuleBasedConfiguration; import com.intellij.execution.configurations.RunConfiguration; @@ -133,12 +127,14 @@ public RunProfileState getState(@NotNull Executor executor, @NotNull ExecutionEn telemetry.property("kind", executor.getId()); BuildToolDelegate toolDelegate = BuildToolDelegate.getDelegate(getModule()); allocateLocalPort(); + RunProfileState state = null; if (toolDelegate != null) { telemetry.property("tool", toolDelegate.getDisplay()); + // Create a Gradle or Maven run configuration in memory RunnerAndConfigurationSettings settings = toolDelegate.getConfigurationDelegate(getModule(), this); if (settings != null) { long groupId = ExecutionEnvironment.getNextUnusedExecutionId(); - doRunConfiguration(settings, executor, DefaultExecutionTarget.INSTANCE, groupId, null, + state = doRunConfiguration(settings, executor, DefaultExecutionTarget.INSTANCE, groupId, null, desc -> desc.getComponent().putClientProperty(QuarkusConstants.QUARKUS_RUN_CONTEXT_KEY, new QuarkusRunContext(getModule()))); } } else { @@ -153,7 +149,7 @@ public void run(@NotNull ProgressIndicator indicator) { } }); } - return null; + return state; } private void waitForPortAvailable(int port, ProgressIndicator monitor) throws IOException { @@ -212,21 +208,19 @@ public int getPort() { return port; } - private static void doRunConfiguration(@NotNull RunnerAndConfigurationSettings configuration, - @NotNull Executor executor, - @Nullable ExecutionTarget targetOrNullForDefault, - @Nullable Long executionId, - @Nullable DataContext dataContext, - ProgramRunner.Callback callback) { + private static RunProfileState doRunConfiguration(@NotNull RunnerAndConfigurationSettings configuration, + @NotNull Executor executor, + @Nullable ExecutionTarget targetOrNullForDefault, + @Nullable Long executionId, + @Nullable DataContext dataContext, + ProgramRunner.Callback callback) throws ExecutionException { ExecutionEnvironmentBuilder builder = createEnvironment(executor, configuration); if (builder == null) { - return; + return null; } - if (targetOrNullForDefault != null) { builder.target(targetOrNullForDefault); - } - else { + } else { builder.activeTarget(); } if (executionId != null) { @@ -235,7 +229,7 @@ private static void doRunConfiguration(@NotNull RunnerAndConfigurationSettings c if (dataContext != null) { builder.dataContext(dataContext); } - ExecutionManager.getInstance(configuration.getConfiguration().getProject()).restartRunProfile(builder.build(callback)); + return configuration.getConfiguration().getState(executor, builder.build(callback)); } } diff --git a/src/main/java/com/redhat/devtools/intellij/quarkus/run/dashboard/QuarkusRunDashboardCustomizer.java b/src/main/java/com/redhat/devtools/intellij/quarkus/run/dashboard/QuarkusRunDashboardCustomizer.java new file mode 100644 index 000000000..42d2ad8df --- /dev/null +++ b/src/main/java/com/redhat/devtools/intellij/quarkus/run/dashboard/QuarkusRunDashboardCustomizer.java @@ -0,0 +1,84 @@ +/******************************************************************************* + * Copyright (c) 2023 Red Hat, Inc. + * Distributed under license by Red Hat, Inc. All rights reserved. + * This program is made available under the terms of the + * Eclipse Public License v2.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v20.html + * + * Contributors: + * Red Hat, Inc. - initial API and implementation + ******************************************************************************/ +package com.redhat.devtools.intellij.quarkus.run.dashboard; + +import com.intellij.execution.RunnerAndConfigurationSettings; +import com.intellij.execution.dashboard.RunDashboardCustomizer; +import com.intellij.execution.dashboard.RunDashboardRunConfigurationNode; +import com.intellij.execution.process.ProcessHandler; +import com.intellij.execution.ui.RunContentDescriptor; +import com.intellij.ide.projectView.PresentationData; +import com.intellij.ui.SimpleColoredComponent; +import com.intellij.ui.SimpleTextAttributes; +import com.redhat.devtools.intellij.quarkus.QuarkusModuleUtil; +import com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration; +import com.redhat.devtools.intellij.quarkus.run.QuarkusRunContext; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.HashMap; +import java.util.Map; + +/** + * Dashboard customizer for Quarkus to provide: + * + *
    + *
  • Open quarkus application in a browser.
  • + *
  • Open quarkus DevUI in a browser.
  • + *
+ */ +public class QuarkusRunDashboardCustomizer extends RunDashboardCustomizer { + + @Override + public boolean isApplicable(@NotNull RunnerAndConfigurationSettings settings, @Nullable RunContentDescriptor descriptor) { + return settings.getConfiguration() instanceof QuarkusRunConfiguration; + } + + @Override + public boolean updatePresentation(@NotNull PresentationData presentation, @NotNull RunDashboardRunConfigurationNode node) { + if (!(node.getConfigurationSettings().getConfiguration() instanceof QuarkusRunConfiguration)) { + return false; + } + node.putUserData(RunDashboardCustomizer.NODE_LINKS, null); + RunContentDescriptor descriptor = node.getDescriptor(); + if (descriptor != null) { + ProcessHandler processHandler = descriptor.getProcessHandler(); + if (processHandler != null && !processHandler.isProcessTerminated()) { + // The Quarkus run configuration is running + QuarkusRunConfiguration quarkusRunConfiguration = (QuarkusRunConfiguration) node.getConfigurationSettings().getConfiguration(); + if (QuarkusModuleUtil.isQuarkusWebAppModule(quarkusRunConfiguration.getModule())) { + // It is a Web application, add links for: + // - Opening quarkus application in a browser + // - Opening DevUI in a browser + QuarkusRunContext runContext = new QuarkusRunContext(quarkusRunConfiguration.getModule()); + // Add application Url as hyperlink + String applicationUrl = runContext.getApplicationURL(); + String applicationLabel = applicationUrl; + presentation.addText(" ", SimpleTextAttributes.REGULAR_ATTRIBUTES); + presentation.addText(applicationLabel, SimpleTextAttributes.LINK_ATTRIBUTES); + + // Add DevUI Url as hyperlink + String devUIUrl = runContext.getDevUIURL(); + String devUILabel = "Dev UI"; + presentation.addText(" - ", SimpleTextAttributes.REGULAR_ATTRIBUTES); + presentation.addText(devUILabel, SimpleTextAttributes.LINK_ATTRIBUTES); + + Map links = new HashMap<>(); + links.put(applicationLabel, new SimpleColoredComponent.BrowserLauncherTag(applicationUrl)); + links.put(devUILabel, new SimpleColoredComponent.BrowserLauncherTag(devUIUrl)); + node.putUserData(RunDashboardCustomizer.NODE_LINKS, links); + } + } + } + return true; + } + +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index da049d7f1..ed5b7c914 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -338,9 +338,12 @@ + + +