|
| 1 | +--- |
| 2 | +layout: docs |
| 3 | +title: Command Line Parser |
| 4 | +index: 9 |
| 5 | +--- |
| 6 | + |
| 7 | +Parse |
| 8 | +===== |
| 9 | +Ståle W. Pedersen |
| 10 | +:Author: Ståle W. Pedersen |
| 11 | + |
| 12 | +:source-highlighter: prettify |
| 13 | +
|
| 14 | +== Parse |
| 15 | +
|
| 16 | +=== Command Line Parser |
| 17 | +
|
| 18 | +Æsh provide a Command Line Parser API which make it very easy to parse command lines. The command line parser is independant of the Console API, but can be used with it if wanted. The API support defining the commands you want parsed both with annotations and with a builder pattern. |
| 19 | +
|
| 20 | +=== Annotations |
| 21 | +
|
| 22 | +Probably the easiest way to define a parser is by using annotations. |
| 23 | +The annotation must be defined at class level and is called link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/CommandDefinition.java[CommandDefinition]. |
| 24 | +CommandDefinition is the only strong requirement, but without any Options or Arguments the command would not accept any attributes. |
| 25 | +
|
| 26 | +There are four different option types: |
| 27 | +
|
| 28 | +link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/Option.java[*Option*] |
| 29 | + is the simplest kind of Option with only one value |
| 30 | + |
| 31 | + Example: -h foo |
| 32 | +
|
| 33 | +link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/OptionList.java[OptionList] |
| 34 | + can contain several values. It must be defined in connection to a field that implements Collection. |
| 35 | + |
| 36 | + Example: --foo bar1,bar2,bar3 |
| 37 | + |
| 38 | +link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/OptionGroup.java[OptionGroup] |
| 39 | + is similar to OptionList in that it store several values, but OptionGroup also store the key given. This annotation must be used in connection to a field that implements Map. |
| 40 | + |
| 41 | + Example: -Dname1=value1 -Dname2=value2 |
| 42 | + |
| 43 | +link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/Arguments.java[Arguments] |
| 44 | + defines the possible arguments thats given to a command. It do not require any option key, but as OptionList it require that the field must implement Collection. |
| 45 | +
|
| 46 | +=== A simple first example: |
| 47 | +[source,java] |
| 48 | +.Example1.java |
| 49 | +---- |
| 50 | +@CommandDefinition(name = "example1", description = "a simple example") |
| 51 | +public class Example1 { |
| 52 | +
|
| 53 | + @Option(name = "X", description = "enable X", hasValue = false) |
| 54 | + private Boolean enableX; |
| 55 | +
|
| 56 | + @Option(shortName = 'e', name = "equal", description = "enable equal", required = true) |
| 57 | + private String equal; |
| 58 | +
|
| 59 | + @Option(shortName = 'i', name = "int1") |
| 60 | + private Integer int1; |
| 61 | +
|
| 62 | + @OptionList |
| 63 | + public List<String> values; |
| 64 | +
|
| 65 | + public Boolean getEnableX() { return enableX; } |
| 66 | + public String getEqual() { return equal; } |
| 67 | + public List<String> getValues() { return values; } |
| 68 | +} |
| 69 | +---- |
| 70 | +So lets make it a bit more interesting and say that we want to use this class to parse an line like: |
| 71 | +"example1 --X --equal blabla --values one,two,three" |
| 72 | +[source,java] |
| 73 | +.Example1Test.java |
| 74 | +---- |
| 75 | +Example1 example1 = new Example1(); |
| 76 | +//this will throw an error if the object do not use the required annotations and |
| 77 | +//if the line contain option name/values that do not match the defined options |
| 78 | +ParserGenerator.parseAndPopulate(example1, "example1 --X --equal blabla --values one,two,three"); |
| 79 | +assertTrue(example1.getEnableX()); |
| 80 | +assertEquals("blabla", example1.getEqual()); |
| 81 | +assertEquals("one", example1.getValues().get(0)); |
| 82 | +---- |
| 83 | +A lot of the different settings are available for each option type which are described below. |
| 84 | +
|
| 85 | +=== Option |
| 86 | +
|
| 87 | +The different Option types have some common elements like: |
| 88 | +
|
| 89 | +* +name+ |
| 90 | +** The option name. If it's not set the field name will be used. Two dashes (--) are added to the name on the command line. |
| 91 | +* +shortName+ |
| 92 | +** The short option name. If it's not set the first char of name will be used. One dash (-) is added to the short name on the command line. |
| 93 | +* +description+ |
| 94 | +** A simple description of the option. This info is displayed when help info is shown. |
| 95 | +* +required+ |
| 96 | +** Specify if this option is required. Defaults to false. |
| 97 | +* +defaultValue[]+ |
| 98 | +** Specify the default value(s) that will be used if the option do not have any value. Defaults to empty array. |
| 99 | +* +hasValue+ |
| 100 | +** Define if this option should have a value connected to it. Only possible to set this to true when the field type is Boolean/boolean. Default is true. |
| 101 | +* +converter+ |
| 102 | +** Specify a custom converter for the data type of the connected field. |
| 103 | +* +completer+ |
| 104 | +** Specify a custom completer |
| 105 | +* +validator+ |
| 106 | +** Specify a custom validator |
| 107 | +
|
| 108 | +=== Converter |
| 109 | +When using a "custom" type for a field a converter is needed to inject the correct value. To ensure this we created a simple interface that all the converter implementations need to implement: |
| 110 | +[source,java] |
| 111 | +.CLConverter.java |
| 112 | +---- |
| 113 | +public interface CLConverter<T> { |
| 114 | + T convert(String input); |
| 115 | +} |
| 116 | +---- |
| 117 | +
|
| 118 | +Lets show an example of a rather simple (and ignorant) CurrencyConverter: |
| 119 | +[source, java] |
| 120 | +.CurrencyConverter.java |
| 121 | +---- |
| 122 | +import java.util.Currency; |
| 123 | +
|
| 124 | +public class CurrencyConverter implements CLConverter<Currency> { |
| 125 | + @Override |
| 126 | + public Currency convert(String input) { |
| 127 | + return Currency.getInstance(input); |
| 128 | + } |
| 129 | +} |
| 130 | +---- |
| 131 | +A more production friendly converter would try to do some validation of the input etc... |
| 132 | +
|
| 133 | +=== Completer |
| 134 | +Note that a completer is not needed if you only want to parse a command line and just populate the values. But if you are creating your own commands and want the possibility to autocomplete the values you need a completer. |
| 135 | +Aesh already have a built in completer for Files and Boolean/booleans, all other types require adefined completer. |
| 136 | +The Completer interface looks like: |
| 137 | +[source, java] |
| 138 | +.OptionCompleter.java |
| 139 | +---- |
| 140 | +public interface OptionCompleter { |
| 141 | + CompleterData complete(String completeValue); |
| 142 | +} |
| 143 | +---- |
| 144 | +
|
| 145 | +A FooCompleter |
| 146 | +[source, java] |
| 147 | +.FooOptionCompleter.java |
| 148 | +---- |
| 149 | +public class FooOptionCompleter { |
| 150 | + @Override |
| 151 | + public CompleterData complete(String completeValue) { |
| 152 | + List<String> values = new ArrayList<String>(); |
| 153 | + if(completeValue == null || completeValue.length() == 0) |
| 154 | + values.add("Foo"); |
| 155 | + else if("Foo".startsWith(completeValue)) |
| 156 | + values.add("Foo") |
| 157 | + return new CompleterData(values); |
| 158 | + } |
| 159 | +} |
| 160 | +---- |
| 161 | +
|
| 162 | +=== Validator |
| 163 | +The validator is optional and will be executed during population of the option value. The validator interface looks like: |
| 164 | +[source,java] |
| 165 | +.OptionValidator.java |
| 166 | +---- |
| 167 | +public interface OptionValidator<T> { |
| 168 | + void validate(T value) throws OptionValidatorException; |
| 169 | +} |
| 170 | +---- |
| 171 | +
|
| 172 | +Note that implementations of this interface must have an empty constructor. |
| 173 | +
|
| 174 | +=== Builder |
| 175 | +
|
| 176 | +It is also possible to create a parser by using the builder classes. As with annotations there are two classes; link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/ParserBuilder.java[ParserBuilder] and link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/OptionBuilder.java[OptionBuilder]. |
| 177 | +A simple example on how they can be used: |
| 178 | +
|
| 179 | +How the parser is used is described in the section below. |
| 180 | +
|
| 181 | +=== Usage |
| 182 | +
|
| 183 | +When using annotations you create the parser like: |
| 184 | +
|
| 185 | +[source,java] |
| 186 | +---- |
| 187 | +CommandLineParser parser = ParserGenerator.generateParser(MyCommand1.class); |
| 188 | +---- |
| 189 | +
|
| 190 | +With a builder you use: |
| 191 | +[source,java] |
| 192 | +---- |
| 193 | +CommandLineParser parser = ParserBuilder(....).generateParser(); |
| 194 | +---- |
| 195 | +
|
| 196 | +The link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/CommandLineParser.java[CommandLineParser] object has two tasks. First is to parse a command line and the other is to print out usage info based on the defined parameter and options. |
| 197 | +
|
| 198 | +To parse a line simply do: |
| 199 | +
|
| 200 | +[source,java] |
| 201 | +---- |
| 202 | +CommandLine cl = commandLineParser.parse(inputString); |
| 203 | +---- |
| 204 | +
|
| 205 | +The link:https://github.com/aeshell/aesh/blob/master/src/main/java/org/jboss/aesh/cl/CommandLine.java[CommandLine] class have many defined methods of checking if specific options where enabled and with what value. |
| 206 | +
|
| 207 | +Please note that if any unspecified options are found an IllegalArgumentException will be thrown. Also, if a required option is not found or options specified with a value, but is not given any an IllegalArgumentException will be thrown. |
| 208 | +
|
| 209 | +The CommandLine also feature a nice way of printing out a usage text (help info). This text is parsed from the defined parameter/options. |
| 210 | +
|
0 commit comments