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 e9a09c926cc CAMEL-22098: camel-jbang - camel dependency runtime
e9a09c926cc is described below

commit e9a09c926cce01035df7562260270f5665adb8ed
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Wed May 21 19:44:17 2025 +0200

    CAMEL-22098: camel-jbang - camel dependency runtime
---
 .../dsl/jbang/core/commands/CamelJBangMain.java    |   3 +-
 .../dsl/jbang/core/commands/DependencyRuntime.java | 188 +++++++++++++++++++++
 .../camel/dsl/jbang/core/commands/RunHelper.java   |   9 +-
 .../camel/dsl/jbang/core/common/CatalogLoader.java |  56 ++++--
 .../jbang/core/commands/DependencyListTest.java    |   5 +-
 .../camel/main/download/DependencyDownloader.java  |  11 ++
 .../main/download/MavenDependencyDownloader.java   |  17 +-
 7 files changed, 264 insertions(+), 25 deletions(-)

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 52834122c6f..b18d6cd299d 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
@@ -143,7 +143,8 @@ public class CamelJBangMain implements Callable<Integer> {
                 .addSubcommand("dependency", new CommandLine(new 
DependencyCommand(main))
                         .addSubcommand("list", new CommandLine(new 
DependencyList(main)))
                         .addSubcommand("copy", new CommandLine(new 
DependencyCopy(main)))
-                        .addSubcommand("update", new CommandLine(new 
DependencyUpdate(main))))
+                        .addSubcommand("update", new CommandLine(new 
DependencyUpdate(main)))
+                        .addSubcommand("runtime", new CommandLine(new 
DependencyRuntime(main))))
                 .addSubcommand("catalog", new CommandLine(new 
CatalogCommand(main))
                         .addSubcommand("component", new CommandLine(new 
CatalogComponent(main)))
                         .addSubcommand("dataformat", new CommandLine(new 
CatalogDataFormat(main)))
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyRuntime.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyRuntime.java
new file mode 100644
index 00000000000..20f6941e472
--- /dev/null
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/DependencyRuntime.java
@@ -0,0 +1,188 @@
+/*
+ * 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.nio.file.Paths;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.StringJoiner;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+
+import org.apache.camel.catalog.CamelCatalog;
+import org.apache.camel.dsl.jbang.core.common.CatalogLoader;
+import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
+import org.apache.camel.dsl.jbang.core.common.XmlHelper;
+import org.apache.camel.util.json.Jsoner;
+import picocli.CommandLine;
+
+@CommandLine.Command(name = "runtime",
+                     description = "Display Camel runtime and version for 
given Maven project", sortOptions = false,
+                     showDefaultValues = true)
+public class DependencyRuntime extends CamelCommand {
+
+    protected static final String EXPORT_DIR = 
CommandLineHelper.CAMEL_JBANG_WORK_DIR + "/export";
+
+    @CommandLine.Option(names = { "--json" },
+                        description = "Output in JSON Format")
+    boolean jsonOutput;
+
+    public DependencyRuntime(CamelJBangMain main) {
+        super(main);
+    }
+
+    @Override
+    public Integer doCall() throws Exception {
+        // read pom.xml
+        Path pom = Paths.get(".").resolve("pom.xml");
+        if (Files.exists(pom)) {
+            DocumentBuilderFactory dbf = 
XmlHelper.createDocumentBuilderFactory();
+            DocumentBuilder db = dbf.newDocumentBuilder();
+            Document dom = db.parse(Files.newInputStream(pom));
+            NodeList nl = dom.getElementsByTagName("dependency");
+            String camelVersion = null;
+            String camelQuarkusVersion = null;
+            String springBootVersion = null;
+            String quarkusVersion = null;
+            String quarkusGroupId = "io.quarkus.platform";
+            for (int i = 0; i < nl.getLength(); i++) {
+                Element node = (Element) nl.item(i);
+
+                // must be child at <project/dependencyManagement> or 
<project/dependencies>
+                String p = node.getParentNode().getNodeName();
+                String p2 = node.getParentNode().getParentNode().getNodeName();
+                boolean accept = ("dependencyManagement".equals(p2) || 
"project".equals(p2)) && (p.equals("dependencies"));
+                if (!accept) {
+                    continue;
+                }
+
+                String g = 
node.getElementsByTagName("groupId").item(0).getTextContent();
+                String a = 
node.getElementsByTagName("artifactId").item(0).getTextContent();
+                String v = null;
+                NodeList vl = node.getElementsByTagName("version");
+                if (vl.getLength() > 0) {
+                    v = vl.item(0).getTextContent();
+                }
+
+                // BOMs
+                if ("org.apache.camel".equals(g) && "camel-bom".equals(a)) {
+                    camelVersion = v;
+                    continue;
+                }
+                if ("org.apache.camel.springboot".equals(g) && 
"camel-spring-boot-bom".equals(a)) {
+                    camelVersion = v;
+                    continue;
+                }
+                if ("org.springframework.boot".equals(g) && 
"spring-boot-dependencies".equals(a)) {
+                    springBootVersion = v;
+                    continue;
+                }
+                if (("${quarkus.platform.group-id}".equals(g) || 
"io.quarkus.platform".equals(g)) &&
+                        ("${quarkus.platform.artifact-id}".equals(a) || 
"quarkus-bom".equals(a))) {
+                    if ("${quarkus.platform.version}".equals(v)) {
+                        quarkusVersion = 
dom.getElementsByTagName("quarkus.platform.version").item(0).getTextContent();
+                    } else {
+                        quarkusVersion = v;
+                    }
+                    continue;
+                }
+                if (("${quarkus.platform.group-id}".equals(g))) {
+                    quarkusGroupId = 
dom.getElementsByTagName("quarkus.platform.group-id").item(0).getTextContent();
+                }
+            }
+
+            String repos = null;
+            StringJoiner sj = new StringJoiner(",");
+            nl = dom.getElementsByTagName("repository");
+            for (int i = 0; i < nl.getLength(); i++) {
+                Element node = (Element) nl.item(i);
+
+                // must be child at <repositories/repository>
+                String p = node.getParentNode().getNodeName();
+                boolean accept = "repositories".equals(p);
+                if (!accept) {
+                    continue;
+                }
+                String url = 
node.getElementsByTagName("url").item(0).getTextContent();
+                sj.add(url);
+            }
+            if (sj.length() > 0) {
+                repos = sj.toString();
+            }
+
+            // its a bit harder to know the camel version from Quarkus because 
of the universal BOM
+            if (quarkusVersion != null && camelVersion == null) {
+                CamelCatalog catalog = CatalogLoader.loadQuarkusCatalog(repos, 
quarkusVersion, quarkusGroupId);
+                if (catalog != null) {
+                    // find out the camel quarkus version via the constant 
language that are built-in camel-core
+                    camelQuarkusVersion = 
catalog.languageModel("constant").getVersion();
+                    // okay so the camel version is also hard to resolve from 
quarkus
+                    camelVersion = 
CatalogLoader.resolveCamelVersionFromQuarkus(repos, camelQuarkusVersion);
+                }
+            }
+
+            String runtime = "camel-main";
+            if (springBootVersion != null) {
+                runtime = "camel-spring-boot";
+            } else if (quarkusVersion != null) {
+                runtime = "camel-quarkus";
+            }
+
+            if (jsonOutput) {
+                Map<String, String> map = new LinkedHashMap<>();
+                map.put("runtime", runtime);
+                if (camelVersion != null) {
+                    map.put("camelVersion", camelVersion);
+                }
+                if (camelQuarkusVersion != null) {
+                    map.put("camelQuarkusVersion", camelQuarkusVersion);
+                }
+                if (springBootVersion != null) {
+                    map.put("springBootVersion", springBootVersion);
+                }
+                if (quarkusVersion != null) {
+                    map.put("quarkusVersion", quarkusVersion);
+                }
+                printer().println(
+                        Jsoner.serialize(map));
+            } else {
+                printer().println("Runtime: " + runtime);
+                if (camelVersion != null) {
+                    printer().println("Camel Version: " + camelVersion);
+                }
+                if (camelQuarkusVersion != null) {
+                    printer().println("Camel Quarkus Version: " + 
camelQuarkusVersion);
+                }
+                if (springBootVersion != null) {
+                    printer().println("Spring Boot Version: " + 
springBootVersion);
+                } else if (quarkusVersion != null) {
+                    printer().println("Quarkus Version: " + quarkusVersion);
+                }
+            }
+        }
+
+        return 0;
+    }
+
+}
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RunHelper.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RunHelper.java
index ca0b2631793..57f2c986327 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RunHelper.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/RunHelper.java
@@ -61,6 +61,8 @@ public final class RunHelper {
 
         Path pomPath = Paths.get("pom.xml");
         if (Files.exists(pomPath) && Files.isRegularFile(pomPath)) {
+            CamelCatalog catalog = new DefaultCamelCatalog();
+
             // find additional dependencies form pom.xml
             MavenXpp3Reader mavenReader = new MavenXpp3Reader();
             try (Reader reader = Files.newBufferedReader(pomPath)) {
@@ -89,7 +91,7 @@ public final class RunHelper {
                         // camel dependencies
                         String a = d.getArtifactId();
 
-                        if (!isInCamelCatalog(a)) {
+                        if (!isInCamelCatalog(catalog, a)) {
                             // not a known camel artifact
                             continue;
                         }
@@ -170,7 +172,10 @@ public final class RunHelper {
     }
 
     public static boolean isInCamelCatalog(String artifactId) {
-        CamelCatalog catalog = new DefaultCamelCatalog();
+        return isInCamelCatalog(new DefaultCamelCatalog(), artifactId);
+    }
+
+    public static boolean isInCamelCatalog(CamelCatalog catalog, String 
artifactId) {
         for (String n : catalog.findComponentNames()) {
             String a = catalog.componentModel(n).getArtifactId();
             if (artifactId.equals(a)) {
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CatalogLoader.java
 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CatalogLoader.java
index 8aac715a2cd..bca0712fcb9 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CatalogLoader.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/CatalogLoader.java
@@ -19,6 +19,7 @@ package org.apache.camel.dsl.jbang.core.common;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -193,20 +194,25 @@ public final class CatalogLoader {
 
             if (camelQuarkusVersion != null) {
                 // download camel-quarkus-catalog we use to know if we have an 
extension or not
-                downloader.downloadDependency("org.apache.camel.quarkus", 
"camel-quarkus-catalog", camelQuarkusVersion);
-
-                Class<RuntimeProvider> clazz = (Class<RuntimeProvider>) 
cl.loadClass(QUARKUS_CATALOG_PROVIDER);
-                if (clazz != null) {
-                    Class<CamelCatalog> clazz2 = (Class<CamelCatalog>) 
cl.loadClass(DEFAULT_CAMEL_CATALOG);
-                    if (clazz2 != null) {
-                        answer = ObjectHelper.newInstance(clazz2);
-                    }
-                    RuntimeProvider provider = ObjectHelper.newInstance(clazz);
-                    if (provider != null) {
-                        answer.setRuntimeProvider(provider);
+                List<MavenArtifact> artifacts = 
downloader.downloadArtifacts("org.apache.camel.quarkus",
+                        "camel-quarkus-catalog", camelQuarkusVersion, true);
+                if (artifacts != null) {
+                    // this will add to classpath
+                    downloader.downloadDependency("org.apache.camel.quarkus", 
"camel-quarkus-catalog", camelQuarkusVersion);
+
+                    Class<RuntimeProvider> clazz = (Class<RuntimeProvider>) 
cl.loadClass(QUARKUS_CATALOG_PROVIDER);
+                    if (clazz != null) {
+                        Class<CamelCatalog> clazz2 = (Class<CamelCatalog>) 
cl.loadClass(DEFAULT_CAMEL_CATALOG);
+                        if (clazz2 != null) {
+                            answer = ObjectHelper.newInstance(clazz2);
+                        }
+                        RuntimeProvider provider = 
ObjectHelper.newInstance(clazz);
+                        if (provider != null) {
+                            answer.setRuntimeProvider(provider);
+                        }
+                        // use classloader that loaded quarkus provider to 
ensure we can load its resources
+                        answer.getVersionManager().setClassLoader(cl);
                     }
-                    // use classloader that loaded quarkus provider to ensure 
we can load its resources
-                    answer.getVersionManager().setClassLoader(cl);
                 }
             }
             answer.enableCache();
@@ -217,6 +223,30 @@ public final class CatalogLoader {
         return answer;
     }
 
+    public static String resolveCamelVersionFromQuarkus(String repos, String 
camelQuarkusVersion) throws Exception {
+        DependencyDownloaderClassLoader cl = new 
DependencyDownloaderClassLoader(CatalogLoader.class.getClassLoader());
+        MavenDependencyDownloader downloader = new MavenDependencyDownloader();
+        downloader.setRepositories(repos);
+        downloader.setClassLoader(cl);
+        try {
+            downloader.start();
+
+            List<MavenArtifact> artifacts = 
downloader.downloadArtifacts("org.apache.camel.quarkus", 
"camel-quarkus-catalog",
+                    camelQuarkusVersion, true);
+            for (MavenArtifact ma : artifacts) {
+                String g = ma.getGav().getGroupId();
+                String a = ma.getGav().getArtifactId();
+                if ("org.apache.camel".equals(g) && "camel-catalog".equals(a)) 
{
+                    return ma.getGav().getVersion();
+                }
+            }
+        } finally {
+            downloader.stop();
+        }
+
+        return null;
+    }
+
     private static final class DownloadCatalogVersionManager implements 
VersionManager {
 
         private ClassLoader classLoader;
diff --git 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyListTest.java
 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyListTest.java
index 385a6952eed..47fa955555c 100644
--- 
a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyListTest.java
+++ 
b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/DependencyListTest.java
@@ -55,7 +55,7 @@ class DependencyListTest extends CamelCommandBaseTest {
     @ParameterizedTest
     @MethodSource("runtimeProvider")
     public void shouldDependencyList(RuntimeType rt) throws Exception {
-        Export command = createCommand(rt, new String[] { 
"classpath:route.yaml" },
+        DependencyList command = createCommand(rt, new String[] { 
"classpath:route.yaml" },
                 "--gav=examples:route:1.0.0", "--dir=" + workingDir, 
"--quiet", "--camel-version=4.11.0",
                 "--quarkus-version=3.22.2", "--spring-boot-version=3.4.5");
         int exit = command.doCall();
@@ -75,9 +75,8 @@ class DependencyListTest extends CamelCommandBaseTest {
         }
     }
 
-    private Export createCommand(RuntimeType rt, String[] files, String... 
args) {
+    private DependencyList createCommand(RuntimeType rt, String[] files, 
String... args) {
         DependencyList command = new DependencyList(new 
CamelJBangMain().withPrinter(printer));
-        ;
         CommandLine.populateCommand(command, "--gav=examples:route:1.0.0", 
"--dir=" + workingDir, "--quiet",
                 "--runtime=%s".formatted(rt.runtime()));
         if (args != null) {
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
index 840ca8b136b..fec871a2ae4 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/DependencyDownloader.java
@@ -155,6 +155,17 @@ public interface DependencyDownloader extends 
CamelContextAware, StaticService {
      */
     MavenArtifact downloadArtifact(String groupId, String artifactId, String 
version);
 
+    /**
+     * Downloads maven artifact (can also include transitive dependencies).
+     *
+     * @param  groupId      maven group id
+     * @param  artifactId   maven artifact id
+     * @param  version      maven version
+     * @param  transitively whether to include transitive dependencies
+     * @return              the artifacts, or null if none found
+     */
+    List<MavenArtifact> downloadArtifacts(String groupId, String artifactId, 
String version, boolean transitively);
+
     /**
      * Resolves the available versions for the given maven artifact
      *
diff --git 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
index 7b1954c33fd..47bda5971e1 100644
--- 
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
+++ 
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/download/MavenDependencyDownloader.java
@@ -330,24 +330,29 @@ public class MavenDependencyDownloader extends 
ServiceSupport implements Depende
 
     @Override
     public MavenArtifact downloadArtifact(String groupId, String artifactId, 
String version) {
+        List<MavenArtifact> artifacts = downloadArtifacts(groupId, artifactId, 
version, false);
+        if (artifacts != null && artifacts.size() == 1) {
+            return artifacts.get(0);
+        }
+        return null;
+    }
+
+    @Override
+    public List<MavenArtifact> downloadArtifacts(String groupId, String 
artifactId, String version, boolean transitively) {
         String gav = groupId + ":" + artifactId + ":" + version;
         List<String> deps = List.of(gav);
 
         // include Apache snapshot to make it easy to use upcoming releases
         boolean useApacheSnapshots = "org.apache.camel".equals(groupId) && 
version.contains("SNAPSHOT");
 
-        List<MavenArtifact> artifacts = resolveDependenciesViaAether(deps, 
null, false, useApacheSnapshots);
+        List<MavenArtifact> artifacts = resolveDependenciesViaAether(deps, 
null, transitively, useApacheSnapshots);
         if (verbose) {
             LOG.info("Dependencies: {} -> [{}]", gav, artifacts);
         } else {
             LOG.debug("Dependencies: {} -> [{}]", gav, artifacts);
         }
 
-        if (artifacts.size() == 1) {
-            return artifacts.get(0);
-        }
-
-        return null;
+        return artifacts;
     }
 
     @Override

Reply via email to