This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch CAMEL-23653
in repository https://gitbox.apache.org/repos/asf/camel.git

commit cc1c242c018dd3d8bc65c60f012f77569aba677c
Author: Claus Ibsen <[email protected]>
AuthorDate: Sun May 31 18:27:55 2026 +0200

    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 <[email protected]>
---
 .../dsl/jbang/core/commands/CamelJBangMain.java    | 61 ++++++++++++++++++++++
 .../MissingPluginParameterExceptionHandler.java    | 16 +++++-
 .../camel/dsl/jbang/core/common/PluginHelper.java  |  6 ++-
 3 files changed, 81 insertions(+), 2 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)) {

Reply via email to