Skip to content

refactor(cli): self-register commands via ServiceLoader#171

Merged
rlaope merged 1 commit into
masterfrom
refactor/cli-serviceloader
May 9, 2026
Merged

refactor(cli): self-register commands via ServiceLoader#171
rlaope merged 1 commit into
masterfrom
refactor/cli-serviceloader

Conversation

@rlaope
Copy link
Copy Markdown
Owner

@rlaope rlaope commented May 9, 2026

Summary

ArgusCli.java held a 67-line manual registration list. Every command had to be imported and added to a LinkedHashMap by hand, and the ordering of that list happened to drive help output.

This PR moves discovery to a META-INF/services/io.argus.cli.command.Command manifest. ArgusCli loads commands via ServiceLoader and sorts within each CommandGroup alphabetically for the help screen β€” so behaviour no longer depends on registration order.

TuiCommand stays explicitly registered after the loader pass because it takes the populated commands map as a constructor argument and so cannot satisfy ServiceLoader's no-arg-constructor requirement.

  • ArgusCli.java: βˆ’149 lines (66 manual register calls + 67 imports gone)
  • META-INF/services/io.argus.cli.command.Command: +66 lines (one FQN per command)
  • 17-command smoke pass on the fatJar; help still shows "67 commands"

Why this and not full SPI unification

The earlier architectural sketch suggested merging CLI Command with the server-side DiagnosticCommand SPI. That overlap exists on metadata (name/group/description) but the execute(...) shapes diverge β€” CLI commands carry ANSI / TUI / --format=json / CliConfig concerns that CommandContext doesn't model, and only ~29 of the 67 CLI commands have a server sibling. A full unification would touch ~80 files for a mostly-cosmetic win. The actual friction was the central manual registration list, which this PR eliminates.

Behaviour changes

  • Help output is now alphabetical within each CommandGroup. Previous order was a hand-curated list that drifted as commands were added at the end. The group order itself (the CommandGroup enum's declaration order) is unchanged.
  • Adding a CLI command no longer requires editing ArgusCli.java β€” drop the class and add one line to the META-INF file.

Test plan

  • ./gradlew build -x integrationTest passes
  • argus --help shows "67 commands" line
  • Spot-checked 17 commands resolve via ServiceLoader (alert/ps/gc/heap/threads/doctor/harness/zgc/gcwhy/nmt/jfr/profile/flame/top/trace/tui/watch)
  • Verify help output sort order on the user side meets expectations

ArgusCli.java held a 67-line manual registration list β€” every command
class had to be imported and added to a LinkedHashMap by hand, and the
ordering of that list happened to drive help output. Adding a command
required touching one place outside the command's own file.

Move discovery to a META-INF/services/io.argus.cli.command.Command
manifest. ArgusCli loads commands with ServiceLoader; help output sorts
alphabetically within each CommandGroup so behaviour no longer depends
on registration order.

TuiCommand stays explicitly registered after the loader pass because it
takes the populated commands map as a constructor argument and so has
no public no-arg constructor that ServiceLoader requires.

Scope note: this PR does not unify CLI Command with the server-side
DiagnosticCommand SPI. Those interfaces overlap on metadata
(name/group/description) but diverge on the execute() shape β€” CLI
commands carry ANSI/TUI/--format=json/CliConfig concerns the server
context object does not have. Unification would invade ~80 files for a
mostly-cosmetic win, while the registration friction (one central list)
is what actually hurt. Helps output went from 67 manual lines to 66
declarative lines plus alphabetical-within-group ordering.

ArgusCli.java: -149 lines.

Signed-off-by: rlaope <piyrw9754@gmail.com>
@rlaope rlaope merged commit 54eab2f into master May 9, 2026
11 checks passed
@rlaope rlaope deleted the refactor/cli-serviceloader branch May 9, 2026 03:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant