[ 
https://issues.apache.org/jira/browse/CAMEL-23810?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18135656#comment-18135656
 ] 

Claus Ibsen commented on CAMEL-23810:
-------------------------------------

Step 1 of the plan (measure), on main (baaf5322), JDK 25, Apple M4 Pro, the 
launcher's classes on a flat classpath (as JBang runs it), median of 7 runs, 
update check off:

||Phase||camel version||camel --help||camel ps||
|JVM start to main|70 ms|70 ms|70 ms|
|model of the core commands (create the 143 commands + picocli)|341 ms|340 
ms|339 ms|
|the 6 embedded plugins (customize)|151 ms|151 ms|151 ms|
|plugin discovery, user configuration|1 ms|15 ms|1 ms|
|parse and run the command|42 ms|9 ms|46 ms|
|*JVM exit*|*310 ms*|*310 ms*|*310 ms*|
|wall|about 920 ms|about 900 ms|about 920 ms|

What the model costs: loading and creating the 158 command classes without 
picocli 233 ms; picocli's model of them on top 116 ms (of which about 57 ms is 
picocli's fixed cost, measured with 2 commands); a warm rebuild 
({{newCommandLine()}}) 22 ms. Loading and creating only the 2 commands that 
run: 6 ms.

Two findings that have nothing to do with picocli:
* *Every command waits 300 ms in the exit of the JVM*: {{Harden}} creates a JDK 
{{HttpClient}} in a field initializer, so its selector thread is in native code 
when the JVM exits, and HotSpot waits up to 300 ms for it. With the client 
created on first use: exit 5 ms, wall 566 ms for {{camel version}}.
* {{InfraBaseCommand}} creates a Jackson {{ObjectMapper}} in a field (the first 
one costs about 50 ms).

So aesh can save at most the picocli share (about 115 ms of about 570 ms after 
the fix above), while creating only the commands a command line names (help 
aside) would save most of the 490 ms of the model, on picocli as on aesh. Speed 
alone is therefore not a reason for the port; the other reasons (completion, 
native launcher, alignment with JBang) remain.

_Claude Code on behalf of davsclaus (Claus Ibsen)_


