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

Allow quarkus:run to launch DevServices #40273

Merged
merged 2 commits into from
Apr 25, 2024
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 @@ -13,6 +13,7 @@
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.pkg.PackageConfig;
import io.quarkus.deployment.pkg.builditem.BuildSystemTargetBuildItem;
import io.quarkus.deployment.pkg.builditem.LegacyJarRequiredBuildItem;
import io.quarkus.deployment.pkg.builditem.OutputTargetBuildItem;
import io.quarkus.deployment.pkg.builditem.UberJarRequiredBuildItem;
Expand All @@ -32,7 +33,8 @@ public void defaultJavaCommand(PackageConfig packageConfig,
OutputTargetBuildItem jar,
List<UberJarRequiredBuildItem> uberJarRequired,
List<LegacyJarRequiredBuildItem> legacyJarRequired,
BuildProducer<RunCommandActionBuildItem> cmds) {
BuildProducer<RunCommandActionBuildItem> cmds,
BuildSystemTargetBuildItem buildSystemTarget) {

Path jarPath = null;
if (legacyJarRequired.isEmpty() && (!uberJarRequired.isEmpty()
Expand All @@ -52,7 +54,7 @@ public void defaultJavaCommand(PackageConfig packageConfig,
List<String> args = new ArrayList<>();
args.add(determineJavaPath());

for (Map.Entry<?, ?> e : System.getProperties().entrySet()) {
for (Map.Entry<?, ?> e : buildSystemTarget.getBuildSystemProps().entrySet()) {
args.add("-D" + e.getKey().toString() + "=" + e.getValue().toString());
}
args.add("-jar");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package io.quarkus.deployment.cmd;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;

import io.quarkus.builder.BuildResult;
import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem;

public class StartDevServicesAndRunCommandHandler implements BiConsumer<Object, BuildResult> {

@Override
public void accept(Object o, BuildResult buildResult) {
var runCommandActionResult = buildResult.consume(RunCommandActionResultBuildItem.class);
var devServicesLauncherConfigResult = buildResult.consume(DevServicesLauncherConfigResultBuildItem.class);

// FYI: AugmentAction.performCustomBuild runs in its own classloader
// so we can only pass back instances of those classes in the system classloader

Consumer<Map<String, List>> consumer = (Consumer<Map<String, List>>) o;

// build up the commands
Map<String, List> cmds = new HashMap<>();
for (RunCommandActionBuildItem item : runCommandActionResult.getCommands()) {
List<String> itemList = new ArrayList<>();
addLaunchCommand(itemList, item, devServicesLauncherConfigResult.getConfig());
cmds.put(item.getCommandName(), itemList);
}

consumer.accept(cmds);
}

private void addLaunchCommand(List list, RunCommandActionBuildItem item, Map<String, String> devServicesProperties) {
List<String> effectiveArgs;
List<String> originalArgs = item.getArgs();
if (devServicesProperties.isEmpty()) {
effectiveArgs = originalArgs;
} else {
// here we want to "inject" our dev services configuration into the predetermined launch command

effectiveArgs = new ArrayList<>(originalArgs.size() + devServicesProperties.size());
int jarArgIndex = -1;
for (int i = 0; i < originalArgs.size(); i++) {
if (originalArgs.get(i).trim().equals("-jar")) {
jarArgIndex = i;
break;
}
}
if (jarArgIndex == -1) {
effectiveArgs = originalArgs;
} else {
effectiveArgs.addAll(originalArgs.subList(0, jarArgIndex));
for (var devServiceConfigEntry : devServicesProperties.entrySet()) {
effectiveArgs.add("-D" + devServiceConfigEntry.getKey() + "=" + devServiceConfigEntry.getValue());
}
effectiveArgs.addAll(originalArgs.subList(jarArgIndex, originalArgs.size()));
}
}

list.add(effectiveArgs);
list.add(item.getWorkingDirectory());
list.add(item.getStartedExpression());
list.add(item.isNeedsLogfile());
list.add(item.getLogFile());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@
import io.quarkus.bootstrap.app.CuratedApplication;
import io.quarkus.bootstrap.app.QuarkusBootstrap;
import io.quarkus.bootstrap.model.ApplicationModel;
import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem;
import io.quarkus.deployment.cmd.RunCommandActionResultBuildItem;
import io.quarkus.deployment.cmd.RunCommandHandler;
import io.quarkus.deployment.cmd.StartDevServicesAndRunCommandHandler;
import io.quarkus.gradle.extension.QuarkusPluginExtension;

public abstract class QuarkusRun extends QuarkusBuildTask {
Expand Down Expand Up @@ -111,13 +112,14 @@ public void runQuarkus() {
.setAppArtifact(appModel.getAppArtifact())
.setLocalProjectDiscovery(false)
.setIsolateDeployment(true)
.setMode(QuarkusBootstrap.Mode.TEST)
.build().bootstrap()) {

AugmentAction action = curatedApplication.createAugmentor();
AtomicReference<Boolean> exists = new AtomicReference<>();
AtomicReference<String> tooMany = new AtomicReference<>();
String target = System.getProperty("quarkus.run.target");
action.performCustomBuild(RunCommandHandler.class.getName(), new Consumer<Map<String, List>>() {
action.performCustomBuild(StartDevServicesAndRunCommandHandler.class.getName(), new Consumer<Map<String, List>>() {
@Override
public void accept(Map<String, List> cmds) {
List cmd = null;
Expand Down Expand Up @@ -166,7 +168,7 @@ public void accept(Map<String, List> cmds) {
}
}
},
RunCommandActionResultBuildItem.class.getName());
RunCommandActionResultBuildItem.class.getName(), DevServicesLauncherConfigResultBuildItem.class.getName());
if (target != null && !exists.get()) {
getProject().getLogger().error("quarkus.run.target " + target + " is not found");
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.function.Consumer;
import java.util.stream.Stream;

import org.apache.maven.AbstractMavenLifecycleParticipant;
Expand All @@ -26,6 +27,7 @@
import org.eclipse.aether.repository.RemoteRepository;

import io.quarkus.bootstrap.app.CuratedApplication;
import io.quarkus.bootstrap.app.QuarkusBootstrap;
import io.quarkus.maven.components.BootstrapSessionListener;
import io.quarkus.maven.components.ManifestSection;
import io.quarkus.maven.dependency.ArtifactKey;
Expand Down Expand Up @@ -294,6 +296,11 @@ protected CuratedApplication bootstrapApplication(LaunchMode mode) throws MojoEx
return bootstrapProvider.bootstrapApplication(this, mode);
}

protected CuratedApplication bootstrapApplication(LaunchMode mode, Consumer<QuarkusBootstrap.Builder> builderCustomizer)
throws MojoExecutionException {
return bootstrapProvider.bootstrapApplication(this, mode, builderCustomizer);
}

protected Properties getBuildSystemProperties(boolean quarkusOnly) throws MojoExecutionException {
return bootstrapProvider.bootstrapper(this).getBuildSystemProperties(this, quarkusOnly);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;

import javax.inject.Inject;
import javax.inject.Named;
Expand Down Expand Up @@ -126,7 +127,13 @@ public QuarkusMavenAppBootstrap bootstrapper(QuarkusBootstrapMojo mojo) {

public CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, LaunchMode mode)
throws MojoExecutionException {
return bootstrapper(mojo).bootstrapApplication(mojo, mode);
return bootstrapApplication(mojo, mode, null);
}

public CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, LaunchMode mode,
Consumer<QuarkusBootstrap.Builder> builderCustomizer)
throws MojoExecutionException {
return bootstrapper(mojo).bootstrapApplication(mojo, mode, builderCustomizer);
}

public ApplicationModel getResolvedApplicationModel(ArtifactKey projectId, LaunchMode mode, String bootstrapId) {
Expand Down Expand Up @@ -203,7 +210,8 @@ private MavenArtifactResolver artifactResolver(QuarkusBootstrapMojo mojo, Launch
}
}

private CuratedApplication doBootstrap(QuarkusBootstrapMojo mojo, LaunchMode mode)
private CuratedApplication doBootstrap(QuarkusBootstrapMojo mojo, LaunchMode mode,
Consumer<QuarkusBootstrap.Builder> builderCustomizer)
throws MojoExecutionException {

final BootstrapAppModelResolver modelResolver = new BootstrapAppModelResolver(artifactResolver(mojo, mode))
Expand Down Expand Up @@ -253,6 +261,9 @@ private CuratedApplication doBootstrap(QuarkusBootstrapMojo mojo, LaunchMode mod
.setForcedDependencies(forcedDependencies);

try {
if (builderCustomizer != null) {
builderCustomizer.accept(builder);
}
return builder.build().bootstrap();
} catch (BootstrapException e) {
throw new MojoExecutionException("Failed to bootstrap the application", e);
Expand Down Expand Up @@ -346,15 +357,16 @@ private String toManifestSectionAttributeKey(String section, String key) throws
key);
}

protected CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, LaunchMode mode)
protected CuratedApplication bootstrapApplication(QuarkusBootstrapMojo mojo, LaunchMode mode,
Consumer<QuarkusBootstrap.Builder> builderCustomizer)
throws MojoExecutionException {
if (mode == LaunchMode.DEVELOPMENT) {
return devApp == null ? devApp = doBootstrap(mojo, mode) : devApp;
return devApp == null ? devApp = doBootstrap(mojo, mode, builderCustomizer) : devApp;
}
if (mode == LaunchMode.TEST) {
return testApp == null ? testApp = doBootstrap(mojo, mode) : testApp;
return testApp == null ? testApp = doBootstrap(mojo, mode, builderCustomizer) : testApp;
}
return prodApp == null ? prodApp = doBootstrap(mojo, mode) : prodApp;
return prodApp == null ? prodApp = doBootstrap(mojo, mode, builderCustomizer) : prodApp;
}

protected ArtifactCoords managingProject(QuarkusBootstrapMojo mojo) {
Expand Down
18 changes: 14 additions & 4 deletions devtools/maven/src/main/java/io/quarkus/maven/RunMojo.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@

import io.quarkus.bootstrap.app.AugmentAction;
import io.quarkus.bootstrap.app.CuratedApplication;
import io.quarkus.bootstrap.app.QuarkusBootstrap;
import io.quarkus.deployment.builditem.DevServicesLauncherConfigResultBuildItem;
import io.quarkus.deployment.cmd.RunCommandActionResultBuildItem;
import io.quarkus.deployment.cmd.RunCommandHandler;
import io.quarkus.deployment.cmd.StartDevServicesAndRunCommandHandler;
import io.quarkus.runtime.LaunchMode;

@Mojo(name = "run")
public class RunMojo extends QuarkusBootstrapMojo {
Expand Down Expand Up @@ -47,12 +50,19 @@ protected void doExecute() throws MojoExecutionException, MojoFailureException {
}
}

try (CuratedApplication curatedApplication = bootstrapApplication()) {
try (CuratedApplication curatedApplication = bootstrapApplication(LaunchMode.NORMAL,
new Consumer<QuarkusBootstrap.Builder>() {
@Override
public void accept(QuarkusBootstrap.Builder builder) {
// we need this for dev services
builder.setMode(QuarkusBootstrap.Mode.TEST);
}
})) {
AugmentAction action = curatedApplication.createAugmentor();
AtomicReference<Boolean> exists = new AtomicReference<>();
AtomicReference<String> tooMany = new AtomicReference<>();
String target = System.getProperty("quarkus.run.target");
action.performCustomBuild(RunCommandHandler.class.getName(), new Consumer<Map<String, List>>() {
action.performCustomBuild(StartDevServicesAndRunCommandHandler.class.getName(), new Consumer<Map<String, List>>() {
@Override
public void accept(Map<String, List> cmds) {
List cmd = null;
Expand Down Expand Up @@ -94,7 +104,7 @@ public void accept(Map<String, List> cmds) {
}
}
},
RunCommandActionResultBuildItem.class.getName());
RunCommandActionResultBuildItem.class.getName(), DevServicesLauncherConfigResultBuildItem.class.getName());
if (target != null && !exists.get()) {
getLog().error("quarkus.run.target " + target + " is not found");
return;
Expand Down
Loading