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 2026/06/01 09:25:23 UTC

(camel) branch main updated: CAMEL-23653: camel-jbang - Make it easy to use plugins (#23657)

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 e59b852914f7 CAMEL-23653: camel-jbang - Make it easy to use plugins (#23657)
e59b852914f7 is described below

commit e59b852914f7b46795387bf208280259d2c0efb5
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Mon Jun 1 11:25:15 2026 +0200

    CAMEL-23653: camel-jbang - Make it easy to use plugins (#23657)
    
    * CAMEL-23653: camel-jbang - Make it easy to use plugins
    
    Auto-install bundled plugins on first use and show available plugins in help output.
    
    Co-Authored-By: Claude <no...@anthropic.com>
    
    * CAMEL-23653: Fix test to match corrected quote in error message
    
    Co-Authored-By: Claude <no...@anthropic.com>
    
    ---------
    
    Co-authored-by: Claude <no...@anthropic.com>
---
 .../dsl/jbang/core/commands/CamelJBangMain.java    | 61 ++++++++++++++++++++++
 .../MissingPluginParameterExceptionHandler.java    | 16 +++++-
 .../camel/dsl/jbang/core/common/PluginHelper.java  |  6 ++-
 .../ParameterExceptionHandlerTest.java             |  2 +-
 4 files changed, 82 insertions(+), 3 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 5ffd1ecd473a..04a0f9d39a6a 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
@@ -16,6 +16,10 @@
  */
 package org.apache.camel.dsl.jbang.core.commands;
 
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
 import java.util.concurrent.Callable;
 
 import org.apache.camel.catalog.CamelCatalog;
@@ -59,7 +63,9 @@ import org.apache.camel.dsl.jbang.core.commands.version.VersionList;
 import org.apache.camel.dsl.jbang.core.commands.version.VersionSet;
 import org.apache.camel.dsl.jbang.core.common.CommandLineHelper;
 import org.apache.camel.dsl.jbang.core.common.PluginHelper;
+import org.apache.camel.dsl.jbang.core.common.PluginType;
 import org.apache.camel.dsl.jbang.core.common.Printer;
+import org.apache.camel.util.json.JsonObject;
 import picocli.CommandLine;
 import picocli.CommandLine.Command;
 
@@ -232,6 +238,9 @@ public class CamelJBangMain implements Callable<Integer> {
         CommandLineHelper.augmentWithUserConfiguration(commandLine);
         preExecute(commandLine, args);
         int exitCode = commandLine.execute(args);
+        if (isHelpRequest(args)) {
+            printAvailablePlugins();
+        }
         postExecute(commandLine, args, exitCode);
         quit(exitCode);
     }
@@ -271,6 +280,58 @@ public class CamelJBangMain implements Callable<Integer> {
         return 0;
     }
 
+    private static boolean isHelpRequest(String[] args) {
+        if (args == null || args.length == 0) {
+            return true;
+        }
+        for (String arg : args) {
+            if ("--help".equals(arg) || "-h".equals(arg)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void printAvailablePlugins() {
+        Set<String> installed = new HashSet<>();
+        JsonObject config = PluginHelper.getPluginConfig();
+        if (config != null) {
+            JsonObject plugins = config.getMap("plugins");
+            if (plugins != null) {
+                installed.addAll(plugins.keySet());
+            }
+        }
+        // also consider already registered subcommands as installed
+        Set<String> registered = commandLine.getSubcommands().keySet();
+
+        List<String[]> rows = new ArrayList<>();
+        for (PluginType pt : PluginType.values()) {
+            if (!installed.contains(pt.getName()) && !registered.contains(pt.getCommand())) {
+                rows.add(new String[] { pt.getCommand(), pt.getDescription() });
+            }
+        }
+        for (JsonObject kp : PluginHelper.loadKnownPlugins()) {
+            String name = kp.getString("name");
+            String command = kp.getStringOrDefault("command", name);
+            if (!installed.contains(name) && !registered.contains(command)
+                    && PluginType.findByName(name).isEmpty()) {
+                rows.add(new String[] { command, kp.getStringOrDefault("description", "") });
+            }
+        }
+
+        if (!rows.isEmpty()) {
+            int maxCmd = rows.stream().mapToInt(r -> r[0].length()).max().orElse(0);
+            out.println();
+            out.println("Plugins (not installed):");
+            for (String[] row : rows) {
+                out.printf("  %-" + maxCmd + "s   %s%n", row[0], row[1]);
+            }
+            out.println();
+            out.println("Tip: Install with: camel plugin add <name>");
+            out.println("     Bundled plugins are auto-installed on first use.");
+        }
+    }
+
     /**
      * Gets the main output printer to write command output.
      *
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/MissingPluginParameterExceptionHandler.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/MissingPluginParameterExceptionHandler.java
index 9f930aceeb6e..6b131ad9b1ef 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/MissingPluginParameterExceptionHandler.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/MissingPluginParameterExceptionHandler.java
@@ -17,7 +17,10 @@
 package org.apache.camel.dsl.jbang.core.commands.exceptionhandler;
 
 import java.io.PrintWriter;
+import java.util.Optional;
 
+import org.apache.camel.dsl.jbang.core.common.PluginHelper;
+import org.apache.camel.dsl.jbang.core.common.PluginType;
 import picocli.CommandLine;
 import picocli.CommandLine.IParameterExceptionHandler;
 import picocli.CommandLine.Model.CommandSpec;
@@ -31,6 +34,17 @@ public class MissingPluginParameterExceptionHandler implements IParameterExcepti
         CommandLine cmd = ex.getCommandLine();
         PrintWriter err = cmd.getErr();
 
+        if (ex.getMessage().startsWith("Unmatched argument at index 0") && args.length > 0) {
+            Optional<PluginType> pluginType = PluginType.findByName(args[0]);
+            if (pluginType.isPresent()) {
+                PluginHelper.enable(pluginType.get());
+                PrintWriter out = cmd.getOut();
+                out.printf("Installed plugin: %s%n", pluginType.get().getName());
+                out.println("Please re-run the command.");
+                return 0;
+            }
+        }
+
         if ("DEBUG".equalsIgnoreCase(System.getProperty("picocli.trace"))) {
             err.println(cmd.getColorScheme().stackTraceText(ex));
         }
@@ -44,7 +58,7 @@ public class MissingPluginParameterExceptionHandler implements IParameterExcepti
 
         if (ex.getMessage().startsWith("Unmatched argument at index 0")) {
             err.println(cmd.getColorScheme().errorText(
-                    "Maybe a specific Camel JBang plugin must be installed? (Try camel plugin --help' for more information)"));
+                    "Maybe a specific Camel JBang plugin must be installed? (Try 'camel plugin --help' for more information)"));
         }
 
         return cmd.getExitCodeExceptionMapper() != null
diff --git a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java
index 0fa2eb0a1f55..a71d7c888717 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/main/java/org/apache/camel/dsl/jbang/core/common/PluginHelper.java
@@ -118,7 +118,11 @@ public final class PluginHelper {
      */
     public static void addPlugins(CommandLine commandLine, CamelJBangMain main, String... args) {
         // first arg is the command name (ie camel generate xxx)
+        // if the first arg is a flag (e.g. --help), treat as no target so all plugins load
         String target = args != null && args.length > 0 ? args[0] : null;
+        if (target != null && target.startsWith("-")) {
+            target = null;
+        }
 
         // First, try to load embedded plugins from classpath (fat-jar scenario)
         boolean foundEmbeddedPlugins = false;
@@ -536,7 +540,7 @@ public final class PluginHelper {
         return Optional.ofNullable(getPluginConfig()).orElseGet(PluginHelper::createPluginConfig);
     }
 
-    static JsonObject getPluginConfig() {
+    public static JsonObject getPluginConfig() {
         try {
             Path f = CommandLineHelper.getHomeDir().resolve(PLUGIN_CONFIG);
             if (Files.exists(f)) {
diff --git a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/ParameterExceptionHandlerTest.java b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/ParameterExceptionHandlerTest.java
index a6ec85d69c6c..210773167f0b 100644
--- a/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/ParameterExceptionHandlerTest.java
+++ b/dsl/camel-jbang/camel-jbang-core/src/test/java/org/apache/camel/dsl/jbang/core/commands/exceptionhandler/ParameterExceptionHandlerTest.java
@@ -37,7 +37,7 @@ class ParameterExceptionHandlerTest {
         Assertions.assertEquals("Did you mean: camel eval or camel stop or camel infra?", lines[1],
                 "Second line with suggestion in case it is a typo");
         Assertions.assertEquals(
-                "Maybe a specific Camel JBang plugin must be installed? (Try camel plugin --help' for more information)",
+                "Maybe a specific Camel JBang plugin must be installed? (Try 'camel plugin --help' for more information)",
                 lines[4], "Last line suggesting new plugin");
     }