1
2
3
4
5
6
7 package com.varmateo.yawg.cli;
8
9 import java.nio.file.InvalidPathException;
10 import java.nio.file.Path;
11 import java.nio.file.Paths;
12
13 import io.vavr.collection.Array;
14 import io.vavr.collection.Seq;
15 import io.vavr.collection.Set;
16 import io.vavr.control.Option;
17
18 import org.apache.commons.cli.CommandLine;
19 import org.apache.commons.cli.CommandLineParser;
20 import org.apache.commons.cli.GnuParser;
21 import org.apache.commons.cli.MissingArgumentException;
22 import org.apache.commons.cli.MissingOptionException;
23 import org.apache.commons.cli.Options;
24 import org.apache.commons.cli.ParseException;
25 import org.apache.commons.cli.UnrecognizedOptionException;
26
27
28
29
30
31 final class CliParameterSet {
32
33
34 private static final String FLAG_TRUE = "true";
35
36 private final Set<CliParameter> _allOptions;
37 private final CommandLine _cmdLine;
38
39
40
41
42
43 private CliParameterSet(
44 final Set<CliParameter> allOptions,
45 final CommandLine cmdLine) {
46
47 _allOptions = allOptions;
48 _cmdLine = cmdLine;
49 }
50
51
52
53
54
55 public static CliParameterSet parse(
56 final Set<CliParameter> options,
57 final String[] args)
58 throws CliException {
59
60 Options apacheOptions = buildApacheOptions(options);
61 CommandLineParser cliParser = new GnuParser();
62 final CommandLine cmdLine;
63
64 try {
65 cmdLine = cliParser.parse(apacheOptions, args, false);
66 } catch ( ParseException e ) {
67 throw raiseCliException(apacheOptions, e);
68 }
69
70 @SuppressWarnings("unchecked")
71 java.util.List<String> argList = cmdLine.getArgList();
72 if ( (argList!=null) && !argList.isEmpty() ) {
73
74
75
76 throw CliException.unknownOption(argList.get(0));
77 }
78
79 return new CliParameterSet(options, cmdLine);
80 }
81
82
83
84
85
86 private static Options buildApacheOptions(final Set<CliParameter> options) {
87
88 return options
89 .map(CliParameter::apacheOption)
90 .foldLeft(
91 new Options(),
92 (xs, x) -> xs.addOption(x));
93 }
94
95
96
97
98
99 private static CliException raiseCliException(
100 final Options options,
101 final ParseException e)
102 throws CliException {
103
104 final CliException cause;
105
106 if ( e instanceof MissingOptionException ) {
107 final MissingOptionException ex = (MissingOptionException)e;
108 final String shortOpt = (String)ex.getMissingOptions().get(0);
109 final org.apache.commons.cli.Option option = options.getOption(shortOpt);
110 final String optionName = getApacheOptionName(option);
111 cause = CliException.missingOption(optionName);
112 } else if ( e instanceof UnrecognizedOptionException ) {
113 final UnrecognizedOptionException ex = (UnrecognizedOptionException)e;
114 final String optionName = ex.getOption();
115 cause = CliException.unknownOption(optionName);
116 } else if ( e instanceof MissingArgumentException ) {
117 final MissingArgumentException ex = (MissingArgumentException)e;
118 final String optionName = getApacheOptionName(ex.getOption());
119 cause = CliException.missingOptionArg(optionName);
120 } else {
121 cause = CliException.optionParseFailure(e);
122 }
123
124 throw cause;
125 }
126
127
128
129
130
131 private static String getApacheOptionName(
132 final org.apache.commons.cli.Option apacheOption) {
133
134 final String result;
135
136 String longName = apacheOption.getLongOpt();
137 if ( longName != null ) {
138 result = "--" + longName;
139 } else {
140 String shortName = apacheOption.getOpt();
141 result = "-" + shortName;
142 }
143
144 return result;
145 }
146
147
148
149
150
151 public Set<CliParameter> supportedOptions() {
152
153 return _allOptions;
154 }
155
156
157
158
159
160 public boolean hasOption(final CliParameter option) {
161
162 final String optionName = option.name();
163
164 return _cmdLine.hasOption(optionName);
165 }
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181 public Seq<String> getAll(final CliParameter option) {
182
183 final String optionName = option.name();
184 final String[] optionValues = _cmdLine.getOptionValues(optionName);
185
186 return Option.of(optionValues)
187 .map(Array::of)
188 .getOrElse(Array::of);
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 public String get(final CliParameter option)
207 throws CliException {
208
209 final String optionValue;
210 final String optionName = option.name();
211 final String[] optionValues = _cmdLine.getOptionValues(optionName);
212
213 if ( optionValues != null ) {
214 final int indexOfLast = optionValues.length-1;
215 optionValue = optionValues[indexOfLast];
216 } else {
217 throw CliException.missingOption(option.literal());
218 }
219
220 return optionValue;
221 }
222
223
224
225
226
227
228
229
230
231
232
233 public String get(
234 final CliParameter option,
235 final String defaultValue) {
236
237 final String optionValue;
238 final String optionName = option.name();
239 final String[] optionValues = _cmdLine.getOptionValues(optionName);
240
241 if ( optionValues != null ) {
242 final int indexOfLast = optionValues.length-1;
243 optionValue = optionValues[indexOfLast];
244 } else {
245 optionValue = defaultValue;
246 }
247
248 return optionValue;
249 }
250
251
252
253
254
255 public Path getPath(final CliParameter option)
256 throws CliException {
257
258 String pathStr = get(option);
259
260 return stringToPath(option, pathStr);
261 }
262
263
264
265
266
267 public Path getPath(
268 final CliParameter option,
269 final Path defaultValue)
270 throws CliException {
271
272 String pathStr = get(option, null);
273
274 return pathStr == null
275 ? defaultValue
276 : stringToPath(option, pathStr);
277 }
278
279
280
281
282
283 private Path stringToPath(
284 final CliParameter option,
285 final String pathStr)
286 throws CliException {
287
288 try {
289 return Paths.get(pathStr);
290 } catch ( InvalidPathException e ) {
291 throw CliException.invalidPath(option.literal(), pathStr);
292 }
293 }
294
295
296
297
298
299 public boolean isTrue(final CliParameter option) {
300
301 boolean result = false;
302
303 if ( hasOption(option) ) {
304 String value = get(option, FLAG_TRUE);
305
306 result = FLAG_TRUE.equals(value);
307 }
308
309 return result;
310 }
311
312
313 }