Evolving wildfly CLI to Aesh Command API

Version 1

    The motivation of moving CLI to a different Aesh API is to take benefit of latest Aesh features:

    • No more active polling, low level Layer in sync with CLI.
    • Better completion (e.g.: in the middle of the command). Completions can be easily reused by different commands.
    • Modern/Descriptive Command API that scales with command complexity. Simple API for simple use cases.
    • Automatic test generation. Reflection on Command classes would allow to test part of commands automaticaly.
    • Help generation. Reflection on Command classes would allow to generate help content.
    • Command top level parsing (command/action/options) is handled by Aesh. (NB: Complex parsing: Value and Operation syntax is still implemented by the CLI).
    • Should simplify the work for creating new commands by customers, community and within Red Hat.
    • Support for piping and redirecting to other commands.
    • Easily take advantage of utility commands that Aesh provides through the aesh-extensions module. Like less, more, grep, man, etc.

    In Addition this is an opportunity to revisit the exposed commands and possibly offer a better user experience (but we must keep backward compatibility at the command level).


    Aesh Command API example

     

    @CommandDefinition(name = "mycommand", description = "Do some stuff")

    public class MyCommand implements <CliCommandInvocation> {

        @Option(hasvalue = false)

        private boolean myoption;

     

         @Override

         public CommandResult execute(CliCommandInvocation commandInvocation) {

             if (myoption) {

                   ModelControllerClient client = commandInvocation.getCommandContext().getModelControllerClient();

                   // Access to server, implement command logic

                   // ...

             }      

         }

    }

    CLI backward compatibility

    2 aspects:

    1. Command line, must be 100% backward compatible. Legacy syntax is hidden from completion but is usable. We are thinking at offering a "legacy" mode where completion would be active.
    2. CommandHandler API should be deprecated, ServiceLoader discovered CommandHandler should still be usable.

    Actual implementation

    The work is done in the following branch (in sync with wildly-core master):GitHub - jfdenise/wildfly-core at aesh

     

     

    Revamped CLI commands specification

    Common rules for Command:

    • Command should be as auto-descriptive as possible, no need to read help. Completion should be enough to drive you do your task.
    • Keep the set of options simple.
    • One use case should map to one (at most) action.
    • Create less command, more sub commands. Grouping actions under a single command helps figure-out CLI capabilities. Each command with its own set of options.
    • No disjunctive set of options, prefer action per group of options.
    • Try to avoid "this option makes sense only if this other one is not used".
    • If an option is exposed, it must be usable, no "This command can't be run in XXX mode".
    • Homogeneous option naming (that is already the case)
    • For Command that have actions, no implicit action should be offered. This means that the top level command should not offer any feature other than help.
    • Backward compatibility options mustn't pollute completion.
    • Help option should be hidden but supported.
    • All command has an help that only describe it and provide a reference to sub commands help.
    • Each sub command has its own help. This will provide scalable help.
      • Aesh have a builtin man command that can be useful for static commands where we can write a doc file (atm it must be packaged into the jboss-cli.jar ).
      • Combination of static content and content retrieved from the Option/Command descriptions should be offered.

     

    This table contains the specification of each core commands. The rows in bold are commands that need rework to comply with the command rules.

    Some domain specific options are not exposed but must be supported as they are today.

    NB: All discovered commands (patch, ...) should work as of today. Marked deprecated they should be rewrote in the longer term.

     

    Command Name

    Actions (Sub command)

    Options

    Hidden options or command (Backward compatibility)

    Notes

    <path>:<op>NONENONENONENot compliant with Aesh command syntax
    aliasNONEUnnamed optionNONE
    batch

    new

    NONEbatchSwitch to batch mode
    batchclearNONEclear-batchclear all
    batchdiscardNONEdiscard-batchdiscard active
    batchlistNONEbatch -lList heldbacks batches
    batchload-fileUnnamed optionbatch --fileLoad a file
    batchholdbackUnnamed optionholdback-batch <batch name>Holdback a batch
    batchreactivateUnnamed optionbatch <batch name>Re-activate a batch
    batchedit-lineUnnamed optionedit-batch-lineEdit a line
    batchmv-line--current --newmove-batch-lineMove a line
    batchrm-lineUnnamed optionremove-batch-lineRemove a line
    batchrun--headers --verboserun-batchRun a batch
    batchrun-fileUnnamed optionrun-batch --fileRun a batch file
    catchNONENONENONEcatch
    cdNONEUnnamed option followed by --no-validationNONEcd to a resource
    clearNONENONENONEclear screen
    commandadd--node-type --property-id --command-nameNONEcreate a new command
    commandlistNONENONElist commands
    commandremoveUnnamed optioncommand remove --command-nameremove a command
    connectNONEUnnamed option (only the URL, no need for controller=)Value controller=<URL>connect to server
    <Meta Command>write-attributes--<propertyId> --<attribute0> ...--<attributeN><Meta Command> --propertyIDa generic command
    connection-infoNONENONENONEprint info
    deployfileUnnamed option followed by --disabled --force --name --runtime-name --script --unmanaged --headersdeploy <file name> ...deploy/upload a file
    deployurlUnnamed option followed by --name --headersdeploy --urldeploy an url
    deploynameUnnamed option followed by --headersdeploy --namedeploy a disabled named deployment
    deployinfoUnnamed option followed by --headersdeployment-info --nameretrieve deployment info
    deployment-overlayadd--name --content --deployments --redeploy-affected --headersNONEadd overlay
    deployment-overlayremove--name --content --deployments --redeploy-affected --headersNONEremove overlay
    deployment-overlayupload--name --content --headersNONEadd to existing
    deployment-overlaylink--name --deployments --redeploy-affected --headersNONElink
    deployment-overlayredeploy-affected--name --headersNONEredeploy
    deployment-overlaylist-content--name -lNONElist content
    deployment-overlaylist-links--name -lNONElist linked deployments
    deployment-overlaylist-overlays-ldeployment-overlay -llist overlays
    echoNONENONENONEecho
    echo-dmrNONEUnnamed option (with a filter to only propose echo-dmr compliant commands)NONEecho dir request
    elseNONEUnnamed optionNONEelse
    embedserver--admin-only (--server-config |-c) --std-out --timeout --empty-config --remove-existing-config --jboss-homeembed-serverembed a server
    embedhost-controller--admin-only (--domain-config |-c) --std-out --timeout --host-config --jboss-homeembed-host-controllerembed host controller
    end-ifNONENONENONEend an if
    end-tryNONENONENONEend try
    finallyNONENONENONEfinally
    helpNONENONE (do we really want more than commands and operations)?help --commandsdescribe commands AND operations
    historyclearNONEhistory --clearclear history
    historydisableNONEhistory --disabledisable history
    historyenableNONEhistory --enableenable history
    ifNONEUnnamed optionNONEif workflow
    lsNONEUnnamed option -l --attribute-description-property --resolve-expressionsNONEls
    moduleadd-xml--name --slot --resources --resource-delimiter --module-xmlmodule add --name ...add a new module using a module descriptor
    moduleadd--name --slot --resources --resource-delimiter --dependencies --properties --main-classmodule add --name ...add a new module
    moduleremove--name --slotNONEremove a module
    patchapplyUnnamed argument --override-all --override-modules --override --preserve --host --distribution --module-path --bundle-pathNONEapply a patch
    patchhistory--patch-stream --host --distribution --module-path --bundle-pathNONEhistory
    patchinfo--patch-id --verbose --patch-stream --distribution --module-path --bundle-path --hostpatch <id>info on a patch
    patchlist-streams--distribution --module-path --bundle-path --hostpatch --streamsinfo on streams
    patchlist-patchesNONEpatchlist patches
    patchrollback--reset-configuration --patch-is --patch-stream --rollback-to --override-all --overidde-modules --overidde --preserve --host --distribution --module-path --bundle-pathNONErollback
    patchinspectUnnamed option --verboseNONEinspect key informations
    pwdNONENONENONEpwd
    quit/exitNONENONENONEquit
    readattributeUnnamed option --node --include-defaults --verbose --resolve-expressions --headersread-attributeread attribute
    readoperationUnnamed option --node --headersread-operationread operation
    reloadNONE--admin-only --use-current-server-configNONEreload
    setNONENONENONEset var
    shutdownNONE--restart --host --timeoutNONEshutdown
    tryNONENONENONEtry
    unaliasNONEUnnamed argumentNONEremove an alias
    undeployNONEUnnamed argument --keep-content --path --script --headersNONEunderploy a deployment
    unsetNONEUnnamed argumentNONEunset var
    versionNONENONENONEprint version