Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Connect Quarkus run configuration with Services view support #1268

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<Boolean>() {
@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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand All @@ -153,7 +149,7 @@ public void run(@NotNull ProgressIndicator indicator) {
}
});
}
return null;
return state;
}

private void waitForPortAvailable(int port, ProgressIndicator monitor) throws IOException {
Expand Down Expand Up @@ -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) {
Expand All @@ -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));
}

}
Original file line number Diff line number Diff line change
@@ -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:
*
* <ul>
* <li>Open quarkus application in a browser.</li>
* <li>Open quarkus DevUI in a browser.</li>
* </ul>
*/
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()) {
angelozerr marked this conversation as resolved.
Show resolved Hide resolved
// 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<Object, Object> 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;
}

}
3 changes: 3 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -338,9 +338,12 @@
<projectService serviceImplementation="com.redhat.devtools.intellij.lsp4mp4ij.classpath.ClasspathResourceChangedManager"/>
<projectService serviceImplementation="com.redhat.devtools.intellij.lsp4mp4ij.psi.core.project.PsiMicroProfileProjectManager"/>
<projectService serviceImplementation="com.redhat.devtools.intellij.quarkus.QuarkusDeploymentSupport"/>

<!--Quarkus run config -->
<projectService serviceImplementation="com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfigurationManager" />
<configurationType implementation="com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfigurationType"/>
<consoleActionsPostProcessor implementation="com.redhat.devtools.intellij.quarkus.run.QuarkusRunConsolePostProcessor"/>
<runDashboardCustomizer implementation="com.redhat.devtools.intellij.quarkus.run.dashboard.QuarkusRunDashboardCustomizer"/>

<!-- Qute -->
<facetType implementation="com.redhat.devtools.intellij.qute.facet.QuteFacetType"/>
Expand Down
Loading