> camel-jbang - Port from picolli to aesh
> ---------------------------------------
>
>                 Key: CAMEL-23810
>                 URL: https://issues.apache.org/jira/browse/CAMEL-23810
>             Project: Camel
>          Issue Type: Improvement
>            Reporter: Claus Ibsen
>            Assignee: Claus Ibsen
>            Priority: Major
>             Fix For: 4.24.0
>
>
> Port the Camel CLI (dsl/camel-jbang) from picocli to aesh, as JBang did: 
> [https://www.jbang.dev/learn/from-picocli-to-sh-how-porting-jbang-s-cli-made-everything-better/]
>  (jbangdev/jbang#2453).
> Starts from the state after CAMEL-25388 (exit codes 0/1/2/3/70/124, 
> CAMEL-25389) and CAMEL-24724 stage 1 and 2 (run and export are the 
> picocli-free camel-jbang-run engine), and keeps the exit code contract.
> h2. What reaches beyond the command layer
> * *The plugin SPI is picocli*: {{Plugin.customize(CommandLine, 
> CamelJBangMain)}} is public, and plugins outside Camel implement it: forage 
> (Kaoto), kit, and the test plugin mounts the picocli commands of Citrus 
> ({{org.citrusframework.jbang.cli}}) with a picocli execution strategy.
> * *The metadata and docs mojo reads the source*: 
> {{PrepareCamelJBangCommandsMojo}} regex-parses the {{addSubcommand}} chains 
> of {{CamelJBangMain}} and the picocli annotations (Roaster). The 175 pages 
> under {{jbang-commands/}} and the JSON that AskTools uses come from it.
> * *{{camel shell}} and the shell panel of the TUI* use jline's 
> {{PicocliCommandRegistry}}.
> h2. Size (main, 2026-10-31)
> 164 {{@Command}}, 861 {{@Option}}, 355 boolean options (160 {{arity="0..1"}}, 
> 89 {{fallbackValue="true"}}), 59 {{@Mixin}}, 5 converters, 17 parameter 
> consumers ({{DebugConsumer}} looks ahead), 42 completion candidate classes, 
> {{scope=INHERIT}} on {{--profile}}, user configuration via 
> {{PicocliPropertiesDefaultProvider}}, {{originalArgs()}} to start the CLI 
> again in another process ({{Run}}, {{Debug}}, {{InfraRun}}), 96 test files 
> using picocli directly.
> h2. aesh (checked 2026-10-31)
> * 3.18.6 ({{org.aesh:aesh}}, {{aesh-processor}}, {{aesh-bom}}), Apache-2.0, 
> Java 8 baseline. Annotation processor (no reflection, one registry per jar), 
> {{@Mixin}}, negatable, {{fallbackValue}}/{{optionalValue}}, {{inherited}}, 
> converters, completers, {{DefaultValueProvider}}, 
> {{CommandResult.valueOf(int)}}, {{MutableCommandRegistry}} for commands added 
> at runtime, AsciiDoc doc and bash/zsh/fish completion generators.
> * No picocli compatibility layer: every annotation is rewritten (JBang: one 
> PR, 134 files).
> * Risks: jbang#2504 (primitive boolean options) still open, JBang worked 
> around it with boxed {{Boolean}}; bus factor about 1; about 40 releases in 
> 2026 with API churn ({{@GroupCommandDefinition}} removed in 3.15); stricter 
> parsing than picocli around attached values ({{-R-Xmx4G}}, {{-D k=v}}). Pin 
> an exact version.
> h2. Plan
> As stage 2 of CAMEL-24724: a guard first, seams while still on picocli, then 
> one switch. Not per command group (two parsers in one command tree).
> # *Measure* the startup of {{camel --help}}, {{camel ps}}, {{camel version}} 
> on the JVM and the share of picocli (part may be the eager creation of 143 
> subcommands and the plugins, which picocli could do lazily too). A decision 
> point: if the gain is small, the reasons are completion, the native launcher 
> and staying aligned with JBang.
> # *A golden guard of the CLI surface*, on picocli: the committed metadata 
> JSON and pages, plus a {{CliParseGoldenTest}} recording command lines per 
> command, the field values after parsing, the exit code and the help (booleans 
> {{0..1}}, {{--profile}}, the lookahead consumers, {{split}}, converters, user 
> configuration, {{$\{camel-version\}}}). The port keeps it unchanged, except 
> the differences listed on purpose.
> # *Seams in core*, on picocli, no behaviour change: the uses of {{spec}} and 
> {{ParseResult}} behind {{CamelCommand}} helpers ({{isOptionGiven}}, the 
> original arguments, {{printHelp}}, {{runDefault}}, the configuration dump, 
> the placeholders); a test helper instead of {{populateCommand}}/{{parseArgs}} 
> in the tests.
> # *A plugin SPI without picocli*, on picocli: a new {{Plugin}} method 
> registering command classes with names and aliases; {{customize(CommandLine, 
> ...)}} deprecated but working in 4.24. Tell the forage, kit and Citrus 
> maintainers.
> # *The mojo reads a list of commands* in code (used by {{CamelJBangMain}} 
> too), not the source text. The generated output does not change.
> # *The switch*, one PR, mostly scripted: aesh pinned via {{aesh-bom}} and 
> {{aesh-processor}}; the exit codes mapped in one place on the base command; 
> installing a missing plugin on first use without matching picocli's message 
> text; the grouped command list of the help via {{HelpSectionProvider}}; 
> {{camel config}} via {{DefaultValueProvider}}; completion via aesh's 
> generator; the shell and the TUI shell panel on a command registry of aesh; 
> booleans boxed where needed.
> # *Cleanup*: remove picocli and {{jline-picocli}}, the old SPI (or its 
> bridge), upgrade-guide entry (plugin SPI, regenerate the completion script).
> h2. Open decisions
> * Release: proposal is steps 1-5 in 4.24 (old SPI deprecated), the switch in 
> 4.25, so forage, kit and Citrus have a release to move.
> * Plugin compatibility: a bridge for the old picocli SPI for one release 
> (picocli optional), or a break.
> * Citrus: ask to port citrus-jbang to aesh, or keep the test plugin on a 
> picocli bridge.
> * aesh risks (bus factor, jbang#2504, churn): acceptable with an exact 
> version and the golden guard of step 2.
> _Plan by Claude Code on behalf of davsclaus (Claus Ibsen)_



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to