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:
- 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.
- 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> | NONE | NONE | NONE | Not compliant with Aesh command syntax |
alias | NONE | Unnamed option | NONE | |
batch | new | NONE | batch | Switch to batch mode |
batch | clear | NONE | clear-batch | clear all |
batch | discard | NONE | discard-batch | discard active |
batch | list | NONE | batch -l | List heldbacks batches |
batch | load-file | Unnamed option | batch --file | Load a file |
batch | holdback | Unnamed option | holdback-batch <batch name> | Holdback a batch |
batch | reactivate | Unnamed option | batch <batch name> | Re-activate a batch |
batch | edit-line | Unnamed option | edit-batch-line | Edit a line |
batch | mv-line | --current --new | move-batch-line | Move a line |
batch | rm-line | Unnamed option | remove-batch-line | Remove a line |
batch | run | --headers --verbose | run-batch | Run a batch |
batch | run-file | Unnamed option | run-batch --file | Run a batch file |
catch | NONE | NONE | NONE | catch |
cd | NONE | Unnamed option followed by --no-validation | NONE | cd to a resource |
clear | NONE | NONE | NONE | clear screen |
command | add | --node-type --property-id --command-name | NONE | create a new command |
command | list | NONE | NONE | list commands |
command | remove | Unnamed option | command remove --command-name | remove a command |
connect | NONE | Unnamed option (only the URL, no need for controller=) | Value controller=<URL> | connect to server |
<Meta Command> | write-attributes | --<propertyId> --<attribute0> ...--<attributeN> | <Meta Command> --propertyID | a generic command |
connection-info | NONE | NONE | NONE | print info |
deploy | file | Unnamed option followed by --disabled --force --name --runtime-name --script --unmanaged --headers | deploy <file name> ... | deploy/upload a file |
deploy | url | Unnamed option followed by --name --headers | deploy --url | deploy an url |
deploy | name | Unnamed option followed by --headers | deploy --name | deploy a disabled named deployment |
deploy | info | Unnamed option followed by --headers | deployment-info --name | retrieve deployment info |
deployment-overlay | add | --name --content --deployments --redeploy-affected --headers | NONE | add overlay |
deployment-overlay | remove | --name --content --deployments --redeploy-affected --headers | NONE | remove overlay |
deployment-overlay | upload | --name --content --headers | NONE | add to existing |
deployment-overlay | link | --name --deployments --redeploy-affected --headers | NONE | link |
deployment-overlay | redeploy-affected | --name --headers | NONE | redeploy |
deployment-overlay | list-content | --name -l | NONE | list content |
deployment-overlay | list-links | --name -l | NONE | list linked deployments |
deployment-overlay | list-overlays | -l | deployment-overlay -l | list overlays |
echo | NONE | NONE | NONE | echo |
echo-dmr | NONE | Unnamed option (with a filter to only propose echo-dmr compliant commands) | NONE | echo dir request |
else | NONE | Unnamed option | NONE | else |
embed | server | --admin-only (--server-config |-c) --std-out --timeout --empty-config --remove-existing-config --jboss-home | embed-server | embed a server |
embed | host-controller | --admin-only (--domain-config |-c) --std-out --timeout --host-config --jboss-home | embed-host-controller | embed host controller |
end-if | NONE | NONE | NONE | end an if |
end-try | NONE | NONE | NONE | end try |
finally | NONE | NONE | NONE | finally |
help | NONE | NONE (do we really want more than commands and operations)? | help --commands | describe commands AND operations |
history | clear | NONE | history --clear | clear history |
history | disable | NONE | history --disable | disable history |
history | enable | NONE | history --enable | enable history |
if | NONE | Unnamed option | NONE | if workflow |
ls | NONE | Unnamed option -l --attribute-description-property --resolve-expressions | NONE | ls |
module | add-xml | --name --slot --resources --resource-delimiter --module-xml | module add --name ... | add a new module using a module descriptor |
module | add | --name --slot --resources --resource-delimiter --dependencies --properties --main-class | module add --name ... | add a new module |
module | remove | --name --slot | NONE | remove a module |
patch | apply | Unnamed argument --override-all --override-modules --override --preserve --host --distribution --module-path --bundle-path | NONE | apply a patch |
patch | history | --patch-stream --host --distribution --module-path --bundle-path | NONE | history |
patch | info | --patch-id --verbose --patch-stream --distribution --module-path --bundle-path --host | patch <id> | info on a patch |
patch | list-streams | --distribution --module-path --bundle-path --host | patch --streams | info on streams |
patch | list-patches | NONE | patch | list patches |
patch | rollback | --reset-configuration --patch-is --patch-stream --rollback-to --override-all --overidde-modules --overidde --preserve --host --distribution --module-path --bundle-path | NONE | rollback |
patch | inspect | Unnamed option --verbose | NONE | inspect key informations |
pwd | NONE | NONE | NONE | pwd |
quit/exit | NONE | NONE | NONE | quit |
read | attribute | Unnamed option --node --include-defaults --verbose --resolve-expressions --headers | read-attribute | read attribute |
read | operation | Unnamed option --node --headers | read-operation | read operation |
reload | NONE | --admin-only --use-current-server-config | NONE | reload |
set | NONE | NONE | NONE | set var |
shutdown | NONE | --restart --host --timeout | NONE | shutdown |
try | NONE | NONE | NONE | try |
unalias | NONE | Unnamed argument | NONE | remove an alias |
undeploy | NONE | Unnamed argument --keep-content --path --script --headers | NONE | underploy a deployment |
unset | NONE | Unnamed argument | NONE | unset var |
version | NONE | NONE | NONE | print version |
Comments