CLI modules enables you to write simple @Command beans reusing @RootConfiguration for their parameters.

Sample

@Command(name = "my-commands", description = "A super command.") (1)
public class MyCommand implements Runnable { (2)
    private final Conf conf;

    public MyCommand(final Conf conf) { (3)
        this.conf = conf;
    }

    @Override
    public void run() { (4)
        // impl what you want
    }

    @RootConfiguration("my-commands") (5)
    public record Conf(String name) {}
}
  1. Mark a bean with @Command to make it a command. You can customize the command name (first command line value to call the command) and its description (usage/help on error),
  2. Ensure to make the command a Runnable ,
  3. Ensure to have a constructor with the first parameter (required) being the configuration class (as in configuration ),
  4. Implement your command in run callback,
  5. The configuration of the command is a standard one, you can customize the prefix thanks @RootConfiguration annotation (so here all options will use --my-command-xxxx instead of default --Conf-xxx ).
TIP

if you don't want to set any prefix for the configuration, set the prefix in @RootConfiguration to -: the generated factory then reads the plain xxx keys (so --xxx on the command line) instead of <prefix>.xxx.

NOTE

since the keys of a - configuration are plain keys, the record also resolves naturally when injected as a plain bean: command line arguments (--xxx), system properties (xxx) and environment variables (XXX) are all usable without any custom configuration source bridge.

Injections

You can inject any simple type (classes, not lists) beans in your command through the constructor (> first parameter).

TIP
if you need to inject a list, you can always create a bean which holds the list and inject this wrapper in your command.

Subcommands

The command name is a path of segments: @Command(name = {"deploy", "run"}) declares the deploy runsubcommand while @Command(name = "deploy/run") is a single literal deploy/run segment. The single-value shorthand is accepted for one segment. Segments are matched against the leading CLI arguments and the longest match wins, so deploy and deploy run can coexist.

@Command(name = {"deploy", "run"}, description = "Run a deployment.") (1)
public class DeployRunCommand implements Runnable {
    private final Conf conf;

    public DeployRunCommand(final Conf conf) {
        this.conf = conf;
    }

    @Override
    public void run() {
        // impl what you want
    }

    @RootConfiguration("deploy.run") (2)
    public record Conf(String name) {}
}
  1. Use an array to declare a subcommand path, a single value is a single segment (literal / are kept),
  2. Options then use the --deploy-run-xxx form.

Parents are implicit dispatchers and need no @Command class:

  • my-app deploy or my-app deploy --help prints the group usage filtered to the direct subcommands of deploy (implicit intermediate groups are marked (group)),

  • my-app deploy foo where foo is not a subcommand reports a missing command error scoped to the deploy group,

  • my-app --help, my-app help and my-app help <path> print the global, command or group usage,

  • my-app deploy run --help prints the options of the deploy run command.

Launching

fusion-cli provides an integration with Launcher main, if you don't use it, you will have to call yourself CLIAwaiter and register an instance of Args.

Shell completion

Every Fusion CLI application exposes completion commands generating shell completion scripts (subcommands completion/bash, completion/powershell and completion/zsh): they register as regularCliCommand beans, so they appear in the app usage, documentation and their own completion.

Only the completion command matching the current shell is registered by default: the shell is detected from$SHELL (bash/zsh) or the OS (powershell on Windows), defaulting to bash. You can force the set with thefusion.cli.shell configuration key (fusion.cli.shell or FUSION_CLI_SHELL):bash, zsh, powershell to keep a single one, all to register every shell, or none to register none.

  • bash: my-app completion bash > /etc/bash_completion.d/my-app then source it, or eval "$(my-app completion bash)".

  • zsh: my-app completion zsh > ~/.zfunc/_my-app and add fpath+autoload -Uz compinit && compinit.

  • powershell: my-app completion powershell | Out-String | Invoke-Expression or paste the output into your $PROFILE.

The application name used in the scripts defaults to app and can be overridden with thefusion.cli.app.name configuration key. Completion proposes subcommand segments while the command path is incomplete, then the --options of the resolved leaf command. For testing, completion/bash also reads thecomp.line and comp.point configuration keys (the COMP_LINE/COMP_POINT environment variables set by the shell completer) to report the candidates for an arbitrary cursor position instead of printing the script.