This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 86e04170f3a1 CAMEL-24726: camel-jbang-export - ProjectRunner runs the
integration with Quarkus and Spring Boot, as camel run does (#28741)
86e04170f3a1 is described below
commit 86e04170f3a1f8310e8fc6ebea8a1bfbe824955a
Author: Claus Ibsen <[email protected]>
AuthorDate: Fri Oct 30 22:36:51 2026 +0100
CAMEL-24726: camel-jbang-export - ProjectRunner runs the integration with
Quarkus and Spring Boot, as camel run does (#28741)
Signed-off-by: Claus Ibsen <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
---
.../apache/camel/dsl/jbang/core/commands/Run.java | 591 +--------------------
.../jbang/core/commands/RunExportGoldenTest.java | 7 +-
.../core/commands/RunExportedProjectTest.java | 103 ----
.../camel/dsl/jbang/core/commands/RunTest.java | 55 +-
.../dsl/jbang/export/run/CamelMainRunner.java | 81 +--
.../dsl/jbang/export/run/MavenRunSupport.java | 216 ++++++--
.../camel/dsl/jbang/export/run/ProjectRunner.java | 19 +-
.../camel/dsl/jbang/export/run/QuarkusRunner.java | 194 +++++++
.../camel/dsl/jbang/export/run/RunPipeline.java | 10 +-
.../camel/dsl/jbang/export/run/RunRequest.java | 14 +
.../dsl/jbang/export/run/SpringBootRunner.java | 212 ++++++++
.../src/main/resources/spring-boot-logback.xml | 0
.../dsl/jbang/export/run/ProjectRunnerTest.java | 116 +++-
.../jbang/export/run}/RunExistingProjectTest.java | 83 +--
.../jbang/export/run/RunExportedProjectTest.java | 175 ++++++
.../run}/RunMavenRuntimePreviousLogTest.java | 15 +-
16 files changed, 1025 insertions(+), 866 deletions(-)
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
index 400176e87728..1bf17133364d 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/Run.java
@@ -20,18 +20,14 @@ import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.UnsupportedFlavorException;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.Reader;
-import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.ParseException;
import java.util.*;
-import java.util.concurrent.atomic.AtomicReference;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@@ -58,18 +54,13 @@ import
org.apache.camel.dsl.jbang.core.common.ProfileCompletionCandidates;
import org.apache.camel.dsl.jbang.core.common.RunRuntimeCompletionCandidates;
import org.apache.camel.dsl.jbang.core.common.RunRuntimeTypeConverter;
import org.apache.camel.dsl.jbang.core.common.TerminalWidthHelper;
-import org.apache.camel.dsl.jbang.export.ExportRequest;
-import org.apache.camel.dsl.jbang.export.ProjectExporter;
-import org.apache.camel.dsl.jbang.export.common.ChildProcess;
import org.apache.camel.dsl.jbang.export.common.ExportHelper;
-import org.apache.camel.dsl.jbang.export.common.MavenCommand;
import org.apache.camel.dsl.jbang.export.common.PreviousRun;
import org.apache.camel.dsl.jbang.export.common.Printer;
import org.apache.camel.dsl.jbang.export.common.RuntimeType;
import org.apache.camel.dsl.jbang.export.common.RuntimeUtil;
import org.apache.camel.dsl.jbang.export.common.TemplateHelper;
import org.apache.camel.dsl.jbang.export.common.VersionHelper;
-import org.apache.camel.dsl.jbang.export.run.MavenRunSupport;
import org.apache.camel.dsl.jbang.export.run.ProjectRunner;
import org.apache.camel.dsl.jbang.export.run.RunContext;
import org.apache.camel.dsl.jbang.export.run.RunPipeline;
@@ -88,10 +79,6 @@ import org.apache.camel.util.StringHelper;
import org.apache.camel.util.TimeUtils;
import org.apache.camel.util.json.JsonObject;
import org.apache.camel.util.json.Jsoner;
-import org.apache.maven.model.Dependency;
-import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
@@ -99,11 +86,6 @@ import picocli.CommandLine.Parameters;
import static
org.apache.camel.dsl.jbang.core.common.CamelCommandHelper.extractState;
import static org.apache.camel.dsl.jbang.export.common.CamelJBangConstants.*;
-import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.keepLeftoverRunLog;
-import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.keepRunLog;
-import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.resolveExistingProjectAppName;
-import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.resolveExportedAppName;
-import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.runLogFile;
@Command(name = "run", description = "Run as local Camel integration",
sortOptions = false, showDefaultValues = true,
footer = {
@@ -122,13 +104,9 @@ public class Run extends CamelCommand {
public static final String RUN_JAVA_SH = "classpath:templates/run-java.sh";
public static final String RUN_SETTINGS_FILE =
ExportHelper.RUN_SETTINGS_FILE;
- public static final String RUN_PLATFORM_DIR =
MavenRunSupport.RUN_PLATFORM_DIR;
+ public static final String RUN_PLATFORM_DIR =
ProjectRunner.RUN_PLATFORM_DIR;
private static final String CLIPBOARD_GENERATED_FILE =
"generated-clipboard";
- // the same layout as the camel-jbang console logging, so the log file
reads the same for every runtime
- static final String QUARKUS_LOG_FILE_FORMAT
- = "%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %i --- [%15.15t] %-40.40c{3.} :
%s%e%n";
-
private static final Pattern PACKAGE_PATTERN = Pattern.compile(
"^\\s*package\\s+([a-zA-Z][.\\w]*)\\s*;.*$", Pattern.MULTILINE);
@@ -626,9 +604,6 @@ public class Run extends CamelCommand {
}
}
- // the logback configuration of an existing Spring Boot project run, in a
temp file
- private Path springBootLogback;
-
public Integer runTransform(boolean ignoreLoadingError) throws Exception {
// just boot silently and exit
this.transformRun = true;
@@ -876,168 +851,25 @@ public class Run extends CamelCommand {
}
boolean jfrEnabled() {
- return MavenRunSupport.jfrEnabled(toRunRequest(exportBaseDir));
+ return toRunRequest(exportBaseDir).jfrEnabled();
}
String jfrFileName() {
- return MavenRunSupport.jfrFileName(toRunRequest(exportBaseDir));
- }
-
- /**
- * The JFR JVM arguments for runtimes that fork a subprocess (Quarkus,
Spring Boot), or {@code null} when JFR was
- * not requested.
- */
- String buildJfrJvmArgs() {
- return MavenRunSupport.jfrJvmArgs(toRunRequest(exportBaseDir),
printer());
- }
-
- /**
- * The execution limits ({@code --max-seconds}, {@code --max-messages} and
{@code --max-idle-seconds}) as
- * {@code camel.main.durationMax*} system properties, which all the
runtimes honour.
- */
- List<String> buildDurationLimitArgs() {
- return MavenRunSupport.durationLimitArgs(toRunRequest(exportBaseDir));
- }
-
- /**
- * The JVM arguments the exported Quarkus or Spring Boot project is run
with ({@code jvm.args} and
- * {@code spring-boot.run.jvmArguments}): {@code --jvm-args}, the flight
recording and the execution limits. Returns
- * null when there are none.
- */
- String buildExportedRunJvmArgs() {
- return MavenRunSupport.exportedRunJvmArgs(toRunRequest(exportBaseDir),
printer());
+ return toRunRequest(exportBaseDir).jfrFileName();
}
protected int runQuarkus() throws Exception {
if (background) {
throw CliException.usage("Run Camel Quarkus with --background is
not supported");
}
+ return runWithMaven();
+ }
- AtomicReference<Process> processRef = new AtomicReference<>();
-
- // existing Maven project: run directly without export
- if (files != null && files.size() == 1 &&
files.get(0).endsWith("pom.xml")) {
- return runExistingQuarkusProject(processRef);
- }
-
- AtomicReference<String> appNameRef = new AtomicReference<>();
-
- // create temp run dir
- Path runDirPath = Paths.get(RUN_PLATFORM_DIR,
Long.toString(System.currentTimeMillis()));
- if (!this.background) {
- // Mark for deletion on exit
- // the process (and those it started) stops with this JVM, then
the files of the run are removed
- ChildProcess.stopOnExit(processRef::get, () -> {
- removeDir(runDirPath);
- // the log is kept as the previous run of the app (CAMEL-25832)
- keepRunLog(appNameRef.get(), processRef.get(), false);
- });
- }
- Files.createDirectories(runDirPath);
-
- // export to hidden folder
- ExportRequest eq = new ExportRequest();
- eq.baseDir = this.exportBaseDir;
- eq.javaLiveReload = this.dev;
- eq.symbolicLink = this.dev;
- eq.mavenWrapper = true;
- eq.quarkusPlatform = this.quarkusPlatform.toPlatform();
- eq.javaVersion = javaVersion;
- eq.camelVersion = this.camelVersion;
- eq.javaVersion = this.javaVersion;
- eq.kameletsVersion = this.kameletsVersion;
- eq.exportDir = runDirPath.toString();
- eq.localKameletDir = this.localKameletDir;
- eq.excludes = this.excludes;
- eq.files = this.files;
- eq.name = this.name;
- eq.verbose = this.verbose;
- eq.port = this.serverOptions.port;
- eq.managementPort = this.serverOptions.managementPort;
- eq.gav = this.gav;
- eq.runtime = this.runtime;
- if (eq.gav == null) {
- if (eq.name == null) {
- eq.name = "jbang-run-dummy";
- }
- eq.gav = "org.example.project:" + eq.name + ":1.0-SNAPSHOT";
- }
- eq.dependencies = this.dependencies;
- eq.dependencies.add("camel:cli-connector");
- if (jfrEnabled()) {
- eq.dependencies.add("camel:jfr");
- }
- eq.mavenResolver = this.mavenResolver.toResolver();
- eq.skipPlugins = this.skipPlugins;
- eq.packageScanJars = this.packageScanJars;
- eq.quiet = true;
- eq.logging = false;
- eq.loggingLevel = "off";
- eq.ignoreLoadingError = this.ignoreLoadingError;
- eq.lazyBean = this.lazyBean;
- eq.profile = this.profile;
- eq.observe = this.serverOptions.observe;
- eq.console = this.serverOptions.console;
- eq.consoleForRun = true;
- eq.applicationProperties = this.property;
-
- printer().println("Running using Quarkus (preparing and downloading
files)");
-
- // run export
- ExportBaseCommand.applySystemProperties(eq);
- int exit = new ProjectExporter(CliExportContext.create(getMain(),
getMain().getOut(), eq.yes))
- .export(eq.baseDir, eq);
- if (exit != 0) {
- return exit;
- }
-
- // the exported project may have derived the application name from the
source files, and the log file
- // must be named after the name the application reports (which is what
camel log and the TUI look for)
- String appName = resolveExportedAppName(runDirPath, eq.name);
- appNameRef.set(appName);
- keepLeftoverRunLog(appName);
-
- // prepare quarkus for logging to file
- Path appProps = Paths.get(eq.exportDir,
"src/main/resources/application.properties");
- if (Files.exists(appProps)) {
- String content = Files.readString(appProps);
- // in the Camel directory of the CLI, where camel log looks for it
(as for an existing Quarkus project)
- String logFile = CommandLineHelper.getCamelDir().resolve(appName +
".log").toAbsolutePath().toString()
- .replace("\\", "/");
- content += "\n# logging to file\n"
- + "quarkus.log.file.enabled=true\n"
- + "quarkus.log.file.path=" + logFile + "\n"
- + "quarkus.log.file.format=" + QUARKUS_LOG_FILE_FORMAT
+ "\n";
- Files.writeString(appProps, content);
+ protected int runSpringBoot() throws Exception {
+ if (background) {
+ throw CliException.usage("Run Camel Spring Boot with --background
is not supported");
}
-
- // run quarkus via maven
- ProcessBuilder pb = new ProcessBuilder();
- List<String> mvnCmd = new ArrayList<>();
- mvnCmd.add(MavenCommand.wrapper(runDirPath).toString());
- mvnCmd.add("--quiet");
- mvnCmd.add("--file");
- mvnCmd.add(runDirPath.toRealPath().resolve("pom.xml").toString());
- String quarkusRunJvmArgs = buildExportedRunJvmArgs();
- if (quarkusRunJvmArgs != null) {
- mvnCmd.add("-Djvm.args=" + quarkusRunJvmArgs);
- }
- if (serverOptions.console) {
- // the console extension only exposes the console in dev and test
mode, and camel run without --dev is
- // quarkus:run (prod mode). This is build-time configuration, and
is set on the build of this temporary
- // project only, so an exported project does not have the console
exposed in prod mode
- mvnCmd.add("-Dquarkus.camel.console.exposure-mode=ALL");
- }
- mvnCmd.add("package");
- mvnCmd.add("quarkus:" + (dev ? "dev" : "run"));
- pb.command(mvnCmd);
-
- pb.inheritIO(); // run in foreground (with IO so logs are visible)
- Process p = startProcess(pb);
- processRef.set(p);
- this.spawnPid = p.pid();
- // wait for that process to exit as we run in foreground
- return p.waitFor();
+ return runWithMaven();
}
protected int runCamelMain() throws Exception {
@@ -1056,64 +888,27 @@ public class Run extends CamelCommand {
}
}
+ return runWithMaven();
+ }
+
+ /**
+ * Runs with Maven (Camel Main, Quarkus or Spring Boot) through {@link
ProjectRunner}, in the foreground.
+ */
+ private int runWithMaven() throws Exception {
RunRequest request = toRunRequest(exportBaseDir);
ExportBaseCommand.applySystemProperties(request);
- RunContext context = CliExportContext.configure(new RunContext(),
getMain(), printer(), false)
- .withProcessStarter(this::startProcess);
- RunningIntegration integration = new
ProjectRunner(context).start(request);
+ RunningIntegration integration = new
ProjectRunner(runContext()).start(request);
this.spawnPid = integration.pid();
// wait for the application to exit as we run in foreground
return integration.waitFor();
}
/**
- * Starts a process of a run with Maven: the build of the project, or the
application. Tests that check what such a
- * run does replace it, so they run neither Maven nor the application.
+ * The context of a run with Maven: the printer, the plugins and the
dependency resolver of the CLI. Tests that
+ * check what such a run does set a process starter, so they run neither
Maven nor the application.
*/
- protected Process startProcess(ProcessBuilder pb) throws IOException {
- return pb.start();
- }
-
- /**
- * The {@code -D} system properties an existing Maven project is run with:
the HTTP port ({@code --port}, as the
- * given property), the execution limits ({@code --max-seconds}, {@code
--max-messages} and
- * {@code --max-idle-seconds}) and the additional properties ({@code
--prop}).
- */
- List<String> buildExistingProjectSystemProperties(String portKey) {
- return
MavenRunSupport.existingProjectSystemProperties(toRunRequest(exportBaseDir),
portKey);
- }
-
- /**
- * The Quarkus logging properties that make an existing Quarkus project
also log to the {@code <name>.log} file in
- * the {@code ~/.camel} directory (the same as the exported project does
via its application.properties).
- */
- static List<String> buildQuarkusLogFileJvmArgs(String appName) {
- Path logFile = CommandLineHelper.getCamelDir().resolve(appName +
".log");
- String fileName = logFile.toAbsolutePath().toString().replace("\\",
"/");
- List<String> args = new ArrayList<>();
- args.add("-Dquarkus.log.file.enabled=true");
- args.add("-Dquarkus.log.file.path=" + fileName);
- // quoted as the format has spaces (quarkus:dev parses jvm.args as a
command line)
- args.add("-Dquarkus.log.file.format=\"" + QUARKUS_LOG_FILE_FORMAT +
"\"");
- return args;
- }
-
- /**
- * Writes the logback configuration used by {@code camel run
--runtime=spring-boot} to the given file. It logs to
- * the console, and to the {@code <name>.log} file in the Camel directory,
as the other runtimes do, so the log can
- * be kept as the previous run of the app (CAMEL-25832).
- */
- static void writeSpringBootLogbackConfig(Path target, String appName)
throws IOException {
- String fileName =
runLogFile(appName).toAbsolutePath().toString().replace("\\", "/")
- .replace("&", "&").replace("<", "<").replace("\"",
""");
- try (InputStream is =
Run.class.getClassLoader().getResourceAsStream("spring-boot-logback.xml")) {
- if (is == null) {
- throw new IOException("spring-boot-logback.xml not found");
- }
- String content = new String(is.readAllBytes(),
StandardCharsets.UTF_8).replace("{{logFile}}", fileName);
- Files.createDirectories(target.getParent());
- Files.writeString(target, content);
- }
+ protected RunContext runContext() {
+ return CliExportContext.configure(new RunContext(), getMain(),
printer(), false);
}
/**
@@ -1131,349 +926,6 @@ public class Run extends CamelCommand {
}
}
- private int runExistingQuarkusProject(AtomicReference<Process> processRef)
throws Exception {
- Path pomPath = Path.of(files.get(0)).toAbsolutePath();
- Path projectDir = pomPath.getParent();
-
- // read the pom.xml and add camel-quarkus-cli-connector dependency
- MavenXpp3Reader mavenReader = new MavenXpp3Reader();
- Model model;
- try (Reader reader = Files.newBufferedReader(pomPath)) {
- model = mavenReader.read(reader);
- }
-
- boolean hasCliConnector = model.getDependencies().stream()
- .anyMatch(d ->
"camel-quarkus-cli-connector".equals(d.getArtifactId()));
- if (!hasCliConnector) {
- Dependency d = new Dependency();
- d.setGroupId("org.apache.camel.quarkus");
- d.setArtifactId("camel-quarkus-cli-connector");
- model.getDependencies().add(d);
- }
- if (jfrEnabled()) {
- boolean hasJfr = model.getDependencies().stream()
- .anyMatch(d ->
"camel-quarkus-jfr".equals(d.getArtifactId()));
- if (!hasJfr) {
- Dependency d = new Dependency();
- d.setGroupId("org.apache.camel.quarkus");
- d.setArtifactId("camel-quarkus-jfr");
- model.getDependencies().add(d);
- }
- }
-
- // write temporary pom with cli-connector injected
- Path tempPom = projectDir.resolve("camel-jbang-run-pom.xml");
- MavenXpp3Writer w = new MavenXpp3Writer();
- try (FileOutputStream fos = new FileOutputStream(tempPom.toFile())) {
- w.write(fos, model);
- }
-
- // log to console and to file in ~/.camel (so camel log and the TUI
can tail the logs)
- String appName = resolveExistingProjectAppName(projectDir, model);
- keepLeftoverRunLog(appName);
-
- // shutdown hook to clean up temp files
- // the process (and those it started) stops with this JVM, then the
files of the run are removed
- ChildProcess.stopOnExit(processRef::get, () -> {
- Files.deleteIfExists(tempPom);
- // the log is kept as the previous run of the app (CAMEL-25832)
- keepRunLog(appName, processRef.get(), false);
- });
-
- // find mvnw or fall back to mvn
- String mvnCmd = MavenCommand.of(projectDir);
-
- List<String> cmd = new ArrayList<>();
- cmd.add(mvnCmd);
- cmd.add("--quiet");
- cmd.add("--file");
- cmd.add(tempPom.toString());
- cmd.add("-Djvm.args=" + String.join(" ",
buildExistingQuarkusJvmArgs(appName)));
- cmd.add("-DskipTests");
- cmd.add("package");
- cmd.add("quarkus:" + (dev ? "dev" : "run"));
-
- printer().println("Running Quarkus project: " + projectDir);
-
- ProcessBuilder pb = new ProcessBuilder();
- pb.command(cmd);
- pb.directory(projectDir.toFile());
- pb.inheritIO();
- Process p = startProcess(pb);
- processRef.set(p);
- this.spawnPid = p.pid();
- return p.waitFor();
- }
-
- /**
- * The JVM arguments ({@code jvm.args}) an existing Quarkus project is run
with: logging to file, the profile, the
- * name, the port and properties, the flight recording and {@code
--jvm-args}.
- */
- List<String> buildExistingQuarkusJvmArgs(String appName) {
- List<String> args = new
ArrayList<>(buildQuarkusLogFileJvmArgs(appName));
- if (profile != null && !"prod".equals(profile)) {
- args.add("-Dcamel.main.profile=" + profile);
- }
- args.add("-Dcamel.main.name=" + appName);
- args.addAll(buildExistingProjectSystemProperties("quarkus.http.port"));
- String jfrArg = buildJfrJvmArgs();
- if (jfrArg != null) {
- args.add(jfrArg);
- }
- if (jvmArgs != null && !jvmArgs.isBlank()) {
- args.add(jvmArgs.trim());
- }
- return args;
- }
-
- protected int runSpringBoot() throws Exception {
- if (background) {
- throw CliException.usage("Run Camel Spring Boot with --background
is not supported");
- }
-
- AtomicReference<Process> processRef = new AtomicReference<>();
-
- // existing Maven project: run directly without export
- if (files != null && files.size() == 1 &&
files.get(0).endsWith("pom.xml")) {
- return runExistingSpringBootProject(processRef);
- }
-
- AtomicReference<String> appNameRef = new AtomicReference<>();
-
- // create temp run dir
- Path runDirPath = Paths.get(RUN_PLATFORM_DIR,
Long.toString(System.currentTimeMillis()));
- if (!this.background) {
- // Mark for deletion on exit
- // the process (and those it started) stops with this JVM, then
the files of the run are removed
- ChildProcess.stopOnExit(processRef::get, () -> {
- removeDir(runDirPath);
- // the log is kept as the previous run of the app (CAMEL-25832)
- keepRunLog(appNameRef.get(), processRef.get(), false);
- });
- }
- Files.createDirectories(runDirPath);
-
- // export to hidden folder
- ExportRequest eq = new ExportRequest();
- eq.baseDir = this.exportBaseDir;
- // the code reload is not supported, since we use symlink, spring-boot
devtools doesn't support symlink
- if (this.dev) {
- printer().printWarn("Code reload is not supported with Spring
Boot.");
- }
- eq.javaLiveReload = false;
- eq.symbolicLink = this.dev;
- eq.mavenWrapper = true;
- eq.springBootVersion = this.springBootVersion;
- eq.javaVersion = this.javaVersion;
- eq.camelVersion = this.camelVersion;
- eq.camelSpringBootVersion = this.camelSpringBootVersion != null ?
this.camelSpringBootVersion : this.camelVersion;
- eq.javaVersion = this.javaVersion;
- eq.kameletsVersion = this.kameletsVersion;
- eq.exportDir = runDirPath.toString();
- eq.localKameletDir = this.localKameletDir;
- eq.excludes = this.excludes;
- eq.files = this.files;
- eq.name = this.name;
- eq.verbose = this.verbose;
- eq.port = this.serverOptions.port;
- eq.managementPort = this.serverOptions.managementPort;
- eq.gav = this.gav;
- eq.mavenResolver = this.mavenResolver.toResolver();
- eq.runtime = this.runtime;
- if (eq.gav == null) {
- if (eq.name == null) {
- eq.name = "jbang-run-dummy";
- }
- eq.gav = "org.example.project:" + eq.name + ":1.0-SNAPSHOT";
- }
- eq.dependencies.addAll(this.dependencies);
- eq.dependencies.add("camel:cli-connector");
- if (jfrEnabled()) {
- eq.dependencies.add("camel:jfr");
- }
- if (this.dev) {
- // hot-reload of spring-boot
-
eq.dependencies.add("mvn:org.springframework.boot:spring-boot-devtools");
- }
- eq.skipPlugins = this.skipPlugins;
- eq.packageScanJars = this.packageScanJars;
- eq.quiet = true;
- eq.logging = false;
- eq.loggingLevel = "off";
- eq.ignoreLoadingError = this.ignoreLoadingError;
- eq.lazyBean = this.lazyBean;
- eq.profile = this.profile;
- eq.observe = this.serverOptions.observe;
- eq.console = this.serverOptions.console;
- eq.consoleForRun = true;
- eq.applicationProperties = this.property;
-
- printer().println("Running using Spring Boot (preparing and
downloading files)");
-
- // run export
- ExportBaseCommand.applySystemProperties(eq);
- int exit = new ProjectExporter(CliExportContext.create(getMain(),
getMain().getOut(), eq.yes))
- .export(eq.baseDir, eq);
- if (exit != 0) {
- return exit;
- }
-
- // the exported project may have derived the application name from the
source files, and the log file is
- // named after the name the application reports (what camel log and
the TUI look for)
- String appName = resolveExportedAppName(runDirPath, eq.name);
- appNameRef.set(appName);
- keepLeftoverRunLog(appName);
-
- // prepare spring-boot for logging to file
- writeSpringBootLogbackConfig(Paths.get(eq.exportDir,
"src/main/resources/logback.xml"), appName);
-
- // run spring-boot via maven
- ProcessBuilder pb = new ProcessBuilder();
- List<String> mvnCmd = new ArrayList<>();
- mvnCmd.add(MavenCommand.wrapper(runDirPath).toString());
- mvnCmd.add("--quiet");
- mvnCmd.add("--file");
- mvnCmd.add(runDirPath.toRealPath().resolve("pom.xml").toString());
- String springBootRunJvmArgs = buildExportedRunJvmArgs();
- if (springBootRunJvmArgs != null) {
- mvnCmd.add("-Dspring-boot.run.jvmArguments=" +
springBootRunJvmArgs);
- }
- // run in the current directory, not the export folder, so the routes
read and write files relative to where
- // camel run is started (CAMEL-25423)
- mvnCmd.add("-Dspring-boot.run.workingDirectory=" +
Paths.get(".").toAbsolutePath().normalize());
- mvnCmd.add("spring-boot:run");
- pb.command(mvnCmd);
-
- pb.inheritIO(); // run in foreground (with IO so logs are visible)
- Process p = startProcess(pb);
- processRef.set(p);
- this.spawnPid = p.pid();
- // wait for that process to exit as we run in foreground
- return p.waitFor();
- }
-
- /**
- * The logback configuration an existing Spring Boot project runs with,
logging to the {@code <name>.log} file so
- * the TUI can read the log: a temp file, so the project is not changed
and needs no src/main/resources. Null when
- * it cannot be written.
- */
- Path springBootLogbackConfig(String appName) {
- if (springBootLogback == null) {
- try {
- Path file = Files.createTempFile("camel-jbang-logback-",
".xml");
- file.toFile().deleteOnExit();
- writeSpringBootLogbackConfig(file, appName);
- springBootLogback = file;
- } catch (IOException e) {
- return null;
- }
- }
- return springBootLogback;
- }
-
- /**
- * The JVM arguments ({@code spring-boot.run.jvmArguments}) an existing
Spring Boot project is run with: logging to
- * file, the profile, the name (so the app reports the name of its log
file), the port and properties, the flight
- * recording and {@code --jvm-args}.
- */
- List<String> buildExistingSpringBootJvmArgs(String appName) {
- List<String> args = new ArrayList<>();
- Path logback = springBootLogbackConfig(appName);
- if (logback != null) {
- args.add("-Dlogging.config=" + logback.toUri());
- }
- if (profile != null && !"prod".equals(profile)) {
- args.add("-Dcamel.main.profile=" + profile);
- }
- args.add("-Dcamel.main.name=" + appName);
- args.addAll(buildExistingProjectSystemProperties("server.port"));
- String jfrArg = buildJfrJvmArgs();
- if (jfrArg != null) {
- args.add(jfrArg);
- }
- if (jvmArgs != null && !jvmArgs.isBlank()) {
- args.add(jvmArgs.trim());
- }
- return args;
- }
-
- private int runExistingSpringBootProject(AtomicReference<Process>
processRef) throws Exception {
- Path pomPath = Path.of(files.get(0)).toAbsolutePath();
- Path projectDir = pomPath.getParent();
-
- // read the pom.xml and add camel-cli-connector-starter dependency
- MavenXpp3Reader mavenReader = new MavenXpp3Reader();
- Model model;
- try (Reader reader = Files.newBufferedReader(pomPath)) {
- model = mavenReader.read(reader);
- }
-
- boolean hasCliConnector = model.getDependencies().stream()
- .anyMatch(d ->
"camel-cli-connector-starter".equals(d.getArtifactId()));
- if (!hasCliConnector) {
- Dependency d = new Dependency();
- d.setGroupId("org.apache.camel.springboot");
- d.setArtifactId("camel-cli-connector-starter");
- model.getDependencies().add(d);
- }
- if (jfrEnabled()) {
- boolean hasJfr = model.getDependencies().stream()
- .anyMatch(d ->
"camel-jfr-starter".equals(d.getArtifactId()));
- if (!hasJfr) {
- Dependency d = new Dependency();
- d.setGroupId("org.apache.camel.springboot");
- d.setArtifactId("camel-jfr-starter");
- model.getDependencies().add(d);
- }
- }
-
- // write temporary pom with cli-connector injected
- Path tempPom = projectDir.resolve("camel-jbang-run-pom.xml");
- MavenXpp3Writer w = new MavenXpp3Writer();
- try (FileOutputStream fos = new FileOutputStream(tempPom.toFile())) {
- w.write(fos, model);
- }
-
- // log to console and to file in ~/.camel (so camel log and the TUI
can tail the logs)
- String appName = resolveExistingProjectAppName(projectDir, model);
- keepLeftoverRunLog(appName);
-
- // shutdown hook to clean up temp files
- // the process (and those it started) stops with this JVM, then the
files of the run are removed
- ChildProcess.stopOnExit(processRef::get, () -> {
- Files.deleteIfExists(tempPom);
- if (springBootLogback != null) {
- Files.deleteIfExists(springBootLogback);
- }
- // the log is kept as the previous run of the app (CAMEL-25832)
- keepRunLog(appName, processRef.get(), false);
- });
-
- // find mvnw or fall back to mvn
- String mvnCmd = MavenCommand.of(projectDir);
-
- List<String> cmd = new ArrayList<>();
- cmd.add(mvnCmd);
- cmd.add("--quiet");
- cmd.add("--file");
- cmd.add(tempPom.toString());
- cmd.add("-Dspring-boot.run.jvmArguments=" + String.join(" ",
buildExistingSpringBootJvmArgs(appName)));
- cmd.add("-DskipTests");
- cmd.add("package");
- cmd.add("spring-boot:run");
-
- printer().println("Running Spring Boot project: " + projectDir);
-
- ProcessBuilder pb = new ProcessBuilder();
- pb.command(cmd);
- pb.directory(projectDir.toFile());
- pb.inheritIO();
- Process p = startProcess(pb);
- processRef.set(p);
- this.spawnPid = p.pid();
- return p.waitFor();
- }
-
protected void doAddInitialProperty(KameletMain main) {
// noop
}
@@ -1521,6 +973,7 @@ public class Run extends CamelCommand {
request.packageScanJars = packageScanJars;
request.camelVersion = camelVersion;
request.springBootVersion = springBootVersion;
+ request.camelSpringBootVersion = camelSpringBootVersion;
request.quarkusPlatform = quarkusPlatform != null ?
quarkusPlatform.toPlatform() : null;
request.kameletsVersion = kameletsVersion;
request.javaVersion = javaVersion;
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExportGoldenTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExportGoldenTest.java
index f72614b6f2a8..35c72be61875 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExportGoldenTest.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExportGoldenTest.java
@@ -39,6 +39,7 @@ import
org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
import org.apache.camel.dsl.jbang.export.common.ExportHelper;
import org.apache.camel.dsl.jbang.export.common.PathUtils;
import org.apache.camel.dsl.jbang.export.common.RuntimeType;
+import org.apache.camel.dsl.jbang.export.run.RunContext;
import org.apache.camel.main.KameletMain;
import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
@@ -370,7 +371,11 @@ class RunExportGoldenTest {
}
@Override
- protected Process startProcess(ProcessBuilder pb) throws IOException {
+ protected RunContext runContext() {
+ return super.runContext().withProcessStarter(this::start);
+ }
+
+ private Process start(ProcessBuilder pb) throws IOException {
started.add(pb);
Path project = exportedProject(pb);
if (project != null && pb.command().contains("package") &&
pb.command().contains("-DskipTests")
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExportedProjectTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExportedProjectTest.java
deleted file mode 100644
index 4da89a7cce6a..000000000000
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExportedProjectTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.dsl.jbang.core.commands;
-
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.List;
-
-import org.apache.camel.dsl.jbang.export.run.MavenRunSupport;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-import picocli.CommandLine;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-/**
- * Verifies how {@code camel run --runtime=quarkus|spring-boot} runs the
exported project: the execution limits are
- * passed to the child JVM like for Camel Main, and the log file is named
after the name the application reports.
- */
-class RunExportedProjectTest extends CamelCommandBaseTestSupport {
-
- @TempDir
- Path dir;
-
- private static Run run(String... args) {
- Run command = new Run(new CamelJBangMain());
- CommandLine.populateCommand(command, args);
- return command;
- }
-
- @Test
- void durationLimitsArePassedToExportedRun() {
- String args = run("--max-seconds=30", "--max-messages=5",
"--max-idle-seconds=10", "route.yaml")
- .buildExportedRunJvmArgs();
-
- assertThat(args).isEqualTo("-Dcamel.main.durationMaxSeconds=30
-Dcamel.main.durationMaxMessages=5"
- + "
-Dcamel.main.durationMaxIdleSeconds=10");
- }
-
- @Test
- void durationLimitsAreMergedWithJvmArgs() {
- String args = run("--jvm-args=-Xmx512m", "--max-seconds=30",
"route.yaml").buildExportedRunJvmArgs();
-
- assertThat(args).isEqualTo("-Xmx512m
-Dcamel.main.durationMaxSeconds=30");
- }
-
- @Test
- void noJvmArgsWhenNothingToPass() {
- assertThat(run("route.yaml").buildExportedRunJvmArgs()).isNull();
- }
-
- @Test
- void jfrIsPassedAsJvmArgument() {
- String args = run("--jfr", "route.yaml").buildExportedRunJvmArgs();
-
- assertThat(args).contains("-XX:StartFlightRecording");
- }
-
- @Test
- void durationLimitsAreTheSameForAllRuntimes() {
- Run run = run("--max-seconds=30", "route.yaml");
-
- List<String> limits = run.buildDurationLimitArgs();
-
assertThat(limits).containsExactly("-Dcamel.main.durationMaxSeconds=30");
- // exported project (camel run foo.yaml --runtime=quarkus|spring-boot)
- assertThat(run.buildExportedRunJvmArgs()).isEqualTo(String.join(" ",
limits));
- // existing project (camel run pom.xml), per runtime
-
assertThat(run.buildExistingQuarkusJvmArgs("my-app")).containsAll(limits);
-
assertThat(run.buildExistingSpringBootJvmArgs("my-app")).containsAll(limits);
-
assertThat(MavenRunSupport.existingCamelMainSystemProperties(run.toRunRequest(null),
"my-app",
- dir.resolve("log4j2.properties")))
- .containsAll(limits);
- }
-
- @Test
- void appNameIsTheExportedCamelMainName() throws Exception {
- Path resources = dir.resolve("src/main/resources");
- Files.createDirectories(resources);
- Files.writeString(resources.resolve("application.properties"),
"camel.main.name=my-route\n");
-
- assertThat(MavenRunSupport.resolveExportedAppName(dir,
"CamelJBang")).isEqualTo("my-route");
- }
-
- @Test
- void appNameFallsBackWhenNotExported() {
- assertThat(MavenRunSupport.resolveExportedAppName(dir,
"CamelJBang")).isEqualTo("CamelJBang");
- }
-
-}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunTest.java
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunTest.java
index 4c8a436b2ffe..aa11d92f46a3 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunTest.java
+++
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunTest.java
@@ -20,8 +20,8 @@ package org.apache.camel.dsl.jbang.core.commands;
import java.nio.file.Path;
import org.apache.camel.dsl.jbang.export.common.RuntimeType;
-import org.apache.camel.dsl.jbang.export.run.MavenRunSupport;
import org.apache.camel.dsl.jbang.export.run.RunPipeline;
+import org.apache.camel.dsl.jbang.export.run.RunRequest;
import org.apache.camel.impl.DefaultCamelContext;
import org.apache.camel.main.KameletMain;
import org.junit.jupiter.api.Assertions;
@@ -195,46 +195,37 @@ class RunTest extends CamelCommandBaseTestSupport {
}
@Test
- void jfrDisabledByDefaultBuildsNoJvmArgs() throws Exception {
+ void jfrIsDisabledByDefault() throws Exception {
Run command = new Run(new CamelJBangMain());
CommandLine.populateCommand(command, "route.yaml");
assertThat(command.jfrEnabled()).isFalse();
- assertThat(command.buildJfrJvmArgs()).isNull();
}
@Test
- void jfrFlagBuildsStartFlightRecordingArg() throws Exception {
+ void jfrFlagEnablesJfr() throws Exception {
Run command = new Run(new CamelJBangMain());
CommandLine.populateCommand(command, "--jfr", "route.yaml");
assertThat(command.jfrEnabled()).isTrue();
- assertThat(command.buildJfrJvmArgs())
- .isEqualTo("-XX:StartFlightRecording=filename=CamelJBang.jfr "
- +
"-Dcamel.main.startupRecorderRuntimeEnabled=true");
}
@Test
- void jfrProfileImpliesJfrAndIsAppendedAsSettings() throws Exception {
+ void jfrProfileImpliesJfr() throws Exception {
Run command = new Run(new CamelJBangMain());
CommandLine.populateCommand(command, "--jfr-profile=profile",
"route.yaml");
assertThat(command.jfrEnabled()).isTrue();
- assertThat(command.buildJfrJvmArgs())
-
.isEqualTo("-XX:StartFlightRecording=filename=CamelJBang.jfr,settings=profile "
- +
"-Dcamel.main.startupRecorderRuntimeEnabled=true");
}
@Test
- void explicitStartFlightRecordingInJvmArgsKeepsRuntimeRecorderEnabled()
throws Exception {
+ void explicitStartFlightRecordingInJvmArgsKeepsJfrEnabled() throws
Exception {
// the explicit recording wins, but --jfr must still enable Camel
runtime events in forked projects
Run command = new Run(new CamelJBangMain());
CommandLine.populateCommand(command, "--jfr",
"--jvm-args=-XX:StartFlightRecording=filename=mine.jfr",
"route.yaml");
assertThat(command.jfrEnabled()).isTrue();
- assertThat(command.buildJfrJvmArgs())
- .isEqualTo("-Dcamel.main.startupRecorderRuntimeEnabled=true");
}
@Test
@@ -274,23 +265,25 @@ class RunTest extends CamelCommandBaseTestSupport {
}
@Test
- void mergeJvmArgsReturnsExistingWhenExtraIsNull() {
- assertThat(MavenRunSupport.mergeJvmArgs("-Xmx256m",
null)).isEqualTo("-Xmx256m");
- assertThat(MavenRunSupport.mergeJvmArgs(null, null)).isNull();
- }
-
- @Test
- void mergeJvmArgsReturnsExtraWhenExistingIsBlank() {
- assertThat(MavenRunSupport.mergeJvmArgs(null,
"-XX:StartFlightRecording=filename=camel.jfr"))
- .isEqualTo("-XX:StartFlightRecording=filename=camel.jfr");
- assertThat(MavenRunSupport.mergeJvmArgs(" ",
"-XX:StartFlightRecording=filename=camel.jfr"))
- .isEqualTo("-XX:StartFlightRecording=filename=camel.jfr");
- }
-
- @Test
- void mergeJvmArgsConcatenatesBothWithSpace() {
- assertThat(MavenRunSupport.mergeJvmArgs("-Xmx256m",
"-XX:StartFlightRecording=filename=camel.jfr"))
- .isEqualTo("-Xmx256m
-XX:StartFlightRecording=filename=camel.jfr");
+ void theOptionsOfARunWithMavenAreInTheRequest() {
+ Run command = new Run(new CamelJBangMain());
+ CommandLine.populateCommand(command, "--runtime=spring-boot",
"--camel-spring-boot-version=4.20.0",
+ "--jvm-args=-Xmx512m", "--jvm-debug=5005", "--port=9090",
"--max-seconds=30", "--prop=foo=bar",
+ "--jfr", "--dev", "route.yaml");
+
+ RunRequest request = command.toRunRequest(null);
+
+ // the default profile of camel run is dev
+ assertThat(request.profile).isEqualTo("dev");
+ assertThat(request.runtime).isEqualTo(RuntimeType.springBoot);
+ assertThat(request.camelSpringBootVersion).isEqualTo("4.20.0");
+ assertThat(request.jvmArgs).isEqualTo("-Xmx512m");
+ assertThat(request.jvmDebugPort).isEqualTo(5005);
+ assertThat(request.port).isEqualTo(9090);
+ assertThat(request.maxSeconds).isEqualTo(30);
+ assertThat(request.applicationProperties).containsExactly("foo=bar");
+ assertThat(request.jfrEnabled()).isTrue();
+ assertThat(request.dev).isTrue();
}
@Test
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/CamelMainRunner.java
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/CamelMainRunner.java
index 3a195d965801..67c2d8e7ae82 100644
---
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/CamelMainRunner.java
+++
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/CamelMainRunner.java
@@ -16,16 +16,13 @@
*/
package org.apache.camel.dsl.jbang.export.run;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.Reader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.StringJoiner;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Stream;
@@ -36,22 +33,22 @@ import
org.apache.camel.dsl.jbang.export.common.MavenCommand;
import org.apache.camel.dsl.jbang.export.common.Printer;
import org.apache.camel.dsl.jbang.export.common.RuntimeType;
import org.apache.camel.util.FileUtil;
-import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
-import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
-import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.CAMEL_MAIN_RUN_LOG_CONFIG;
-import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.RUN_PLATFORM_DIR;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.addDependency;
import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.durationLimitArgs;
import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.existingCamelMainSystemProperties;
-import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.jfrEnabled;
import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.jfrJvmArgs;
import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.keepRunLog;
import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.mergeJvmArgs;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.once;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.readPom;
import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.resolveExistingProjectAppName;
import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.resolveExportedAppName;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.runExportRequest;
import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.writeCamelMainRunLogConfig;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.writeRunPom;
/**
* Runs with Camel Main: the files are exported to a Camel Main project in a
directory of the run, which is packaged
@@ -104,7 +101,7 @@ final class CamelMainRunner {
AtomicReference<Process> appRef = new AtomicReference<>();
// create temp run dir
- Path runDirPath = Paths.get(RUN_PLATFORM_DIR,
Long.toString(System.currentTimeMillis()));
+ Path runDirPath = Paths.get(ProjectRunner.RUN_PLATFORM_DIR,
Long.toString(System.currentTimeMillis()));
// the process (and those it started) stops with this JVM, then the
files of the run are removed
ChildProcess.Cleanup cleanup = once(() -> {
RunPipeline.removeDir(runDirPath);
@@ -117,28 +114,10 @@ final class CamelMainRunner {
Files.createDirectories(runDirPath);
// export to hidden folder
- ExportRequest eq = new ExportRequest(request);
- eq.files = files;
+ ExportRequest eq = runExportRequest(request, runDirPath, files);
eq.javaLiveReload = false;
eq.symbolicLink = false;
- eq.mavenWrapper = true;
- eq.exportDir = runDirPath.toString();
eq.runtime = RuntimeType.main;
- if (eq.gav == null) {
- if (eq.name == null) {
- eq.name = "jbang-run-dummy";
- }
- eq.gav = "org.example.project:" + eq.name + ":1.0-SNAPSHOT";
- }
- eq.dependencies = new ArrayList<>(request.dependencies);
- eq.dependencies.add("camel:cli-connector");
- if (jfrEnabled(request)) {
- eq.dependencies.add("camel:jfr");
- }
- eq.quiet = true;
- eq.logging = false;
- eq.loggingLevel = "off";
- eq.consoleForRun = true;
printer().println("Running using Camel Main (preparing and downloading
files)");
@@ -218,37 +197,13 @@ final class CamelMainRunner {
Path projectDir = pomPath.getParent();
// read the pom.xml and add camel-cli-connector dependency
- MavenXpp3Reader mavenReader = new MavenXpp3Reader();
- Model model;
- try (Reader reader = Files.newBufferedReader(pomPath)) {
- model = mavenReader.read(reader);
- }
-
- boolean hasCliConnector = model.getDependencies().stream()
- .anyMatch(d ->
"camel-cli-connector".equals(d.getArtifactId()));
- if (!hasCliConnector) {
- Dependency d = new Dependency();
- d.setGroupId("org.apache.camel");
- d.setArtifactId("camel-cli-connector");
- model.getDependencies().add(d);
- }
- if (jfrEnabled(request)) {
- boolean hasJfr = model.getDependencies().stream()
- .anyMatch(d -> "camel-jfr".equals(d.getArtifactId()));
- if (!hasJfr) {
- Dependency d = new Dependency();
- d.setGroupId("org.apache.camel");
- d.setArtifactId("camel-jfr");
- model.getDependencies().add(d);
- }
+ Model model = readPom(pomPath);
+ addDependency(model, "org.apache.camel", "camel-cli-connector");
+ if (request.jfrEnabled()) {
+ addDependency(model, "org.apache.camel", "camel-jfr");
}
-
// write temporary pom with cli-connector injected
- Path tempPom = projectDir.resolve("camel-jbang-run-pom.xml");
- MavenXpp3Writer w = new MavenXpp3Writer();
- try (FileOutputStream fos = new FileOutputStream(tempPom.toFile())) {
- w.write(fos, model);
- }
+ Path tempPom = writeRunPom(projectDir, model);
// log to console and to file in ~/.camel (so camel log and the TUI
can tail the logs)
String appName = resolveExistingProjectAppName(projectDir, model);
@@ -339,18 +294,6 @@ final class CamelMainRunner {
}
}
- /**
- * The cleanup runs once: when the integration is stopped, or when this
JVM exits.
- */
- private static ChildProcess.Cleanup once(ChildProcess.Cleanup cleanup) {
- AtomicBoolean done = new AtomicBoolean();
- return () -> {
- if (done.compareAndSet(false, true)) {
- cleanup.run();
- }
- };
- }
-
private Printer printer() {
return runner.getContext().getPrinter();
}
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/MavenRunSupport.java
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/MavenRunSupport.java
index 11296a922fb5..b3bdad0a67d8 100644
---
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/MavenRunSupport.java
+++
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/MavenRunSupport.java
@@ -16,40 +16,48 @@
*/
package org.apache.camel.dsl.jbang.export.run;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.Reader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
+import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.camel.dsl.jbang.export.ExportRequest;
import org.apache.camel.dsl.jbang.export.common.CamelHome;
+import org.apache.camel.dsl.jbang.export.common.ChildProcess;
import org.apache.camel.dsl.jbang.export.common.LogFileReader;
import org.apache.camel.dsl.jbang.export.common.PreviousRun;
import org.apache.camel.dsl.jbang.export.common.Printer;
import org.apache.camel.util.json.JsonObject;
+import org.apache.maven.model.Dependency;
import org.apache.maven.model.Model;
+import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
+import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
/**
* What the runs with Maven (Camel Main, Quarkus and Spring Boot) share: the
directory of the run, the name of the
* application, the JVM arguments of the options of the run, and the log of
the run, which is kept as the previous run
* of the application when it ends.
- *
- * @since 4.24
*/
-public final class MavenRunSupport {
+final class MavenRunSupport {
/**
- * The directory with the projects that are exported to be run, one
directory per run.
+ * The file with the log4j2 configuration that an existing Camel Main
project is run with.
*/
- public static final String RUN_PLATFORM_DIR = ".camel-jbang-run";
+ static final String CAMEL_MAIN_RUN_LOG_CONFIG =
"camel-jbang-run-log4j2.properties";
/**
- * The file with the log4j2 configuration that an existing Camel Main
project is run with.
+ * The format of the log file of a Quarkus run: the same layout as the
camel-jbang console logging, so the log file
+ * reads the same for every runtime.
*/
- public static final String CAMEL_MAIN_RUN_LOG_CONFIG =
"camel-jbang-run-log4j2.properties";
+ static final String QUARKUS_LOG_FILE_FORMAT
+ = "%d{yyyy-MM-dd HH:mm:ss.SSS} %5p %i --- [%15.15t] %-40.40c{3.} :
%s%e%n";
/**
* At most this many records at the end of the log are looked at for why a
run failed.
@@ -63,7 +71,7 @@ public final class MavenRunSupport {
* The application name as configured in the exported project ({@code
camel.main.name}), which is what the running
* application reports to the CLI and the TUI.
*/
- public static String resolveExportedAppName(Path runDirPath, String
fallback) {
+ static String resolveExportedAppName(Path runDirPath, String fallback) {
Path props =
runDirPath.resolve("src/main/resources/application.properties");
if (Files.exists(props)) {
try (InputStream is = Files.newInputStream(props)) {
@@ -86,7 +94,7 @@ public final class MavenRunSupport {
* {@code camel.main.name}, so the name it reports to the CLI and the TUI
matches the {@code <name>.log} file that
* {@code camel log} and the TUI read when there is no {@code <pid>.log}.
*/
- public static String resolveExistingProjectAppName(Path projectDir, Model
model) {
+ static String resolveExistingProjectAppName(Path projectDir, Model model) {
String name = resolveExportedAppName(projectDir, null);
if (name == null && model != null && model.getArtifactId() != null &&
!model.getArtifactId().isBlank()) {
name = model.getArtifactId().trim();
@@ -97,25 +105,11 @@ public final class MavenRunSupport {
return name;
}
- /**
- * Whether the run records a flight recording ({@code --jfr} or {@code
--jfr-profile}).
- */
- public static boolean jfrEnabled(RunRequest request) {
- return request.jfr || request.jfrProfile != null;
- }
-
- /**
- * The file of the flight recording.
- */
- public static String jfrFileName(RunRequest request) {
- return (request.name != null ? request.name : "camel") + ".jfr";
- }
-
/**
* The JFR JVM arguments for runtimes that fork a subprocess, or {@code
null} when JFR was not requested.
*/
- public static String jfrJvmArgs(RunRequest request, Printer printer) {
- if (!jfrEnabled(request)) {
+ static String jfrJvmArgs(RunRequest request, Printer printer) {
+ if (!request.jfrEnabled()) {
return null;
}
StringBuilder arg = new StringBuilder();
@@ -125,7 +119,7 @@ public final class MavenRunSupport {
"--jvm-args already starts a flight recording, skipping
-XX:StartFlightRecording from --jfr"
+ " (Camel runtime instrumentation is still
enabled)");
} else {
-
arg.append("-XX:StartFlightRecording=filename=").append(jfrFileName(request));
+
arg.append("-XX:StartFlightRecording=filename=").append(request.jfrFileName());
if (request.jfrProfile != null) {
arg.append(",settings=").append(request.jfrProfile);
}
@@ -137,7 +131,7 @@ public final class MavenRunSupport {
return arg.toString();
}
- public static String mergeJvmArgs(String existing, String extra) {
+ static String mergeJvmArgs(String existing, String extra) {
if (extra == null) {
return existing;
}
@@ -151,7 +145,7 @@ public final class MavenRunSupport {
* The execution limits ({@code --max-seconds}, {@code --max-messages} and
{@code --max-idle-seconds}) as
* {@code camel.main.durationMax*} system properties, which all the
runtimes honour.
*/
- public static List<String> durationLimitArgs(RunRequest request) {
+ static List<String> durationLimitArgs(RunRequest request) {
List<String> args = new ArrayList<>();
if (request.maxSeconds > 0) {
args.add("-Dcamel.main.durationMaxSeconds=" + request.maxSeconds);
@@ -170,7 +164,7 @@ public final class MavenRunSupport {
* {@code spring-boot.run.jvmArguments}): {@code --jvm-args}, the flight
recording and the execution limits. Returns
* null when there are none.
*/
- public static String exportedRunJvmArgs(RunRequest request, Printer
printer) {
+ static String exportedRunJvmArgs(RunRequest request, Printer printer) {
String args = mergeJvmArgs(request.jvmArgs, jfrJvmArgs(request,
printer));
List<String> limits = durationLimitArgs(request);
if (!limits.isEmpty()) {
@@ -184,7 +178,7 @@ public final class MavenRunSupport {
* given property), the execution limits ({@code --max-seconds}, {@code
--max-messages} and
* {@code --max-idle-seconds}) and the additional properties ({@code
--prop}).
*/
- public static List<String> existingProjectSystemProperties(RunRequest
request, String portKey) {
+ static List<String> existingProjectSystemProperties(RunRequest request,
String portKey) {
List<String> args = new ArrayList<>();
if (request.port != -1) {
args.add("-D" + portKey + "=" + request.port);
@@ -205,7 +199,7 @@ public final class MavenRunSupport {
* The {@code -D} system properties an existing Camel Main project is run
with (Camel runs inside the Maven JVM so
* they go on the Maven command line): the log4j2 configuration, the
profile, the name, the port and properties.
*/
- public static List<String> existingCamelMainSystemProperties(RunRequest
request, String appName, Path logConfig) {
+ static List<String> existingCamelMainSystemProperties(RunRequest request,
String appName, Path logConfig) {
List<String> args = new ArrayList<>();
args.add("-Dlog4j2.configurationFile=" + logConfig.toAbsolutePath());
if (request.profile != null && !"prod".equals(request.profile)) {
@@ -221,7 +215,7 @@ public final class MavenRunSupport {
* console, and to the {@code <name>.log} file in the {@code ~/.camel}
directory. A log a run of that name left
* behind is kept as its previous run first, so the new log does not start
with the output of that run.
*/
- public static void writeCamelMainRunLogConfig(Path target, String appName,
String loggingLevel) throws IOException {
+ static void writeCamelMainRunLogConfig(Path target, String appName, String
loggingLevel) throws IOException {
Path logFile = runLogFile(appName);
keepLeftoverRunLog(appName);
String fileName = logFile.toAbsolutePath().toString().replace("\\",
"/");
@@ -239,7 +233,7 @@ public final class MavenRunSupport {
* The log a run on a Maven runtime writes in the Camel directory: {@code
<name>.log}, which {@code camel log} and
* the TUI read when there is no {@code <pid>.log}.
*/
- public static Path runLogFile(String appName) {
+ static Path runLogFile(String appName) {
return CamelHome.getCamelDir().resolve(appName + ".log");
}
@@ -247,7 +241,7 @@ public final class MavenRunSupport {
* A log that a run of this name left behind, such as a run that was
killed so it could not keep its log, is kept as
* the previous run of the name before the new run writes its own
(CAMEL-25832).
*/
- public static void keepLeftoverRunLog(String appName) {
+ static void keepLeftoverRunLog(String appName) {
PreviousRun.keepLeftover(runLogFile(appName), appName);
}
@@ -262,12 +256,12 @@ public final class MavenRunSupport {
* JVM), or Maven that runs the app in a process of its own
(quarkus:run, quarkus:dev,
* spring-boot:run), whose pid and exit code are not those
of the app
*/
- public static void keepRunLog(String appName, Process process, boolean
app) {
+ static void keepRunLog(String appName, Process process, boolean app) {
Integer code = process != null && !process.isAlive() ?
process.exitValue() : null;
keepRunLog(appName, app && process != null ? process.pid() : 0, code,
app);
}
- public static Path keepRunLog(String appName, long pid, Integer code,
boolean app) {
+ static Path keepRunLog(String appName, long pid, Integer code, boolean
app) {
if (appName == null) {
return null;
}
@@ -293,7 +287,7 @@ public final class MavenRunSupport {
* (Camel Main). The first, as an error that follows it is about the same
failure in other words: Quarkus logs the
* failure of Camel, then that Quarkus failed to start. Null when the end
of the log has no ERROR.
*/
- public static String failureInLog(Path log) {
+ static String failureInLog(Path log) {
if (!Files.isRegularFile(log)) {
return null;
}
@@ -315,7 +309,7 @@ public final class MavenRunSupport {
* The signal a process stopped by it exits with, as 128 and the number of
the signal: 130 for SIGINT (Ctrl+C), 137
* for SIGKILL and 143 for SIGTERM; null for another exit code.
*/
- public static String signalOf(int exitCode) {
+ static String signalOf(int exitCode) {
return switch (exitCode) {
case 130 -> "SIGINT";
case 137 -> "SIGKILL";
@@ -323,4 +317,150 @@ public final class MavenRunSupport {
default -> null;
};
}
+
+ /**
+ * The request of the export of the project that a run builds and runs, to
the given directory of the run: the
+ * options of the run, the CLI connector (and the flight recorder) for the
tools, and no logging of the export.
+ */
+ static ExportRequest runExportRequest(RunRequest request, Path runDir,
List<String> files) {
+ ExportRequest eq = new ExportRequest(request);
+ eq.files = files;
+ eq.mavenWrapper = true;
+ eq.exportDir = runDir.toString();
+ if (eq.gav == null) {
+ if (eq.name == null) {
+ eq.name = "jbang-run-dummy";
+ }
+ eq.gav = "org.example.project:" + eq.name + ":1.0-SNAPSHOT";
+ }
+ eq.dependencies = new ArrayList<>(request.dependencies);
+ eq.dependencies.add("camel:cli-connector");
+ if (request.jfrEnabled()) {
+ eq.dependencies.add("camel:jfr");
+ }
+ eq.quiet = true;
+ eq.logging = false;
+ eq.loggingLevel = "off";
+ eq.consoleForRun = true;
+ return eq;
+ }
+
+ /**
+ * Reads the pom.xml of an existing Maven project.
+ */
+ static Model readPom(Path pom) throws Exception {
+ try (Reader reader = Files.newBufferedReader(pom)) {
+ return new MavenXpp3Reader().read(reader);
+ }
+ }
+
+ /**
+ * Adds the dependency to the project, unless it has it already.
+ */
+ static void addDependency(Model model, String groupId, String artifactId) {
+ boolean found = model.getDependencies().stream().anyMatch(d ->
artifactId.equals(d.getArtifactId()));
+ if (!found) {
+ Dependency d = new Dependency();
+ d.setGroupId(groupId);
+ d.setArtifactId(artifactId);
+ model.getDependencies().add(d);
+ }
+ }
+
+ /**
+ * Writes the pom.xml that an existing Maven project is run with, next to
its own, which is not changed.
+ */
+ static Path writeRunPom(Path projectDir, Model model) throws IOException {
+ Path tempPom = projectDir.resolve("camel-jbang-run-pom.xml");
+ try (FileOutputStream fos = new FileOutputStream(tempPom.toFile())) {
+ new MavenXpp3Writer().write(fos, model);
+ }
+ return tempPom;
+ }
+
+ /**
+ * The Quarkus logging properties that make an existing Quarkus project
also log to the {@code <name>.log} file in
+ * the Camel directory (the same as the exported project does via its
application.properties).
+ */
+ static List<String> quarkusLogFileJvmArgs(String appName) {
+ String fileName =
runLogFile(appName).toAbsolutePath().toString().replace("\\", "/");
+ List<String> args = new ArrayList<>();
+ args.add("-Dquarkus.log.file.enabled=true");
+ args.add("-Dquarkus.log.file.path=" + fileName);
+ // quoted as the format has spaces (quarkus:dev parses jvm.args as a
command line)
+ args.add("-Dquarkus.log.file.format=\"" + QUARKUS_LOG_FILE_FORMAT +
"\"");
+ return args;
+ }
+
+ /**
+ * The JVM arguments ({@code jvm.args}) an existing Quarkus project is run
with: logging to file, the profile, the
+ * name, the port and properties, the flight recording and {@code
--jvm-args}.
+ */
+ static List<String> existingQuarkusJvmArgs(RunRequest request, String
appName, Printer printer) {
+ List<String> args = new ArrayList<>(quarkusLogFileJvmArgs(appName));
+ args.addAll(existingProjectJvmArgs(request, appName,
"quarkus.http.port", printer));
+ return args;
+ }
+
+ /**
+ * The JVM arguments ({@code spring-boot.run.jvmArguments}) an existing
Spring Boot project is run with: logging to
+ * file (the given logback configuration, unless null), the profile, the
name (so the app reports the name of its
+ * log file), the port and properties, the flight recording and {@code
--jvm-args}.
+ */
+ static List<String> existingSpringBootJvmArgs(RunRequest request, String
appName, Path logback, Printer printer) {
+ List<String> args = new ArrayList<>();
+ if (logback != null) {
+ args.add("-Dlogging.config=" + logback.toUri());
+ }
+ args.addAll(existingProjectJvmArgs(request, appName, "server.port",
printer));
+ return args;
+ }
+
+ private static List<String> existingProjectJvmArgs(
+ RunRequest request, String appName, String portKey, Printer
printer) {
+ List<String> args = new ArrayList<>();
+ if (request.profile != null && !"prod".equals(request.profile)) {
+ args.add("-Dcamel.main.profile=" + request.profile);
+ }
+ args.add("-Dcamel.main.name=" + appName);
+ args.addAll(existingProjectSystemProperties(request, portKey));
+ String jfrArg = jfrJvmArgs(request, printer);
+ if (jfrArg != null) {
+ args.add(jfrArg);
+ }
+ if (request.jvmArgs != null && !request.jvmArgs.isBlank()) {
+ args.add(request.jvmArgs.trim());
+ }
+ return args;
+ }
+
+ /**
+ * Writes the logback configuration used by {@code camel run
--runtime=spring-boot} to the given file. It logs to
+ * the console, and to the {@code <name>.log} file in the Camel directory,
as the other runtimes do, so the log can
+ * be kept as the previous run of the app (CAMEL-25832).
+ */
+ static void writeSpringBootLogbackConfig(Path target, String appName)
throws IOException {
+ String fileName =
runLogFile(appName).toAbsolutePath().toString().replace("\\", "/")
+ .replace("&", "&").replace("<", "<").replace("\"",
""");
+ try (InputStream is =
MavenRunSupport.class.getClassLoader().getResourceAsStream("spring-boot-logback.xml"))
{
+ if (is == null) {
+ throw new IOException("spring-boot-logback.xml not found");
+ }
+ String content = new String(is.readAllBytes(),
StandardCharsets.UTF_8).replace("{{logFile}}", fileName);
+ Files.createDirectories(target.getParent());
+ Files.writeString(target, content);
+ }
+ }
+
+ /**
+ * The cleanup runs once: when the integration is stopped, or when this
JVM exits.
+ */
+ static ChildProcess.Cleanup once(ChildProcess.Cleanup cleanup) {
+ AtomicBoolean done = new AtomicBoolean();
+ return () -> {
+ if (done.compareAndSet(false, true)) {
+ cleanup.run();
+ }
+ };
+ }
}
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/ProjectRunner.java
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/ProjectRunner.java
index 814dd0c94696..c69e2bd7a835 100644
---
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/ProjectRunner.java
+++
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/ProjectRunner.java
@@ -20,8 +20,9 @@ import org.apache.camel.dsl.jbang.export.ProjectExporter;
import org.apache.camel.dsl.jbang.export.common.RuntimeType;
/**
- * Runs Camel files, the Java API of camel run. A run is an export with a run
on top: with Camel Main, the files are
- * exported to a Maven project in a directory of the run, which is built with
Maven and started in a JVM of its own; an
+ * Runs Camel files, the Java API of camel run. A run is an export with a run
on top: with Camel Main, Quarkus and
+ * Spring Boot, the files are exported to a Maven project in a directory of
the run, which is built and started with
+ * Maven (Camel Main in a JVM of its own, Quarkus with quarkus:run or
quarkus:dev, Spring Boot with spring-boot:run); an
* existing Maven project (a pom.xml as the file to run) is run with Maven as
it is.
*
* <pre>
@@ -32,12 +33,17 @@ import org.apache.camel.dsl.jbang.export.common.RuntimeType;
* int exit = integration.waitFor();
* </pre>
*
- * Only the Camel Main runtime is run so far; camel run runs the others itself.
+ * Only the runtimes that run with Maven so far: camel run runs the jbang
runtime in its own JVM itself.
*
* @since 4.24
*/
public class ProjectRunner extends ProjectExporter {
+ /**
+ * The directory with the projects that are exported to be run, one
directory per run.
+ */
+ public static final String RUN_PLATFORM_DIR = ".camel-jbang-run";
+
public ProjectRunner() {
this(new RunContext());
}
@@ -53,7 +59,8 @@ public class ProjectRunner extends ProjectExporter {
/**
* Starts the integration: exports and builds the project (the output of
Maven goes to the console of this JVM), and
- * starts the application.
+ * starts the application. With Quarkus and Spring Boot, and an existing
project, the process of the integration is
+ * Maven, which runs the application; stopping it stops the application
too.
*
* @param request the request, which is not changed
* @return the running integration, or a run that ended with the
exit code of the failure (such as a build
@@ -62,6 +69,10 @@ public class ProjectRunner extends ProjectExporter {
public RunningIntegration start(RunRequest request) throws Exception {
if (request.runtime == RuntimeType.main) {
return new CamelMainRunner(this, request).start();
+ } else if (request.runtime == RuntimeType.quarkus) {
+ return new QuarkusRunner(this, request).start();
+ } else if (request.runtime == RuntimeType.springBoot) {
+ return new SpringBootRunner(this, request).start();
}
throw new IllegalArgumentException("Cannot run the runtime " +
request.runtime + " with ProjectRunner");
}
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/QuarkusRunner.java
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/QuarkusRunner.java
new file mode 100644
index 000000000000..b862b927eb6b
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/QuarkusRunner.java
@@ -0,0 +1,194 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.export.run;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.camel.dsl.jbang.export.ExportRequest;
+import org.apache.camel.dsl.jbang.export.common.ChildProcess;
+import org.apache.camel.dsl.jbang.export.common.MavenCommand;
+import org.apache.camel.dsl.jbang.export.common.Printer;
+import org.apache.camel.dsl.jbang.export.common.RuntimeType;
+import org.apache.maven.model.Model;
+
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.QUARKUS_LOG_FILE_FORMAT;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.addDependency;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.existingQuarkusJvmArgs;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.exportedRunJvmArgs;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.keepLeftoverRunLog;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.keepRunLog;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.once;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.readPom;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.resolveExistingProjectAppName;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.resolveExportedAppName;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.runExportRequest;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.runLogFile;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.writeRunPom;
+
+/**
+ * Runs with Quarkus: the files are exported to a Quarkus project in a
directory of the run, which is run with mvn
+ * quarkus:run (quarkus:dev in dev mode); an existing Quarkus project is run
the same way.
+ */
+final class QuarkusRunner {
+
+ private final ProjectRunner runner;
+ private final RunRequest request;
+
+ QuarkusRunner(ProjectRunner runner, RunRequest request) {
+ this.runner = runner;
+ this.request = request;
+ }
+
+ RunningIntegration start() throws Exception {
+ // existing Maven project: run directly without export
+ if (request.files != null && request.files.size() == 1 &&
request.files.get(0).endsWith("pom.xml")) {
+ return startExistingProject();
+ }
+
+ AtomicReference<Process> processRef = new AtomicReference<>();
+ AtomicReference<String> appNameRef = new AtomicReference<>();
+
+ // create temp run dir
+ Path runDirPath = Paths.get(ProjectRunner.RUN_PLATFORM_DIR,
Long.toString(System.currentTimeMillis()));
+ // the process (and those it started) stops with this JVM, then the
files of the run are removed
+ ChildProcess.Cleanup cleanup = once(() -> {
+ RunPipeline.removeDir(runDirPath);
+ // the log is kept as the previous run of the app (CAMEL-25832)
+ keepRunLog(appNameRef.get(), processRef.get(), false);
+ });
+ ChildProcess.stopOnExit(processRef::get, cleanup);
+ Files.createDirectories(runDirPath);
+
+ // export to hidden folder
+ ExportRequest eq = runExportRequest(request, runDirPath,
request.files);
+ eq.javaLiveReload = request.dev;
+ eq.symbolicLink = request.dev;
+ eq.runtime = RuntimeType.quarkus;
+
+ printer().println("Running using Quarkus (preparing and downloading
files)");
+
+ // run export
+ int exit = runner.export(eq.baseDir, eq);
+ if (exit != 0) {
+ return new EndedIntegration(exit);
+ }
+
+ // the exported project may have derived the application name from the
source files, and the log file
+ // must be named after the name the application reports (which is what
camel log and the TUI look for)
+ String appName = resolveExportedAppName(runDirPath, eq.name);
+ appNameRef.set(appName);
+ keepLeftoverRunLog(appName);
+
+ // prepare quarkus for logging to file
+ Path appProps = Paths.get(eq.exportDir,
"src/main/resources/application.properties");
+ if (Files.exists(appProps)) {
+ String content = Files.readString(appProps);
+ // in the Camel directory, where camel log looks for it (as for an
existing Quarkus project)
+ String logFile =
runLogFile(appName).toAbsolutePath().toString().replace("\\", "/");
+ content += "\n# logging to file\n"
+ + "quarkus.log.file.enabled=true\n"
+ + "quarkus.log.file.path=" + logFile + "\n"
+ + "quarkus.log.file.format=" + QUARKUS_LOG_FILE_FORMAT
+ "\n";
+ Files.writeString(appProps, content);
+ }
+
+ // run quarkus via maven
+ List<String> mvnCmd = new ArrayList<>();
+ mvnCmd.add(MavenCommand.wrapper(runDirPath).toString());
+ mvnCmd.add("--quiet");
+ mvnCmd.add("--file");
+ mvnCmd.add(runDirPath.toRealPath().resolve("pom.xml").toString());
+ String quarkusRunJvmArgs = exportedRunJvmArgs(request, printer());
+ if (quarkusRunJvmArgs != null) {
+ mvnCmd.add("-Djvm.args=" + quarkusRunJvmArgs);
+ }
+ if (request.console) {
+ // the console extension only exposes the console in dev and test
mode, and camel run without --dev is
+ // quarkus:run (prod mode). This is build-time configuration, and
is set on the build of this temporary
+ // project only, so an exported project does not have the console
exposed in prod mode
+ mvnCmd.add("-Dquarkus.camel.console.exposure-mode=ALL");
+ }
+ mvnCmd.add("package");
+ mvnCmd.add("quarkus:" + (request.dev ? "dev" : "run"));
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(mvnCmd);
+ pb.inheritIO(); // run in foreground (with IO so logs are visible)
+ Process p = runner.getContext().startProcess(pb);
+ processRef.set(p);
+ return new ProcessIntegration(p, cleanup);
+ }
+
+ private RunningIntegration startExistingProject() throws Exception {
+ AtomicReference<Process> processRef = new AtomicReference<>();
+ Path pomPath = Path.of(request.files.get(0)).toAbsolutePath();
+ Path projectDir = pomPath.getParent();
+
+ // read the pom.xml and add camel-quarkus-cli-connector dependency
+ Model model = readPom(pomPath);
+ addDependency(model, "org.apache.camel.quarkus",
"camel-quarkus-cli-connector");
+ if (request.jfrEnabled()) {
+ addDependency(model, "org.apache.camel.quarkus",
"camel-quarkus-jfr");
+ }
+ // write temporary pom with cli-connector injected
+ Path tempPom = writeRunPom(projectDir, model);
+
+ // log to console and to file in ~/.camel (so camel log and the TUI
can tail the logs)
+ String appName = resolveExistingProjectAppName(projectDir, model);
+ keepLeftoverRunLog(appName);
+
+ // the process (and those it started) stops with this JVM, then the
files of the run are removed
+ ChildProcess.Cleanup cleanup = once(() -> {
+ Files.deleteIfExists(tempPom);
+ // the log is kept as the previous run of the app (CAMEL-25832)
+ keepRunLog(appName, processRef.get(), false);
+ });
+ ChildProcess.stopOnExit(processRef::get, cleanup);
+
+ // find mvnw or fall back to mvn
+ String mvnCmd = MavenCommand.of(projectDir);
+
+ List<String> cmd = new ArrayList<>();
+ cmd.add(mvnCmd);
+ cmd.add("--quiet");
+ cmd.add("--file");
+ cmd.add(tempPom.toString());
+ cmd.add("-Djvm.args=" + String.join(" ",
existingQuarkusJvmArgs(request, appName, printer())));
+ cmd.add("-DskipTests");
+ cmd.add("package");
+ cmd.add("quarkus:" + (request.dev ? "dev" : "run"));
+
+ printer().println("Running Quarkus project: " + projectDir);
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(cmd);
+ pb.directory(projectDir.toFile());
+ pb.inheritIO();
+ Process p = runner.getContext().startProcess(pb);
+ processRef.set(p);
+ return new ProcessIntegration(p, cleanup);
+ }
+
+ private Printer printer() {
+ return runner.getContext().getPrinter();
+ }
+}
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/RunPipeline.java
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/RunPipeline.java
index cc22012b6624..0eab47148578 100644
---
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/RunPipeline.java
+++
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/RunPipeline.java
@@ -500,10 +500,10 @@ public class RunPipeline {
writeSetting(main, profileProperties, "camel.management.port",
() -> String.valueOf(request.managementPort));
}
- writeSetting(main, profileProperties, JFR, jfrEnabled() ? "jfr" :
null);
+ writeSetting(main, profileProperties, JFR, request.jfrEnabled() ?
"jfr" : null);
writeSetting(main, profileProperties, JFR_PROFILE,
request.jfrProfile != null ? request.jfrProfile : null);
- if (jfrEnabled()) {
+ if (request.jfrEnabled()) {
// camel-jfr is always on the classpath, but its runtime
instrumentation is opt-in
writeSetting(main, profileProperties,
"camel.main.startupRecorderRuntimeEnabled", "true");
}
@@ -859,7 +859,7 @@ public class RunPipeline {
writeSetting(main, profileProperties, "camel.server.enabled",
"true");
}
}
- if (jfrEnabled()) {
+ if (request.jfrEnabled()) {
request.dependencies.add("camel:jfr");
}
if (!request.dependencies.isEmpty()) {
@@ -884,10 +884,6 @@ public class RunPipeline {
settings.write(main, existing, key, value);
}
- private boolean jfrEnabled() {
- return request.jfr || request.jfrProfile != null;
- }
-
private boolean isMcpEnabled(Properties profileProperties) {
String val = profileProperties != null
? profileProperties.getProperty(MCP, request.mcp ? "true" :
"false")
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/RunRequest.java
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/RunRequest.java
index f5df523b4332..0cf5c9d69db5 100644
---
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/RunRequest.java
+++
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/RunRequest.java
@@ -214,4 +214,18 @@ public class RunRequest extends ExportRequest {
public RunRequest(ExportRequest export) {
super(export);
}
+
+ /**
+ * Whether the run records a flight recording ({@link #jfr} or {@link
#jfrProfile}).
+ */
+ public boolean jfrEnabled() {
+ return jfr || jfrProfile != null;
+ }
+
+ /**
+ * The file of the flight recording: the name of the integration, else
camel.
+ */
+ public String jfrFileName() {
+ return (name != null ? name : "camel") + ".jfr";
+ }
}
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/SpringBootRunner.java
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/SpringBootRunner.java
new file mode 100644
index 000000000000..b2f75deefb64
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-export/src/main/java/org/apache/camel/dsl/jbang/export/run/SpringBootRunner.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.export.run;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+
+import org.apache.camel.dsl.jbang.export.ExportRequest;
+import org.apache.camel.dsl.jbang.export.common.ChildProcess;
+import org.apache.camel.dsl.jbang.export.common.MavenCommand;
+import org.apache.camel.dsl.jbang.export.common.Printer;
+import org.apache.camel.dsl.jbang.export.common.RuntimeType;
+import org.apache.maven.model.Model;
+
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.addDependency;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.existingSpringBootJvmArgs;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.exportedRunJvmArgs;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.keepLeftoverRunLog;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.keepRunLog;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.once;
+import static org.apache.camel.dsl.jbang.export.run.MavenRunSupport.readPom;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.resolveExistingProjectAppName;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.resolveExportedAppName;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.runExportRequest;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.writeRunPom;
+import static
org.apache.camel.dsl.jbang.export.run.MavenRunSupport.writeSpringBootLogbackConfig;
+
+/**
+ * Runs with Spring Boot: the files are exported to a Spring Boot project in a
directory of the run, which is run with
+ * mvn spring-boot:run; an existing Spring Boot project is run the same way.
+ */
+final class SpringBootRunner {
+
+ private final ProjectRunner runner;
+ private final RunRequest request;
+
+ SpringBootRunner(ProjectRunner runner, RunRequest request) {
+ this.runner = runner;
+ this.request = request;
+ }
+
+ RunningIntegration start() throws Exception {
+ // existing Maven project: run directly without export
+ if (request.files != null && request.files.size() == 1 &&
request.files.get(0).endsWith("pom.xml")) {
+ return startExistingProject();
+ }
+
+ AtomicReference<Process> processRef = new AtomicReference<>();
+ AtomicReference<String> appNameRef = new AtomicReference<>();
+
+ // create temp run dir
+ Path runDirPath = Paths.get(ProjectRunner.RUN_PLATFORM_DIR,
Long.toString(System.currentTimeMillis()));
+ // the process (and those it started) stops with this JVM, then the
files of the run are removed
+ ChildProcess.Cleanup cleanup = once(() -> {
+ RunPipeline.removeDir(runDirPath);
+ // the log is kept as the previous run of the app (CAMEL-25832)
+ keepRunLog(appNameRef.get(), processRef.get(), false);
+ });
+ ChildProcess.stopOnExit(processRef::get, cleanup);
+ Files.createDirectories(runDirPath);
+
+ // the code reload is not supported, since we use symlink, spring-boot
devtools doesn't support symlink
+ if (request.dev) {
+ printer().printWarn("Code reload is not supported with Spring
Boot.");
+ }
+
+ // export to hidden folder
+ ExportRequest eq = runExportRequest(request, runDirPath,
request.files);
+ eq.javaLiveReload = false;
+ eq.symbolicLink = request.dev;
+ eq.runtime = RuntimeType.springBoot;
+ eq.camelSpringBootVersion
+ = request.camelSpringBootVersion != null ?
request.camelSpringBootVersion : request.camelVersion;
+ if (request.dev) {
+ // hot-reload of spring-boot
+
eq.dependencies.add("mvn:org.springframework.boot:spring-boot-devtools");
+ }
+
+ printer().println("Running using Spring Boot (preparing and
downloading files)");
+
+ // run export
+ int exit = runner.export(eq.baseDir, eq);
+ if (exit != 0) {
+ return new EndedIntegration(exit);
+ }
+
+ // the exported project may have derived the application name from the
source files, and the log file is
+ // named after the name the application reports (what camel log and
the TUI look for)
+ String appName = resolveExportedAppName(runDirPath, eq.name);
+ appNameRef.set(appName);
+ keepLeftoverRunLog(appName);
+
+ // prepare spring-boot for logging to file
+ writeSpringBootLogbackConfig(Paths.get(eq.exportDir,
"src/main/resources/logback.xml"), appName);
+
+ // run spring-boot via maven
+ List<String> mvnCmd = new ArrayList<>();
+ mvnCmd.add(MavenCommand.wrapper(runDirPath).toString());
+ mvnCmd.add("--quiet");
+ mvnCmd.add("--file");
+ mvnCmd.add(runDirPath.toRealPath().resolve("pom.xml").toString());
+ String springBootRunJvmArgs = exportedRunJvmArgs(request, printer());
+ if (springBootRunJvmArgs != null) {
+ mvnCmd.add("-Dspring-boot.run.jvmArguments=" +
springBootRunJvmArgs);
+ }
+ // run in the current directory, not the export folder, so the routes
read and write files relative to where
+ // camel run is started (CAMEL-25423)
+ mvnCmd.add("-Dspring-boot.run.workingDirectory=" +
Paths.get(".").toAbsolutePath().normalize());
+ mvnCmd.add("spring-boot:run");
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(mvnCmd);
+ pb.inheritIO(); // run in foreground (with IO so logs are visible)
+ Process p = runner.getContext().startProcess(pb);
+ processRef.set(p);
+ return new ProcessIntegration(p, cleanup);
+ }
+
+ private RunningIntegration startExistingProject() throws Exception {
+ AtomicReference<Process> processRef = new AtomicReference<>();
+ Path pomPath = Path.of(request.files.get(0)).toAbsolutePath();
+ Path projectDir = pomPath.getParent();
+
+ // read the pom.xml and add camel-cli-connector-starter dependency
+ Model model = readPom(pomPath);
+ addDependency(model, "org.apache.camel.springboot",
"camel-cli-connector-starter");
+ if (request.jfrEnabled()) {
+ addDependency(model, "org.apache.camel.springboot",
"camel-jfr-starter");
+ }
+ // write temporary pom with cli-connector injected
+ Path tempPom = writeRunPom(projectDir, model);
+
+ // log to console and to file in ~/.camel (so camel log and the TUI
can tail the logs)
+ String appName = resolveExistingProjectAppName(projectDir, model);
+ keepLeftoverRunLog(appName);
+ Path logback = logbackConfig(appName);
+
+ // the process (and those it started) stops with this JVM, then the
files of the run are removed
+ ChildProcess.Cleanup cleanup = once(() -> {
+ Files.deleteIfExists(tempPom);
+ if (logback != null) {
+ Files.deleteIfExists(logback);
+ }
+ // the log is kept as the previous run of the app (CAMEL-25832)
+ keepRunLog(appName, processRef.get(), false);
+ });
+ ChildProcess.stopOnExit(processRef::get, cleanup);
+
+ // find mvnw or fall back to mvn
+ String mvnCmd = MavenCommand.of(projectDir);
+
+ List<String> cmd = new ArrayList<>();
+ cmd.add(mvnCmd);
+ cmd.add("--quiet");
+ cmd.add("--file");
+ cmd.add(tempPom.toString());
+ cmd.add("-Dspring-boot.run.jvmArguments="
+ + String.join(" ", existingSpringBootJvmArgs(request, appName,
logback, printer())));
+ cmd.add("-DskipTests");
+ cmd.add("package");
+ cmd.add("spring-boot:run");
+
+ printer().println("Running Spring Boot project: " + projectDir);
+
+ ProcessBuilder pb = new ProcessBuilder();
+ pb.command(cmd);
+ pb.directory(projectDir.toFile());
+ pb.inheritIO();
+ Process p = runner.getContext().startProcess(pb);
+ processRef.set(p);
+ return new ProcessIntegration(p, cleanup);
+ }
+
+ /**
+ * The logback configuration an existing Spring Boot project runs with,
logging to the {@code <name>.log} file so
+ * the TUI can read the log: a temp file, so the project is not changed
and needs no src/main/resources. Null when
+ * it cannot be written.
+ */
+ static Path logbackConfig(String appName) {
+ try {
+ Path file = Files.createTempFile("camel-jbang-logback-", ".xml");
+ file.toFile().deleteOnExit();
+ writeSpringBootLogbackConfig(file, appName);
+ return file;
+ } catch (IOException e) {
+ return null;
+ }
+ }
+
+ private Printer printer() {
+ return runner.getContext().getPrinter();
+ }
+}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/main/resources/spring-boot-logback.xml
b/dsl/camel-jbang/camel-jbang-export/src/main/resources/spring-boot-logback.xml
similarity index 100%
rename from
dsl/camel-jbang/camel-jbang-core/src/main/resources/spring-boot-logback.xml
rename to
dsl/camel-jbang/camel-jbang-export/src/main/resources/spring-boot-logback.xml
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/ProjectRunnerTest.java
b/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/ProjectRunnerTest.java
index 5e5848033634..c1e999869952 100644
---
a/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/ProjectRunnerTest.java
+++
b/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/ProjectRunnerTest.java
@@ -64,7 +64,8 @@ class ProjectRunnerTest {
.withJavaHome(Path.of("/opt/jdk"))
.withProcessStarter(pb -> {
started.add(pb);
- if (pb.command().contains("package")) {
+ if (pb.command().contains("package")
+ && pb.command().stream().noneMatch(a ->
a.startsWith("quarkus:") || a.startsWith("spring-boot:"))) {
// the runner JAR that the build of a Camel Main project
makes
Path project =
Path.of(pb.command().get(pb.command().indexOf("--file") + 1)).getParent();
Files.createDirectories(project.resolve("target"));
@@ -88,7 +89,7 @@ class ProjectRunnerTest {
List<String> build = started.get(0).command();
assertThat(build).endsWith("--quiet", "--file", build.get(3),
"-DskipTests", "package");
Path project = Path.of(build.get(3)).getParent();
-
assertThat(project.getParent().getFileName()).hasToString(MavenRunSupport.RUN_PLATFORM_DIR);
+
assertThat(project.getParent().getFileName()).hasToString(ProjectRunner.RUN_PLATFORM_DIR);
assertThat(project.resolve("pom.xml")).exists();
assertThat(Files.readString(project.resolve("pom.xml"))).contains("camel-cli-connector");
@@ -159,14 +160,121 @@ class ProjectRunnerTest {
}
@Test
- void theOtherRuntimesAreNotRunYet() {
+ void aSpringBootRunExportsTheProjectAndRunsItWithMaven() throws Exception {
RunRequest request = request();
- request.runtime = RuntimeType.quarkus;
+ request.runtime = RuntimeType.springBoot;
+ request.jvmArgs = "-Xmx256m";
+ request.maxSeconds = 30;
+
+ RunningIntegration integration = new
ProjectRunner(context).start(request);
+ try {
+ // spring-boot:run builds and runs the application: the process of
the integration is Maven
+ assertThat(started).hasSize(1);
+ List<String> cmd = started.get(0).command();
+ Path project = Path.of(cmd.get(3)).getParent();
+
assertThat(project.getParent().getFileName()).hasToString(ProjectRunner.RUN_PLATFORM_DIR);
+ assertThat(cmd.subList(1, cmd.size())).containsExactly(
+ "--quiet", "--file", cmd.get(3),
+ "-Dspring-boot.run.jvmArguments=-Xmx256m
-Dcamel.main.durationMaxSeconds=30",
+ "-Dspring-boot.run.workingDirectory=" +
Path.of(".").toAbsolutePath().normalize(),
+ "spring-boot:run");
+
assertThat(project.resolve("pom.xml")).content().contains("camel-cli-connector-starter");
+ // the application logs to the log of its name, which is kept as
its previous run
+
assertThat(project.resolve("src/main/resources/logback.xml")).exists();
+ assertThat(printer.getOutput()).contains("Running using Spring
Boot (preparing and downloading files)");
+
+ assertThat(integration.pid()).isEqualTo(4242);
+ assertThat(integration.waitFor()).isEqualTo(7);
+ integration.stop();
+ assertThat(project).doesNotExist();
+ } finally {
+ integration.stop();
+ }
+ }
+
+ @Test
+ void anExistingQuarkusProjectRunsWithMaven() throws Exception {
+ RunRequest request = existingProject(RuntimeType.quarkus);
+ request.dev = true;
+ request.port = 9090;
+ request.jvmArgs = "-Xmx256m";
+
+ RunningIntegration integration = new
ProjectRunner(context).start(request);
+ try {
+ assertThat(started).hasSize(1);
+ ProcessBuilder pb = started.get(0);
+ Path project = dir.resolve("project");
+ assertThat(pb.directory()).isEqualTo(project.toFile());
+ List<String> cmd = pb.command();
+ assertThat(cmd.subList(1, 4)).containsExactly("--quiet", "--file",
+ project.resolve("camel-jbang-run-pom.xml").toString());
+
assertThat(cmd.get(4)).startsWith("-Djvm.args=-Dquarkus.log.file.enabled=true ")
+ .contains("-Dcamel.main.name=orders",
"-Dquarkus.http.port=9090").endsWith(" -Xmx256m");
+ assertThat(cmd.subList(5,
cmd.size())).containsExactly("-DskipTests", "package", "quarkus:dev");
+ // the project is run with a pom of its own, which adds the CLI
connector
+
assertThat(project.resolve("camel-jbang-run-pom.xml")).content().contains("camel-quarkus-cli-connector");
+ assertThat(printer.getOutput()).contains("Running Quarkus project:
" + project);
+
+ assertThat(integration.pid()).isEqualTo(4242);
+ integration.stop();
+
assertThat(project.resolve("camel-jbang-run-pom.xml")).doesNotExist();
+ assertThat(project.resolve("pom.xml")).exists();
+ } finally {
+ integration.stop();
+ }
+ }
+
+ @Test
+ void anExistingSpringBootProjectRunsWithMaven() throws Exception {
+ RunRequest request = existingProject(RuntimeType.springBoot);
+ request.jfr = true;
+
+ RunningIntegration integration = new
ProjectRunner(context).start(request);
+ try {
+ assertThat(started).hasSize(1);
+ Path project = dir.resolve("project");
+ List<String> cmd = started.get(0).command();
+
assertThat(cmd.get(4)).startsWith("-Dspring-boot.run.jvmArguments=-Dlogging.config=file:")
+ .contains("-Dcamel.main.name=orders",
"-XX:StartFlightRecording=filename=CamelJBang.jfr");
+ assertThat(cmd.subList(5,
cmd.size())).containsExactly("-DskipTests", "package", "spring-boot:run");
+ assertThat(project.resolve("camel-jbang-run-pom.xml")).content()
+ .contains("camel-cli-connector-starter",
"camel-jfr-starter");
+ assertThat(printer.getOutput()).contains("Running Spring Boot
project: " + project);
+
+ integration.stop();
+
assertThat(project.resolve("camel-jbang-run-pom.xml")).doesNotExist();
+ } finally {
+ integration.stop();
+ }
+ }
+
+ @Test
+ void theJBangRuntimeIsNotRunYet() {
+ RunRequest request = request();
+ request.runtime = RuntimeType.jbang;
assertThatThrownBy(() -> new ProjectRunner(context).start(request))
.isInstanceOf(IllegalArgumentException.class);
}
+ private RunRequest existingProject(RuntimeType runtime) throws Exception {
+ Path project = dir.resolve("project");
+ Files.createDirectories(project);
+ Files.writeString(project.resolve("pom.xml"), """
+ <project>
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.acme</groupId>
+ <artifactId>orders</artifactId>
+ <version>1.0</version>
+ </project>
+ """);
+ RunRequest request = new RunRequest();
+ request.files.add(project.resolve("pom.xml").toString());
+ request.runtime = runtime;
+ request.workDir = dir.resolve("work");
+ return request;
+ }
+
private RunRequest request() {
RunRequest request = new RunRequest();
Path route = dir.resolve("hello.camel.yaml");
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExistingProjectTest.java
b/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunExistingProjectTest.java
similarity index 71%
rename from
dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExistingProjectTest.java
rename to
dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunExistingProjectTest.java
index 86ee990b903e..d4fa9f948429 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunExistingProjectTest.java
+++
b/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunExistingProjectTest.java
@@ -14,32 +14,31 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands;
+package org.apache.camel.dsl.jbang.export.run;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
-import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
-import org.apache.camel.dsl.jbang.export.run.MavenRunSupport;
+import org.apache.camel.dsl.jbang.export.common.CamelHome;
+import org.apache.camel.dsl.jbang.export.common.StringPrinter;
import org.apache.maven.model.Model;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.api.parallel.Isolated;
-import picocli.CommandLine;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Verifies how {@code camel run pom.xml} runs an existing Maven project: the
application logs to a file in
* {@code ~/.camel} that {@code camel log} and the TUI can read, and the
options are passed to the right JVM for each
- * runtime.
+ * runtime. Isolated, as it changes the home directory of the JVM, which the
other tests use.
*/
@Isolated
-class RunExistingProjectTest extends CamelCommandBaseTestSupport {
+class RunExistingProjectTest {
@TempDir
Path home;
@@ -48,19 +47,25 @@ class RunExistingProjectTest extends
CamelCommandBaseTestSupport {
@BeforeEach
void useTempHome() {
- originalHome = CommandLineHelper.getHomeDir().toString();
- CommandLineHelper.useHomeDir(home.toString());
+ originalHome = CamelHome.getHomeDir().toString();
+ CamelHome.useHomeDir(home.toString());
}
@AfterEach
void restoreHome() {
- CommandLineHelper.useHomeDir(originalHome);
+ CamelHome.useHomeDir(originalHome);
}
- private static Run run(String... args) {
- Run command = new Run(new CamelJBangMain());
- CommandLine.populateCommand(command, args);
- return command;
+ private final StringPrinter printer = new StringPrinter();
+
+ /**
+ * The request of camel run pom.xml with the dev profile, the default of
camel run.
+ */
+ private static RunRequest request() {
+ RunRequest request = new RunRequest();
+ request.files.add("pom.xml");
+ request.profile = "dev";
+ return request;
}
private static Model model(String artifactId) {
@@ -89,7 +94,7 @@ class RunExistingProjectTest extends
CamelCommandBaseTestSupport {
@Test
void
camelMainLogsToFileViaLog4j2ConfigurationOnTheMavenCommandLine(@TempDir Path
project) throws Exception {
Path logConfig =
project.resolve("target").resolve(MavenRunSupport.CAMEL_MAIN_RUN_LOG_CONFIG);
- Path logFile = CommandLineHelper.getCamelDir().resolve("my-app.log");
+ Path logFile = CamelHome.getCamelDir().resolve("my-app.log");
Files.createDirectories(logFile.getParent());
Files.writeString(logFile, "stale output of a previous run");
@@ -97,16 +102,19 @@ class RunExistingProjectTest extends
CamelCommandBaseTestSupport {
// the log of the last run is kept as its previous run (CAMEL-25832),
so the readers do not show stale lines
assertThat(logFile).doesNotExist();
-
assertThat(CommandLineHelper.getCamelDir().resolve("my-app-previous.log")).hasContent("stale
output of a previous run");
+
assertThat(CamelHome.getCamelDir().resolve("my-app-previous.log")).hasContent("stale
output of a previous run");
String content = Files.readString(logConfig);
assertThat(content).contains("appender.file.fileName = " +
logFile.toAbsolutePath().toString().replace("\\", "/"));
assertThat(content).contains("rootLogger.level = debug");
assertThat(content).doesNotContain("{{");
- List<String> args = MavenRunSupport.existingCamelMainSystemProperties(
- run("--profile=dev", "--port=9090", "--max-seconds=30",
"--max-messages=5",
- "--max-idle-seconds=10", "--prop=foo=bar",
"--prop=-Dbar=baz", "pom.xml").toRunRequest(null),
- "my-app", logConfig);
+ RunRequest request = request();
+ request.port = 9090;
+ request.maxSeconds = 30;
+ request.maxMessages = 5;
+ request.maxIdleSeconds = 10;
+ request.applicationProperties = new String[] { "foo=bar", "-Dbar=baz"
};
+ List<String> args =
MavenRunSupport.existingCamelMainSystemProperties(request, "my-app", logConfig);
assertThat(args).containsExactly(
"-Dlog4j2.configurationFile=" + logConfig.toAbsolutePath(),
"-Dcamel.main.profile=dev",
@@ -126,15 +134,15 @@ class RunExistingProjectTest extends
CamelCommandBaseTestSupport {
assertThat(Files.readString(logConfig)).contains("rootLogger.level =
info");
// the default profile (dev) is passed, prod is not as it is the
default of a Maven project
- List<String> args
- =
MavenRunSupport.existingCamelMainSystemProperties(run("pom.xml").toRunRequest(null),
"my-app", logConfig);
+ List<String> args =
MavenRunSupport.existingCamelMainSystemProperties(request(), "my-app",
logConfig);
assertThat(args).containsExactly(
"-Dlog4j2.configurationFile=" + logConfig.toAbsolutePath(),
"-Dcamel.main.profile=dev",
"-Dcamel.main.name=my-app");
- args =
MavenRunSupport.existingCamelMainSystemProperties(run("--profile=prod",
"pom.xml").toRunRequest(null), "my-app",
- logConfig);
+ RunRequest prod = request();
+ prod.profile = "prod";
+ args = MavenRunSupport.existingCamelMainSystemProperties(prod,
"my-app", logConfig);
assertThat(args).containsExactly(
"-Dlog4j2.configurationFile=" + logConfig.toAbsolutePath(),
"-Dcamel.main.name=my-app");
@@ -142,16 +150,15 @@ class RunExistingProjectTest extends
CamelCommandBaseTestSupport {
@Test
void quarkusLogsToFileViaJvmArgs() {
- String logFile =
CommandLineHelper.getCamelDir().resolve("my-app.log").toAbsolutePath().toString()
+ String logFile =
CamelHome.getCamelDir().resolve("my-app.log").toAbsolutePath().toString()
.replace("\\", "/");
- List<String> args = run("--profile=dev", "--port=9090",
"--prop=foo=bar", "--jvm-args=-Xmx512m", "pom.xml")
- .buildExistingQuarkusJvmArgs("my-app");
+ List<String> args = MavenRunSupport.existingQuarkusJvmArgs(options(),
"my-app", printer);
assertThat(args).containsExactly(
"-Dquarkus.log.file.enabled=true",
"-Dquarkus.log.file.path=" + logFile,
- "-Dquarkus.log.file.format=\"" + Run.QUARKUS_LOG_FILE_FORMAT +
"\"",
+ "-Dquarkus.log.file.format=\"" +
MavenRunSupport.QUARKUS_LOG_FILE_FORMAT + "\"",
"-Dcamel.main.profile=dev",
"-Dcamel.main.name=my-app",
"-Dquarkus.http.port=9090",
@@ -161,11 +168,11 @@ class RunExistingProjectTest extends
CamelCommandBaseTestSupport {
@Test
void springBootLogsToFileViaLogbackConfiguration() {
- String logFile =
CommandLineHelper.getCamelDir().resolve("my-app.log").toAbsolutePath().toString()
+ String logFile =
CamelHome.getCamelDir().resolve("my-app.log").toAbsolutePath().toString()
.replace("\\", "/");
- List<String> args = run("--profile=dev", "--port=9090",
"--prop=foo=bar", "--jvm-args=-Xmx512m", "pom.xml")
- .buildExistingSpringBootJvmArgs("my-app");
+ List<String> args =
MavenRunSupport.existingSpringBootJvmArgs(options(), "my-app",
+ SpringBootRunner.logbackConfig("my-app"), printer);
// the logback configuration is a temp file: the project needs no
src/main/resources and is not changed; it logs
// to <name>.log, as the other runtimes do, so the log is kept as the
previous run (CAMEL-25832)
@@ -183,11 +190,23 @@ class RunExistingProjectTest extends
CamelCommandBaseTestSupport {
@Test
void jfrIsPassedAsJvmArgument() {
- List<String> args = run("--jfr",
"pom.xml").buildExistingQuarkusJvmArgs("my-app");
+ RunRequest request = request();
+ request.jfr = true;
+ List<String> args = MavenRunSupport.existingQuarkusJvmArgs(request,
"my-app", printer);
assertThat(args).anyMatch(a ->
a.startsWith("-XX:StartFlightRecording"));
- args = run("--jfr",
"pom.xml").buildExistingSpringBootJvmArgs("my-app");
+ args = MavenRunSupport.existingSpringBootJvmArgs(request, "my-app",
null, printer);
assertThat(args).anyMatch(a ->
a.startsWith("-XX:StartFlightRecording"));
}
+ /**
+ * The options of camel run --profile=dev --port=9090 --prop=foo=bar
--jvm-args=-Xmx512m pom.xml.
+ */
+ private static RunRequest options() {
+ RunRequest request = request();
+ request.port = 9090;
+ request.applicationProperties = new String[] { "foo=bar" };
+ request.jvmArgs = "-Xmx512m";
+ return request;
+ }
}
diff --git
a/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunExportedProjectTest.java
b/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunExportedProjectTest.java
new file mode 100644
index 000000000000..7de1f949eee5
--- /dev/null
+++
b/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunExportedProjectTest.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.dsl.jbang.export.run;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.List;
+
+import org.apache.camel.dsl.jbang.export.common.StringPrinter;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Verifies how {@code camel run --runtime=quarkus|spring-boot} runs the
exported project: the execution limits are
+ * passed to the child JVM like for Camel Main, and the log file is named
after the name the application reports.
+ */
+class RunExportedProjectTest {
+
+ @TempDir
+ Path dir;
+
+ private final StringPrinter printer = new StringPrinter();
+
+ private String exportedRunJvmArgs(RunRequest request) {
+ return MavenRunSupport.exportedRunJvmArgs(request, printer);
+ }
+
+ private static RunRequest limits(int maxSeconds, int maxMessages, int
maxIdleSeconds) {
+ RunRequest request = new RunRequest();
+ request.maxSeconds = maxSeconds;
+ request.maxMessages = maxMessages;
+ request.maxIdleSeconds = maxIdleSeconds;
+ return request;
+ }
+
+ @Test
+ void durationLimitsArePassedToExportedRun() {
+ String args = exportedRunJvmArgs(limits(30, 5, 10));
+
+ assertThat(args).isEqualTo("-Dcamel.main.durationMaxSeconds=30
-Dcamel.main.durationMaxMessages=5"
+ + "
-Dcamel.main.durationMaxIdleSeconds=10");
+ }
+
+ @Test
+ void durationLimitsAreMergedWithJvmArgs() {
+ RunRequest request = limits(30, 0, 0);
+ request.jvmArgs = "-Xmx512m";
+ String args = exportedRunJvmArgs(request);
+
+ assertThat(args).isEqualTo("-Xmx512m
-Dcamel.main.durationMaxSeconds=30");
+ }
+
+ @Test
+ void noJvmArgsWhenNothingToPass() {
+ assertThat(exportedRunJvmArgs(new RunRequest())).isNull();
+ }
+
+ @Test
+ void jfrIsPassedAsJvmArgument() {
+ RunRequest request = new RunRequest();
+ request.jfr = true;
+ String args = exportedRunJvmArgs(request);
+
+ assertThat(args).contains("-XX:StartFlightRecording");
+ }
+
+ @Test
+ void durationLimitsAreTheSameForAllRuntimes() {
+ RunRequest request = limits(30, 0, 0);
+
+ List<String> limits = MavenRunSupport.durationLimitArgs(request);
+
assertThat(limits).containsExactly("-Dcamel.main.durationMaxSeconds=30");
+ // exported project (camel run foo.yaml --runtime=quarkus|spring-boot)
+ assertThat(exportedRunJvmArgs(request)).isEqualTo(String.join(" ",
limits));
+ // existing project (camel run pom.xml), per runtime
+ assertThat(MavenRunSupport.existingQuarkusJvmArgs(request, "my-app",
printer)).containsAll(limits);
+ assertThat(MavenRunSupport.existingSpringBootJvmArgs(request,
"my-app", null, printer)).containsAll(limits);
+ assertThat(MavenRunSupport.existingCamelMainSystemProperties(request,
"my-app", dir.resolve("log4j2.properties")))
+ .containsAll(limits);
+ }
+
+ @Test
+ void appNameIsTheExportedCamelMainName() throws Exception {
+ Path resources = dir.resolve("src/main/resources");
+ Files.createDirectories(resources);
+ Files.writeString(resources.resolve("application.properties"),
"camel.main.name=my-route\n");
+
+ assertThat(MavenRunSupport.resolveExportedAppName(dir,
"CamelJBang")).isEqualTo("my-route");
+ }
+
+ @Test
+ void appNameFallsBackWhenNotExported() {
+ assertThat(MavenRunSupport.resolveExportedAppName(dir,
"CamelJBang")).isEqualTo("CamelJBang");
+ }
+
+ @Test
+ void noFlightRecordingWithoutJfr() {
+ RunRequest request = new RunRequest();
+
+ assertThat(request.jfrEnabled()).isFalse();
+ assertThat(MavenRunSupport.jfrJvmArgs(request, printer)).isNull();
+ }
+
+ @Test
+ void jfrStartsAFlightRecording() {
+ RunRequest request = new RunRequest();
+ request.jfr = true;
+
+ assertThat(request.jfrEnabled()).isTrue();
+ assertThat(MavenRunSupport.jfrJvmArgs(request, printer))
+ .isEqualTo("-XX:StartFlightRecording=filename=CamelJBang.jfr "
+ +
"-Dcamel.main.startupRecorderRuntimeEnabled=true");
+ }
+
+ @Test
+ void aJfrProfileImpliesJfrAndIsTheSettingsOfTheRecording() {
+ RunRequest request = new RunRequest();
+ request.jfrProfile = "profile";
+
+ assertThat(request.jfrEnabled()).isTrue();
+ assertThat(MavenRunSupport.jfrJvmArgs(request, printer))
+
.isEqualTo("-XX:StartFlightRecording=filename=CamelJBang.jfr,settings=profile "
+ +
"-Dcamel.main.startupRecorderRuntimeEnabled=true");
+ }
+
+ @Test
+ void aRecordingInTheJvmArgsWinsAndKeepsTheRuntimeRecorderEnabled() {
+ // the explicit recording wins, but --jfr must still enable Camel
runtime events in forked projects
+ RunRequest request = new RunRequest();
+ request.jfr = true;
+ request.jvmArgs = "-XX:StartFlightRecording=filename=mine.jfr";
+
+ assertThat(MavenRunSupport.jfrJvmArgs(request, printer))
+ .isEqualTo("-Dcamel.main.startupRecorderRuntimeEnabled=true");
+ assertThat(printer.getOutput()).contains("--jvm-args already starts a
flight recording");
+ }
+
+ @Test
+ void theRecordingIsNamedAfterTheIntegration() {
+ RunRequest request = new RunRequest();
+ request.name = "my-app";
+ assertThat(request.jfrFileName()).isEqualTo("my-app.jfr");
+
+ request.name = null;
+ assertThat(request.jfrFileName()).isEqualTo("camel.jfr");
+ }
+
+ @Test
+ void mergeJvmArgs() {
+ assertThat(MavenRunSupport.mergeJvmArgs("-Xmx256m",
null)).isEqualTo("-Xmx256m");
+ assertThat(MavenRunSupport.mergeJvmArgs(null, null)).isNull();
+ assertThat(MavenRunSupport.mergeJvmArgs(null,
"-XX:StartFlightRecording=filename=camel.jfr"))
+ .isEqualTo("-XX:StartFlightRecording=filename=camel.jfr");
+ assertThat(MavenRunSupport.mergeJvmArgs(" ",
"-XX:StartFlightRecording=filename=camel.jfr"))
+ .isEqualTo("-XX:StartFlightRecording=filename=camel.jfr");
+ assertThat(MavenRunSupport.mergeJvmArgs("-Xmx256m",
"-XX:StartFlightRecording=filename=camel.jfr"))
+ .isEqualTo("-Xmx256m
-XX:StartFlightRecording=filename=camel.jfr");
+ }
+}
diff --git
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunMavenRuntimePreviousLogTest.java
b/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunMavenRuntimePreviousLogTest.java
similarity index 96%
rename from
dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunMavenRuntimePreviousLogTest.java
rename to
dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunMavenRuntimePreviousLogTest.java
index cfcf2caca57f..9bb539f25136 100644
---
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/RunMavenRuntimePreviousLogTest.java
+++
b/dsl/camel-jbang/camel-jbang-export/src/test/java/org/apache/camel/dsl/jbang/export/run/RunMavenRuntimePreviousLogTest.java
@@ -14,16 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.camel.dsl.jbang.core.commands;
+package org.apache.camel.dsl.jbang.export.run;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
import java.util.List;
-import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.dsl.jbang.export.common.CamelHome;
import org.apache.camel.dsl.jbang.export.common.PreviousRun;
-import org.apache.camel.dsl.jbang.export.run.MavenRunSupport;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -47,15 +46,15 @@ class RunMavenRuntimePreviousLogTest {
@BeforeEach
void useTempHome() throws Exception {
- originalHome = CommandLineHelper.getHomeDir().toString();
- CommandLineHelper.useHomeDir(home.toString());
- camelDir = CommandLineHelper.getCamelDir();
+ originalHome = CamelHome.getHomeDir().toString();
+ CamelHome.useHomeDir(home.toString());
+ camelDir = CamelHome.getCamelDir();
Files.createDirectories(camelDir);
}
@AfterEach
void restoreHome() {
- CommandLineHelper.useHomeDir(originalHome);
+ CamelHome.useHomeDir(originalHome);
}
private Path log(String name, String content) throws Exception {
@@ -243,7 +242,7 @@ class RunMavenRuntimePreviousLogTest {
void springBootLogsToTheLogOfItsName() throws Exception {
Path logback = home.resolve("export/src/main/resources/logback.xml");
- Run.writeSpringBootLogbackConfig(logback, "orders");
+ MavenRunSupport.writeSpringBootLogbackConfig(logback, "orders");
String logFile =
camelDir.resolve("orders.log").toAbsolutePath().toString().replace("\\", "/");
assertThat(logback).content().contains("<property name=\"LOG_FILE\"
value=\"" + logFile + "\"/>")