This topic contains information about extending the command-line by providing additional commands.
The Overview of command-line interface article provides general command-line information. This article provides the following information about extending the command line:
You might want to extend the command-line to add support for new features or enhance the existing ones. You might want to add a new build command that compiles, packages and publishes a module. Or maybe you want to add a command that validates all of the html files in the public folder. You can easily extend the command-line interface in IBM® WebSphere® sMash as each module has the ability to provide new commands. The command-line uses the features of WebSphere sMash like event processing and virtual directories, so any module can provide additional commands.
You can create a command-line command by registering a handler for the cliTask
event and providing an implementation of the onCliTask
method. The easiest way to register a cliTask
handler is to put a Groovy script in the app/tasks
directory that allows implicit registration of the handler. The virtual directory feature of WebSphere sMash automatically finds the new cliTask
handlers. The Groovy script must provide an implementation of the onCliTask
method to be invoked when the cliTask
event is fired. The onCliTask
method can access the
event zone to obtain the arguments passed on invocation and the name of the event. The following directories are also used.
/event/task
/event/args
The following code snippet shows how the task is invoked.
def onCliTask() { def task = zget("/event/task") System.out.println("task name is " + task) zget("/event/args").each{System.out.println("arg is " + it)} }
If the task handler is written in Java™, then the handler must be explicitly registered
for the cliTask
event providing the task name.
# MyTask /config/handlers += [{ "events": "cliTask", "handler" : "zero.simple.task.MyTask.class", "conditions" : "/event/task =~ mytask" }]
The Java-based task must provide an implementation of the onCliTask
method and the event zone, available through the GlobalContext, can be used to obtain the event arguments.
public void onCliTask() { List<String> args = GlobalContext.zget("/event/args"); ... }
The task implementation might need to access the location from which the task was invoked and the location where the WebSphere sMash command-line is installed. The system property user.dir
can be used to determine the location from which the task was invoked, but this might not be desired location. The command-line supports a walk up feature in which tasks for a module can be invoked from any directory under the module. The apphome
directory is the root directory of the module and can be obtained from the event zone,
event/apphome
. The root directory of the module is probably more useful to find artifacts like the config directory.
static public File getAppRoot() { File app = zget("/event/apphome"); return app; }
The location where the command-line was installed, also referred to as zerohome
, might need to be determined. The command-line scripts set zerohome
as an environment property.
String zerohome = System.getenv("ZERO_HOME");
A task should implement the -json
option. This option allows a structured output that can be reliably parsed by applications like the Application Builder. In general, a task displays messages with the LogHelper
with level INFO, which writes to stderr. When -json
is specified, a json structured result is written to stdout. This enables you to programmatically invoke commands and use the exit code and -json
option to determine the results.
The version command in the zero.cli.tasks
module has a -full
option that displays more comprehensive results for problem determination. The -full
option fires a collectInfo
event that allows other components to provide additional detailed information to be aggregated. The collectInfo
task implementors check for the -json
option and, if specified, add their
results to the map that can be obtained from /event/collectResults
. The results
are placed in the map under a module label, for example, zero.cli.tasks
. If -json
is not specified, then the results are displayed using LogHelper
.
The map found in the /event/collectResults
event zone can not be replaced. The version task requires that this map is updated with the additional information.
The following snippets show registering a handler for the collectInfo
event, and providing results.
/config/handlers += [{ "events": "cliTask", "handler" : "my.component.Dump.class", "conditions" : "/event/task =~ collectInfo" }]
public void onCliTask() { Object obj = zget("/event/collectResults"); if (obj != null && obj instanceof Map ) { ((Map)obj).put("my.component", "my.results"); }
The -json
option can be tested by parsing the args passed in /event/args
.
With command-line task support, you can also group a set of tasks, referred to as subtasks. One of the benefits of using subtasks is that users can request help for a single subtask and see all of the available commands. This grouping makes the command-line easier to use for a set of commands that all operate on a single instance, like a module group or a repository. The following snippet shows explicitly registering a subtask for a Java-based implementation.
# Mytask /config/handlers += [{ "events": "cliTask", "handler" : "zero.cli.tasks.commands.SubCommand.class", "conditions" : "/event/task =~ mytask" }] # MySubTask /config/handlers += [{ "events": "cliSubTask", "handler" : "zero.simple.task.MySubTask.class", "conditions" : "(/event/task =~ mytask) && (/event/subTask =~ mysubtask)" }]
In the preceding example, specifying event/task
defines the task name, and event/subTask
defines the subtask. The condition match invokes the onCliSubTask
method of the handler.
Invoking the task directly, zero mytask, displays the help for the task and all of the
subtasks. A subtask is invoked by specifying the task name and then the subtask name, for example, zero mytask mysubtask
. The subtask must implement the onCliSubTask
method, as shown in the following example.
public void onCliSubTask() { System.out.println("subtask was invoked"); }
A Groovy subtask can also be explicitly registered using the SubCommand
class. In this case, the Groovy subtask script should also be explicitly registered as a handler.
Currently, only explicit registration is supported for all subtasks, implicit registration of a Groovy-based subtask is not supported at this time. Only implicit registration of groovy tasks is supported.
The following code sample shows explicitly registering a Groovy task named testing and a subtask named hello. These tasks can be invoke as zero testing hello
.
# testing /config/handlers += [{ "events": "cliTask", "handler" : "zero.cli.tasks.commands.SubCommand.class", "conditions" : "/event/task =~ testing" }] /config/handlers += [{ "events": "cliSubTask", "handler" : "hello.groovy", "conditions" : "(/event/task =~ testing) && (/event/subTask =~ hello)" }]
The implementation for hello.groovy must be in app/scripts directory.
def onCliSubTask() { System.out.println("hello from subtask"); }
You can use the task support help component to display help text for each of the tasks.
The help component is implemented using property files that are placed in the
app/tasks/help
folder. The naming convention for the help property file is
taskname.properties. A task can also supply help for all supported locales by providing
properties files with language, country and variants specified. Each task should provide help, and zero help
is the preferred way of determining which commands are available to a module.
The following list is the search order used to find the appropriate help property file for a task using the user’s locale:
As an example, to provide a help properties file for the resolve task for English (default) and Japanese, you could provide the following properties files.
resolve_ja.properties resolve.properties
Additional property files can be supplied to support other locale variants.
You can use the help component to display help for subtasks by placing those help property files under the app/tasks/help/${subtask} folder, where ${subtask}
is the name of the subtask. The help property file supports both short and full help text. The short help is displayed when help for all tasks, including subtasks, is requested. Full help is displayed when the help is requested for a single task.
Short text should be limited to one line and is specified in help property file for a task with the label short. The full text is specified with a label of full and allows multiple lines. Each specified line is printed with a new line to allow some control over formatting.
The following example shows a help properties file for a task.
short=Prints the documentation for the given command. full.1=Usage: full.2= full.3=zero help [<command>] full.4= full.5=The command will print the documentation for the given command. If no command is provided, it will print a short summary of all commands currently available to the command-line.