[
https://issues.apache.org/jira/browse/CAMEL-23810?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18136059#comment-18136059
]
Claus Ibsen commented on CAMEL-23810:
-------------------------------------
Trial port of the CLI core to aesh 3.18.6 (camel-jbang-core only; local branch,
not pushed).
Result: camel-jbang-core compiles and runs on aesh. The golden test (#28791)
runs 2207 command lines and records the field values picocli parses. On aesh,
80 of them parse differently, and every difference has a known cause:
* 56 {{camel semantic}}: a group command can't have arguments in aesh
(aeshell/aesh#702)
* 8 an optional value given as the next word, such as {{--jvm-debug 5006}}
(aeshell/aesh#703)
* 8 {{--find}}/{{--grep}} with no value (aeshell/aesh#705)
* 2 {{camel shell}} and {{camel completion}}, not ported yet
* 2 an undefined variable in a default gives "" (aeshell/aesh#700)
* 2 {{camel.run.dev=true}} from {{camel config set}}: today's CLI doesn't apply
it, aesh does (a bug on our side)
* 1 a Path option is made absolute (aesh resolves it against its working
directory on purpose, so we keep a String)
* 1 two @Arguments fields in one class hierarchy ({{dependency update}},
aeshell/aesh#699; we clean this up on our side)
Startup (JDK 25, no CDS, core class path, median of 9):
||Command||picocli||aesh||
|camel version|252 ms|163 ms|
|camel --help|429 ms|285 ms|
|camel get --help|288 ms|187 ms|
What the port took:
* A converter script did most of it: 144 commands, 330 boolean options, 49
mixins, 43 lists, 91 arguments.
* By hand: CamelCommand, CamelJBangMain and the two exception handlers; the
{{camel config set}} defaults as an aesh DefaultValueProvider; the 11 parameter
consumers; the converters and the 32 completion-candidate classes, each through
a small base class; 21 String[] list fields changed to List; 4 uses of @Spec.
* A new CommandTree class keeps the picocli style of addSubcommand(name,
command) and builds the aesh model. In the clean break (no picocli adapter),
plugins get this type instead of picocli's CommandLine.
Not ported yet, roughly by size:
* Tests: 93 of the 325 test files in core use the picocli API.
* {{camel shell}} and the shell panel of {{camel tui}}: both are built on
jline-picocli. This is the biggest unknown.
* The docs mojo (PrepareCamelJBangCommandsMojo) and the command metadata JSON,
which read picocli.
* Help: the grouped command list. aesh already supports footers
(HelpSectionProvider) and ${DEFAULT-VALUE}.
* {{camel completion}}: aesh has completion generators.
* The plugins and the launcher: mostly mechanical with the converter. The test
plugin waits on a Citrus release (citrus#1764).
Issues reported to aesh, tracked in aeshell/aesh#709:
Bugs:
* aeshell/aesh#697 the starting value of a primitive option field is lost
({{boolean global = true}} becomes false)
* aeshell/aesh#698 a required option with a defaultValue is still reported as
missing ({{dependency copy}})
* aeshell/aesh#699 two @Arguments fields in a class hierarchy: one is ignored
without an error
* aeshell/aesh#700 an undefined ${variable} in defaultValue gives an empty
string
* aeshell/aesh#701 an invalid command definition is reported as "Command not
found" (exit 127), and the cause is hidden
Improvements (we adapted our code, but picocli parity would help):
* aeshell/aesh#702 positional arguments on a group command
* aeshell/aesh#703 an optionalValue that takes the next word
* aeshell/aesh#704 array fields in @OptionList
* aeshell/aesh#705 an @OptionList with no value
* aeshell/aesh#706 register a command instance under a given name and aliases
* aeshell/aesh#707 public API to tell which options were given on the command
line
* aeshell/aesh#708 ${COMPLETION-CANDIDATES} from a completer
_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)