You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2022/06/01 14:23:44 UTC
[camel] branch main updated: CAMEL-18151: camel-jbang - Export command for quarkus
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 5af4888658d CAMEL-18151: camel-jbang - Export command for quarkus
5af4888658d is described below
commit 5af4888658d30365b16c096f05cc5e3ee5e863b5
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Wed Jun 1 16:23:20 2022 +0200
CAMEL-18151: camel-jbang - Export command for quarkus
---
.../dsl/jbang/core/commands/CamelJBangMain.java | 3 +-
.../dsl/jbang/core/commands/ExportQuarkus.java | 324 +++++++++++++++++++++
.../src/main/resources/templates/quarkus-main.tmpl | 13 +
.../src/main/resources/templates/quarkus-pom.tmpl | 142 +++++++++
4 files changed, 481 insertions(+), 1 deletion(-)
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
index 84976957b85..40f3c67aadf 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/CamelJBangMain.java
@@ -46,7 +46,8 @@ public class CamelJBangMain implements Callable<Integer> {
.addSubcommand("manifests", new CommandLine(new Manifest(main)))
.addSubcommand("image", new CommandLine(new Image(main))))
.addSubcommand("export", new CommandLine(new Export(main))
- .addSubcommand("spring-boot", new CommandLine(new ExportSpringBoot(main))))
+ .addSubcommand("spring-boot", new CommandLine(new ExportSpringBoot(main)))
+ .addSubcommand("quarkus", new CommandLine(new ExportQuarkus(main))))
.addSubcommand("deploy", new CommandLine(new Deploy(main)))
.addSubcommand("undeploy", new CommandLine(new Undeploy(main)));
/* // TODO: do not show commands that are deprecated and to be either removed or reworked
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
new file mode 100644
index 00000000000..d331b19f6d8
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/ExportQuarkus.java
@@ -0,0 +1,324 @@
+/*
+ * 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.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.stream.Collectors;
+
+import org.apache.camel.main.MavenGav;
+import org.apache.camel.util.FileUtil;
+import org.apache.camel.util.IOHelper;
+import org.apache.camel.util.OrderedProperties;
+import org.apache.camel.util.StringHelper;
+import org.apache.commons.io.FileUtils;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "quarkus", description = "Export as Quarkus project")
+class ExportQuarkus extends CamelCommand {
+
+ private static final String BUILD_DIR = ".camel-jbang/work";
+
+ private static final String[] SETTINGS_PROP_SOURCE_KEYS = new String[] {
+ "camel.main.routesIncludePattern",
+ "camel.component.properties.location",
+ "camel.component.kamelet.location",
+ "camel.jbang.classpathFiles"
+ };
+
+ @CommandLine.Option(names = { "--gav" }, description = "The Maven group:artifact:version", required = true)
+ private String gav;
+
+ @CommandLine.Option(names = { "--main-classname" },
+ description = "The class name of the Quarkus application class",
+ defaultValue = "CamelApplication")
+ private String mainClassname;
+
+ @CommandLine.Option(names = { "--java-version" }, description = "Java version (11 or 17)",
+ defaultValue = "11")
+ private String javaVersion;
+
+ @CommandLine.Option(names = { "--quarkus-version" }, description = "Quarkus version",
+ defaultValue = "2.9.2.Final")
+ private String quarkusVersion;
+
+ @CommandLine.Option(names = { "--kamelets-version" }, description = "Apache Camel Kamelets version",
+ defaultValue = "0.8.1")
+ private String kameletsVersion;
+
+ @CommandLine.Option(names = { "-dir", "--directory" }, description = "Directory where the project will be exported",
+ defaultValue = ".")
+ private String exportDir;
+
+ @CommandLine.Option(names = { "--fresh" }, description = "Make sure we use fresh (i.e. non-cached) resources")
+ private boolean fresh;
+
+ public ExportQuarkus(CamelJBangMain main) {
+ super(main);
+ }
+
+ @Override
+ public Integer call() throws Exception {
+ String[] ids = gav.split(":");
+ if (ids.length != 3) {
+ System.out.println("--gav must be in syntax: groupId:artifactId:version");
+ return 1;
+ }
+
+ File profile = new File(getProfile() + ".properties");
+
+ // the settings file has information what to export
+ File settings = new File(Run.WORK_DIR + "/" + Run.RUN_SETTINGS_FILE);
+ if (fresh || !settings.exists()) {
+ // allow to automatic build
+ System.out.println("Generating fresh run data");
+ int silent = runSilently();
+ if (silent != 0) {
+ return silent;
+ }
+ } else {
+ System.out.println("Reusing existing run data");
+ }
+
+ System.out.println("Exporting as Quarkus project to: " + exportDir);
+
+ // use a temporary work dir
+ File buildDir = new File(BUILD_DIR);
+ FileUtil.removeDir(buildDir);
+ buildDir.mkdirs();
+
+ // copy source files
+ String packageName = ids[0] + "." + ids[1];
+ File srcJavaDir = new File(BUILD_DIR, "src/main/java/" + packageName.replace('.', '/'));
+ srcJavaDir.mkdirs();
+ File srcResourcesDir = new File(BUILD_DIR, "src/main/resources");
+ srcResourcesDir.mkdirs();
+ File srcCamelResourcesDir = new File(BUILD_DIR, "src/main/resources/camel");
+ srcCamelResourcesDir.mkdirs();
+ copySourceFiles(settings, srcJavaDir, srcResourcesDir, srcCamelResourcesDir, packageName);
+ // copy from settings to profile
+ copySettingsAndProfile(settings, profile, srcResourcesDir);
+ // create main class
+ createMainClassSource(srcJavaDir, packageName, mainClassname);
+ // gather dependencies
+ Set<String> deps = resolveDependencies(settings);
+ // create pom
+ createPom(new File(BUILD_DIR, "pom.xml"), deps);
+
+ if (exportDir.equals(".")) {
+ // we export to current dir so prepare for this by cleaning up existing files
+ File target = new File(exportDir);
+ for (File f : target.listFiles()) {
+ if (!f.isHidden() && f.isDirectory()) {
+ FileUtil.removeDir(f);
+ } else if (!f.isHidden() && f.isFile()) {
+ f.delete();
+ }
+ }
+ }
+ // copy to export dir and remove work dir
+ FileUtils.copyDirectory(new File(BUILD_DIR), new File(exportDir));
+ FileUtil.removeDir(new File(BUILD_DIR));
+
+ return 0;
+ }
+
+ private void createPom(File pom, Set<String> deps) throws Exception {
+ String[] ids = gav.split(":");
+
+ InputStream is = ExportQuarkus.class.getClassLoader().getResourceAsStream("templates/quarkus-pom.tmpl");
+ String context = IOHelper.loadText(is);
+ IOHelper.close(is);
+
+ context = context.replaceFirst("\\{\\{ \\.GroupId }}", ids[0]);
+ context = context.replaceFirst("\\{\\{ \\.ArtifactId }}", ids[1]);
+ context = context.replaceFirst("\\{\\{ \\.Version }}", ids[2]);
+ context = context.replaceAll("\\{\\{ \\.QuarkusVersion }}", quarkusVersion);
+ context = context.replaceFirst("\\{\\{ \\.JavaVersion }}", javaVersion);
+
+ StringBuilder sb = new StringBuilder();
+ for (String dep : deps) {
+ MavenGav gav = MavenGav.parseGav(null, dep);
+ String gid = gav.getGroupId();
+ String aid = gav.getArtifactId();
+ String v = gav.getVersion();
+ // transform to camel-quarkus extension GAV
+ if ("org.apache.camel".equals(gid)) {
+ gid = "org.apache.camel.quarkus";
+ aid = aid.replace("camel-", "camel-quarkus-");
+ v = null;
+ }
+ sb.append(" <dependency>\n");
+ sb.append(" <groupId>").append(gid).append("</groupId>\n");
+ sb.append(" <artifactId>").append(aid).append("</artifactId>\n");
+ if (v != null) {
+ sb.append(" <version>").append(v).append("</version>\n");
+ }
+ sb.append(" </dependency>\n");
+ }
+ context = context.replaceFirst("\\{\\{ \\.CamelDependencies }}", sb.toString());
+
+ IOHelper.writeText(context, new FileOutputStream(pom, false));
+ }
+
+ private Set<String> resolveDependencies(File settings) throws Exception {
+ Set<String> answer = new TreeSet<>();
+ List<String> lines = Files.readAllLines(settings.toPath());
+ for (String line : lines) {
+ if (line.startsWith("dependency=")) {
+ String v = StringHelper.after(line, "dependency=");
+ // skip endpointdsl as its already included, and core-languages and java-joor as we let quarkus compile
+ boolean skip = v == null || v.contains("org.apache.camel:camel-core-languages")
+ || v.contains("org.apache.camel:camel-java-joor-dsl")
+ || v.contains("camel-endpointdsl");
+ if (!skip) {
+ answer.add(v);
+ }
+ if (v != null && v.contains("org.apache.camel:camel-kamelet")) {
+ // include kamelet catalog if we use kamelets
+ answer.add("org.apache.camel.kamelets:camel-kamelets:" + kameletsVersion);
+ }
+ }
+ }
+ return answer;
+ }
+
+ private void createMainClassSource(File srcJavaDir, String packageName, String mainClassname) throws Exception {
+ InputStream is = ExportQuarkus.class.getClassLoader().getResourceAsStream("templates/quarkus-main.tmpl");
+ String context = IOHelper.loadText(is);
+ IOHelper.close(is);
+
+ context = context.replaceFirst("\\{\\{ \\.PackageName }}", packageName);
+ context = context.replaceAll("\\{\\{ \\.MainClassname }}", mainClassname);
+ IOHelper.writeText(context, new FileOutputStream(srcJavaDir + "/" + mainClassname + ".java", false));
+ }
+
+ private Integer runSilently() throws Exception {
+ Run run = new Run(getMain());
+ Integer code = run.runSilent();
+ return code;
+ }
+
+ private void copySourceFiles(
+ File settings, File srcJavaDir, File srcResourcesDir, File srcCamelResourcesDir, String packageName)
+ throws Exception {
+ // read the settings file and find the files to copy
+ OrderedProperties prop = new OrderedProperties();
+ prop.load(new FileInputStream(settings));
+
+ for (String k : SETTINGS_PROP_SOURCE_KEYS) {
+ String files = prop.getProperty(k);
+ if (files != null) {
+ for (String f : files.split(",")) {
+ String scheme = getScheme(f);
+ if (scheme != null) {
+ f = f.substring(scheme.length() + 1);
+ }
+ String ext = FileUtil.onlyExt(f, true);
+ boolean java = "java".equals(ext);
+ boolean camel = "camel.main.routesIncludePattern".equals(k) || "camel.component.kamelet.location".equals(k);
+ File target = java ? srcJavaDir : camel ? srcCamelResourcesDir : srcResourcesDir;
+ File source = new File(f);
+ File out = new File(target, source.getName());
+ safeCopy(source, out, true);
+ if (java) {
+ // need to append package name in java source file
+ List<String> lines = Files.readAllLines(out.toPath());
+ lines.add(0, "");
+ lines.add(0, "package " + packageName + ";");
+ FileOutputStream fos = new FileOutputStream(out);
+ for (String line : lines) {
+ fos.write(line.getBytes(StandardCharsets.UTF_8));
+ fos.write("\n".getBytes(StandardCharsets.UTF_8));
+ }
+ IOHelper.close(fos);
+ }
+ }
+ }
+ }
+ }
+
+ private void copySettingsAndProfile(File settings, File profile, File targetDir) throws Exception {
+ OrderedProperties prop = new OrderedProperties();
+ prop.load(new FileInputStream(settings));
+ OrderedProperties prop2 = new OrderedProperties();
+ if (profile.exists()) {
+ prop2.load(new FileInputStream(profile));
+ }
+
+ for (Map.Entry<Object, Object> entry : prop.entrySet()) {
+ String key = entry.getKey().toString();
+ boolean skip = "camel.main.routesCompileDirectory".equals(key) || "camel.main.routesReloadEnabled".equals(key);
+ if (!skip && key.startsWith("camel.main")) {
+ prop2.put(entry.getKey(), entry.getValue());
+ }
+ }
+
+ FileOutputStream fos = new FileOutputStream(new File(targetDir, profile.getName()), false);
+ for (Map.Entry<Object, Object> entry : prop2.entrySet()) {
+ String k = entry.getKey().toString();
+ String v = entry.getValue().toString();
+ // files are now loaded in classpath
+ v = v.replaceAll("file:", "classpath:");
+ if ("camel.main.routesIncludePattern".equals(k)) {
+ // camel.main.routesIncludePattern should remove all .java as we use quarkus to load them
+ // camel.main.routesIncludePattern should remove all file: classpath: as we copy them to src/main/resources/camel where camel auto-load from
+ v = Arrays.stream(v.split(","))
+ .filter(n -> !n.endsWith(".java") && !n.startsWith("file:") && !n.startsWith("classpath:"))
+ .collect(Collectors.joining(","));
+ }
+ if (!v.isBlank()) {
+ String line = k + "=" + v;
+ fos.write(line.getBytes(StandardCharsets.UTF_8));
+ fos.write("\n".getBytes(StandardCharsets.UTF_8));
+ }
+ }
+ IOHelper.close(fos);
+ }
+
+ private static void safeCopy(File source, File target, boolean override) throws Exception {
+ if (!source.exists()) {
+ return;
+ }
+
+ if (!target.exists()) {
+ Files.copy(source.toPath(), target.toPath());
+ } else if (override) {
+ Files.copy(source.toPath(), target.toPath(),
+ StandardCopyOption.REPLACE_EXISTING);
+ }
+ }
+
+ private static String getScheme(String name) {
+ int pos = name.indexOf(":");
+ if (pos != -1) {
+ return name.substring(0, pos);
+ }
+ return null;
+ }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/quarkus-main.tmpl b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/quarkus-main.tmpl
new file mode 100644
index 00000000000..2d678a67867
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/quarkus-main.tmpl
@@ -0,0 +1,13 @@
+package {{ .PackageName }};
+
+import io.quarkus.runtime.annotations.QuarkusMain;
+import io.quarkus.runtime.Quarkus;
+
+@QuarkusMain
+public class {{ .MainClassname }} {
+
+ public static void main(String[] args) {
+ Quarkus.run(args);
+ }
+
+}
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/quarkus-pom.tmpl b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/quarkus-pom.tmpl
new file mode 100644
index 00000000000..dc780acc37b
--- /dev/null
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/resources/templates/quarkus-pom.tmpl
@@ -0,0 +1,142 @@
+<?xml version="1.0"?>
+<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+ <modelVersion>4.0.0</modelVersion>
+
+ <groupId>{{ .GroupId }}</groupId>
+ <artifactId>{{ .ArtifactId }}</artifactId>
+ <version>{{ .Version }}</version>
+
+ <properties>
+ <compiler-plugin.version>3.8.1</compiler-plugin.version>
+ <failsafe.useModulePath>false</failsafe.useModulePath>
+ <maven.compiler.release>{{ .JavaVersion }}</maven.compiler.release>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
+ <quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
+ <quarkus.platform.version>{{ .QuarkusVersion }}</quarkus.platform.version>
+ <surefire-plugin.version>3.0.0-M5</surefire-plugin.version>
+ </properties>
+
+ <dependencyManagement>
+ <dependencies>
+ <dependency>
+ <groupId>${quarkus.platform.group-id}</groupId>
+ <artifactId>${quarkus.platform.artifact-id}</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ <dependency>
+ <groupId>${quarkus.platform.group-id}</groupId>
+ <artifactId>quarkus-camel-bom</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <type>pom</type>
+ <scope>import</scope>
+ </dependency>
+ </dependencies>
+ </dependencyManagement>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-platform-http</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.camel.quarkus</groupId>
+ <artifactId>camel-quarkus-microprofile-health</artifactId>
+ </dependency>
+{{ .CamelDependencies }}
+
+ <dependency>
+ <groupId>io.quarkus</groupId>
+ <artifactId>quarkus-junit5</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>${quarkus.platform.group-id}</groupId>
+ <artifactId>quarkus-maven-plugin</artifactId>
+ <version>${quarkus.platform.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <goals>
+ <goal>build</goal>
+ <goal>generate-code</goal>
+ <goal>generate-code-tests</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${compiler-plugin.version}</version>
+ <configuration>
+ <compilerArgs>
+ <arg>-parameters</arg>
+ </compilerArgs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>${surefire-plugin.version}</version>
+ <configuration>
+ <systemPropertyVariables>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <id>native</id>
+ <activation>
+ <property>
+ <name>native</name>
+ </property>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-failsafe-plugin</artifactId>
+ <version>${surefire-plugin.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>integration-test</goal>
+ <goal>verify</goal>
+ </goals>
+ <configuration>
+ <systemPropertyVariables>
+ <native.image.path>
+ ${project.build.directory}/${project.build.finalName}-runner
+ </native.image.path>
+ <java.util.logging.manager>org.jboss.logmanager.LogManager
+ </java.util.logging.manager>
+ <maven.home>${maven.home}</maven.home>
+ </systemPropertyVariables>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+ <properties>
+ <quarkus.package.type>native</quarkus.package.type>
+ </properties>
+ </profile>
+ </profiles>
+</project>