From a0c467beea9ab58dcf1c54602e1ba71671f58021 Mon Sep 17 00:00:00 2001 From: Bill Burke Date: Tue, 21 Mar 2023 14:53:54 -0400 Subject: [PATCH] quarkus:run gradle --- .../java/io/quarkus/gradle/QuarkusPlugin.java | 3 + .../io/quarkus/gradle/tasks/QuarkusRun.java | 194 ++++++++++++++++++ .../base/pom.tpl.qute.xml | 2 + 3 files changed, 199 insertions(+) create mode 100644 devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusRun.java diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java index 25c0512c62886..c6d34b82d5485 100644 --- a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/QuarkusPlugin.java @@ -47,6 +47,7 @@ import io.quarkus.gradle.tasks.QuarkusListPlatforms; import io.quarkus.gradle.tasks.QuarkusRemoteDev; import io.quarkus.gradle.tasks.QuarkusRemoveExtension; +import io.quarkus.gradle.tasks.QuarkusRun; import io.quarkus.gradle.tasks.QuarkusTest; import io.quarkus.gradle.tasks.QuarkusTestConfig; import io.quarkus.gradle.tasks.QuarkusUpdate; @@ -69,6 +70,7 @@ public class QuarkusPlugin implements Plugin { public static final String QUARKUS_GENERATE_CODE_TESTS_TASK_NAME = "quarkusGenerateCodeTests"; public static final String QUARKUS_BUILD_TASK_NAME = "quarkusBuild"; public static final String QUARKUS_DEV_TASK_NAME = "quarkusDev"; + public static final String QUARKUS_RUN_TASK_NAME = "quarkusRun"; public static final String QUARKUS_REMOTE_DEV_TASK_NAME = "quarkusRemoteDev"; public static final String QUARKUS_TEST_TASK_NAME = "quarkusTest"; public static final String QUARKUS_GO_OFFLINE_TASK_NAME = "quarkusGoOffline"; @@ -174,6 +176,7 @@ private void registerTasks(Project project, QuarkusPluginExtension quarkusExt) { TaskProvider quarkusDev = tasks.register(QUARKUS_DEV_TASK_NAME, QuarkusDev.class, devRuntimeDependencies, quarkusExt); + TaskProvider quarkusRun = tasks.register(QUARKUS_RUN_TASK_NAME, QuarkusRun.class); TaskProvider quarkusRemoteDev = tasks.register(QUARKUS_REMOTE_DEV_TASK_NAME, QuarkusRemoteDev.class, devRuntimeDependencies, quarkusExt); TaskProvider quarkusTest = tasks.register(QUARKUS_TEST_TASK_NAME, QuarkusTest.class, diff --git a/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusRun.java b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusRun.java new file mode 100644 index 0000000000000..e5cc66a6328cb --- /dev/null +++ b/devtools/gradle/gradle-application-plugin/src/main/java/io/quarkus/gradle/tasks/QuarkusRun.java @@ -0,0 +1,194 @@ +package io.quarkus.gradle.tasks; + +import java.io.File; +import java.io.Serializable; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import javax.inject.Inject; + +import org.gradle.api.GradleException; +import org.gradle.api.file.FileCollection; +import org.gradle.api.model.ObjectFactory; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Classpath; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; +import org.gradle.api.tasks.TaskAction; + +import io.quarkus.bootstrap.BootstrapException; +import io.quarkus.bootstrap.app.AugmentAction; +import io.quarkus.bootstrap.app.CuratedApplication; +import io.quarkus.bootstrap.app.QuarkusBootstrap; +import io.quarkus.bootstrap.model.ApplicationModel; +import io.quarkus.bootstrap.resolver.AppModelResolverException; +import io.quarkus.deployment.run.RunCommandHandler; +import io.quarkus.deployment.run.RunCommandLaunchResultBuildItem; +import io.quarkus.gradle.extension.QuarkusPluginExtension; +import io.quarkus.maven.dependency.GACTV; + +public class QuarkusRun extends QuarkusTask { + private final Property workingDirectory; + private final SourceSet mainSourceSet; + + @Inject + public QuarkusRun() { + this("Quarkus runs target application"); + } + + public QuarkusRun(String description) { + super(description); + mainSourceSet = getProject().getExtensions().getByType(SourceSetContainer.class) + .getByName(SourceSet.MAIN_SOURCE_SET_NAME); + + final ObjectFactory objectFactory = getProject().getObjects(); + + workingDirectory = objectFactory.property(File.class); + workingDirectory.convention(getProject().provider(() -> QuarkusPluginExtension.getLastFile(getCompilationOutput()))); + + } + + /** + * The JVM classes directory (compilation output) + */ + @Optional + @InputFiles + @PathSensitive(PathSensitivity.RELATIVE) + public FileCollection getCompilationOutput() { + return mainSourceSet.getOutput().getClassesDirs(); + } + + @Input + public Property getWorkingDirectory() { + return workingDirectory; + } + + /** + * @deprecated See {@link #workingDirectory} + */ + @Deprecated + public void setWorkingDir(String workingDir) { + workingDirectory.set(getProject().file(workingDir)); + } + + @Classpath + public FileCollection getClasspath() { + SourceSet mainSourceSet = QuarkusGradleUtils.getSourceSet(getProject(), SourceSet.MAIN_SOURCE_SET_NAME); + return mainSourceSet.getCompileClasspath().plus(mainSourceSet.getRuntimeClasspath()) + .plus(mainSourceSet.getAnnotationProcessorPath()) + .plus(mainSourceSet.getResources()); + } + + @Input + public Map getQuarkusBuildSystemProperties() { + Map quarkusSystemProperties = new HashMap<>(); + for (Map.Entry systemProperty : System.getProperties().entrySet()) { + if (systemProperty.getKey().toString().startsWith("quarkus.") && + systemProperty.getValue() instanceof Serializable) { + quarkusSystemProperties.put(systemProperty.getKey(), systemProperty.getValue()); + } + } + return quarkusSystemProperties; + } + + @Input + public Map getQuarkusBuildEnvProperties() { + Map quarkusEnvProperties = new HashMap<>(); + for (Map.Entry systemProperty : System.getenv().entrySet()) { + if (systemProperty.getKey() != null && systemProperty.getKey().startsWith("QUARKUS_")) { + quarkusEnvProperties.put(systemProperty.getKey(), systemProperty.getValue()); + } + } + return quarkusEnvProperties; + } + + @TaskAction + public void runQuarkus() { + final ApplicationModel appModel; + + try { + appModel = extension().getAppModelResolver().resolveModel(new GACTV(getProject().getGroup().toString(), + getProject().getName(), getProject().getVersion().toString())); + } catch (AppModelResolverException e) { + throw new GradleException("Failed to resolve Quarkus application model for " + getProject().getPath(), e); + } + + final Properties effectiveProperties = getBuildSystemProperties(appModel.getAppArtifact()); + try (CuratedApplication curatedApplication = QuarkusBootstrap.builder() + .setBaseClassLoader(getClass().getClassLoader()) + .setExistingModel(appModel) + .setTargetDirectory(getProject().getBuildDir().toPath()) + .setBaseName(extension().finalName()) + .setBuildSystemProperties(effectiveProperties) + .setAppArtifact(appModel.getAppArtifact()) + .setLocalProjectDiscovery(false) + .setIsolateDeployment(true) + .build().bootstrap()) { + + AugmentAction action = curatedApplication.createAugmentor(); + AtomicReference exists = new AtomicReference<>(); + AtomicReference tooMany = new AtomicReference<>(); + String target = System.getProperty("quarkus.run.target"); + action.performCustomBuild(RunCommandHandler.class.getName(), new Consumer>() { + @Override + public void accept(Map cmds) { + List cmd = null; + if (target != null) { + cmd = cmds.get(target); + if (cmd == null) { + exists.set(false); + return; + } + } else if (cmds.size() == 1) { // defaults to pure java run + cmd = cmds.values().iterator().next(); + } else if (cmds.size() == 2) { // choose not default + for (Map.Entry entry : cmds.entrySet()) { + if (entry.getKey().equals("java")) + continue; + cmd = entry.getValue(); + break; + } + } else if (cmds.size() > 2) { + tooMany.set(cmds.keySet().stream().collect(Collectors.joining(" "))); + return; + } else { + throw new RuntimeException("Should never reach this!"); + } + List args = (List) cmd.get(0); + getProject().getLogger().info("Executing \"" + String.join(" ", args) + "\""); + Path wd = (Path) cmd.get(1); + File wdir = wd != null ? wd.toFile() : workingDirectory.get(); + getProject().exec(action -> { + action.commandLine(args).workingDir(wdir); + action.setStandardInput(System.in) + .setErrorOutput(System.out) + .setStandardOutput(System.out); + }); + } + }, + RunCommandLaunchResultBuildItem.class.getName()); + if (target != null && !exists.get()) { + getProject().getLogger().error("quarkus.run.target " + target + " is not found"); + return; + } + if (tooMany.get() != null) { + getProject().getLogger().error( + "Too many installed extensions support quarkus:run. Use -Dquarkus.run.target= to choose"); + getProject().getLogger().error("Extensions: " + tooMany.get()); + } + } catch (BootstrapException e) { + throw new GradleException("Failed to run application", e); + } + } +} diff --git a/devtools/project-core-extension-codestarts/src/main/resources/codestarts/quarkus/examples/azure-functions-example/base/pom.tpl.qute.xml b/devtools/project-core-extension-codestarts/src/main/resources/codestarts/quarkus/examples/azure-functions-example/base/pom.tpl.qute.xml index c5e6ca47def6a..c619d5bda1ade 100644 --- a/devtools/project-core-extension-codestarts/src/main/resources/codestarts/quarkus/examples/azure-functions-example/base/pom.tpl.qute.xml +++ b/devtools/project-core-extension-codestarts/src/main/resources/codestarts/quarkus/examples/azure-functions-example/base/pom.tpl.qute.xml @@ -41,6 +41,7 @@ +