1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.plugins.invoker;
20
21 import java.io.File;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Optional;
29 import java.util.Properties;
30 import java.util.function.Consumer;
31 import java.util.regex.Matcher;
32 import java.util.regex.Pattern;
33
34 import org.apache.commons.lang3.StringUtils;
35 import org.apache.maven.shared.invoker.InvocationRequest;
36
37
38
39
40
41
42 class InvokerProperties {
43 private static final String SELECTOR_PREFIX = "selector.";
44
45 private static final Pattern ENVIRONMENT_VARIABLES_PATTERN =
46 Pattern.compile("invoker\\.environmentVariables\\.([A-Za-z][^.]+)(\\.([0-9]+))?");
47
48
49 private Boolean defaultDebug;
50 private Boolean defaultQuiet;
51 private List<String> defaultGoals;
52 private List<String> defaultProfiles;
53 private String defaultMavenOpts;
54 private Integer defaultTimeoutInSeconds;
55 private Map<String, String> defaultEnvironmentVariables;
56 private File defaultMavenExecutable;
57 private Boolean defaultUpdateSnapshots;
58
59 private enum InvocationProperty {
60 PROJECT("invoker.project"),
61 BUILD_RESULT("invoker.buildResult"),
62 GOALS("invoker.goals"),
63 PROFILES("invoker.profiles"),
64 MAVEN_EXECUTABLE("invoker.mavenExecutable"),
65 MAVEN_OPTS("invoker.mavenOpts"),
66 FAILURE_BEHAVIOR("invoker.failureBehavior"),
67 NON_RECURSIVE("invoker.nonRecursive"),
68 OFFLINE("invoker.offline"),
69 SYSTEM_PROPERTIES_FILE("invoker.systemPropertiesFile"),
70 DEBUG("invoker.debug"),
71 QUIET("invoker.quiet"),
72 SETTINGS_FILE("invoker.settingsFile"),
73 TIMEOUT_IN_SECONDS("invoker.timeoutInSeconds"),
74 UPDATE_SNAPSHOTS("invoker.updateSnapshots");
75
76 private final String key;
77
78 InvocationProperty(final String s) {
79 this.key = s;
80 }
81
82 @Override
83 public String toString() {
84 return key;
85 }
86 }
87
88 private enum SelectorProperty {
89 JAVA_VERSION(".java.version"),
90 MAVEN_VERSION(".maven.version"),
91 OS_FAMLY(".os.family");
92
93 private final String suffix;
94
95 SelectorProperty(String suffix) {
96 this.suffix = suffix;
97 }
98
99 @Override
100 public String toString() {
101 return suffix;
102 }
103 }
104
105
106
107
108 private final Properties properties;
109
110
111
112
113
114
115
116 InvokerProperties(Properties properties) {
117 this.properties = (properties != null) ? properties : new Properties();
118 }
119
120
121
122
123
124 public void setDefaultDebug(boolean defaultDebug) {
125 this.defaultDebug = defaultDebug;
126 }
127
128
129
130
131
132 public void setDefaultQuiet(boolean defaultQuiet) {
133 this.defaultQuiet = defaultQuiet;
134 }
135
136
137
138
139
140 public void setDefaultGoals(List<String> defaultGoals) {
141 this.defaultGoals = defaultGoals;
142 }
143
144
145
146
147
148 public void setDefaultProfiles(List<String> defaultProfiles) {
149 this.defaultProfiles = defaultProfiles;
150 }
151
152
153
154
155
156 public void setDefaultMavenExecutable(String defaultMavenExecutable) {
157 if (StringUtils.isNotBlank(defaultMavenExecutable)) {
158 this.defaultMavenExecutable = new File(defaultMavenExecutable);
159 }
160 }
161
162
163
164
165
166 public void setDefaultMavenOpts(String defaultMavenOpts) {
167 this.defaultMavenOpts = defaultMavenOpts;
168 }
169
170
171
172
173
174 public void setDefaultTimeoutInSeconds(int defaultTimeoutInSeconds) {
175 this.defaultTimeoutInSeconds = defaultTimeoutInSeconds;
176 }
177
178
179
180
181
182 public void setDefaultEnvironmentVariables(Map<String, String> defaultEnvironmentVariables) {
183 this.defaultEnvironmentVariables = defaultEnvironmentVariables;
184 }
185
186
187
188
189
190 public void setDefaultUpdateSnapshots(boolean defaultUpdateSnapshots) {
191 this.defaultUpdateSnapshots = defaultUpdateSnapshots;
192 }
193
194
195
196
197
198
199 public Properties getProperties() {
200 return this.properties;
201 }
202
203
204
205
206
207
208 public String getJobName() {
209 return this.properties.getProperty("invoker.name", "");
210 }
211
212
213
214
215
216
217 public String getJobDescription() {
218 return this.properties.getProperty("invoker.description", "");
219 }
220
221
222
223
224
225
226 public int getOrdinal() {
227 return Integer.parseInt(this.properties.getProperty("invoker.ordinal", "0"));
228 }
229
230
231
232
233
234
235 public String getJreVersion() {
236 return this.properties.getProperty("invoker.java.version", "");
237 }
238
239
240
241
242
243
244 public String getJreVersion(int index) {
245 return this.properties.getProperty(SELECTOR_PREFIX + index + SelectorProperty.JAVA_VERSION, getJreVersion());
246 }
247
248
249
250
251
252
253
254 public String getMavenVersion() {
255 return this.properties.getProperty("invoker.maven.version", "");
256 }
257
258
259
260
261
262
263 public String getMavenVersion(int index) {
264 return this.properties.getProperty(SELECTOR_PREFIX + index + SelectorProperty.MAVEN_VERSION, getMavenVersion());
265 }
266
267
268
269
270
271
272 public String getOsFamily() {
273 return this.properties.getProperty("invoker.os.family", "");
274 }
275
276
277
278
279
280
281
282
283 public String getOsFamily(int index) {
284 return this.properties.getProperty(SELECTOR_PREFIX + index + SelectorProperty.OS_FAMLY, getOsFamily());
285 }
286
287 public Collection<InvokerToolchain> getToolchains() {
288 return getToolchains(Pattern.compile("invoker\\.toolchain\\.([^.]+)\\.(.+)"));
289 }
290
291 public Collection<InvokerToolchain> getToolchains(int index) {
292 return getToolchains(Pattern.compile("selector\\." + index + "\\.invoker\\.toolchain\\.([^.]+)\\.(.+)"));
293 }
294
295 private Collection<InvokerToolchain> getToolchains(Pattern p) {
296 Map<String, InvokerToolchain> toolchains = new HashMap<>();
297 for (Map.Entry<Object, Object> entry : this.properties.entrySet()) {
298 Matcher m = p.matcher(entry.getKey().toString());
299 if (m.matches()) {
300 String type = m.group(1);
301 String providesKey = m.group(2);
302 String providesValue = entry.getValue().toString();
303
304 InvokerToolchain tc = toolchains.get(type);
305 if (tc == null) {
306 tc = new InvokerToolchain(type);
307 toolchains.put(type, tc);
308 }
309 tc.addProvides(providesKey, providesValue);
310 }
311 }
312 return toolchains.values();
313 }
314
315
316
317
318
319
320
321
322 private Map<String, String> getEnvironmentVariables(int index) {
323
324 Map<String, String> envItems = new HashMap<>();
325
326 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
327 Matcher matcher =
328 ENVIRONMENT_VARIABLES_PATTERN.matcher(entry.getKey().toString());
329 if (matcher.matches()) {
330
331 if (String.valueOf(index).equals(matcher.group(3))) {
332
333 envItems.put(matcher.group(1), entry.getValue().toString());
334 } else if (matcher.group(3) == null) {
335
336 if (!envItems.containsKey(matcher.group(1))) {
337 envItems.put(matcher.group(1), entry.getValue().toString());
338 }
339 }
340 }
341 }
342 return envItems;
343 }
344
345
346
347
348
349
350
351 public boolean isInvocationDefined(int index) {
352 return Arrays.stream(InvocationProperty.values())
353 .map(InvocationProperty::toString)
354 .map(v -> properties.getProperty(v + '.' + index))
355 .anyMatch(Objects::nonNull);
356 }
357
358
359
360
361
362
363
364
365 public boolean isSelectorDefined(int index) {
366 return Arrays.stream(SelectorProperty.values())
367 .map(v -> v.suffix)
368 .map(v -> properties.getProperty(SELECTOR_PREFIX + index + v))
369 .anyMatch(Objects::nonNull);
370 }
371
372 private <T> void setIfNotNull(Consumer<T> consumer, T value) {
373 if (value != null) {
374 consumer.accept(value);
375 }
376 }
377
378
379
380
381
382
383
384
385 public void configureInvocation(InvocationRequest request, int index) {
386 get(InvocationProperty.PROJECT, index).ifPresent(project -> {
387 File file = new File(request.getBaseDirectory(), project);
388 if (file.isFile()) {
389 request.setBaseDirectory(file.getParentFile());
390 request.setPomFile(file);
391 } else {
392 request.setBaseDirectory(file);
393 request.setPomFile(null);
394 }
395 });
396
397 setIfNotNull(
398 request::setGoals,
399 get(InvocationProperty.GOALS, index)
400 .map(s -> StringUtils.split(s, ", \t\n\r\f"))
401 .map(Arrays::asList)
402 .filter(l -> !l.isEmpty())
403 .orElse(defaultGoals));
404
405 setIfNotNull(
406 request::setProfiles,
407 get(InvocationProperty.PROFILES, index)
408 .map(s -> StringUtils.split(s, ", \t\n\r\f"))
409 .map(Arrays::asList)
410 .filter(l -> !l.isEmpty())
411 .orElse(defaultProfiles));
412
413 setIfNotNull(
414 request::setMavenExecutable,
415 get(InvocationProperty.MAVEN_EXECUTABLE, index).map(File::new).orElse(defaultMavenExecutable));
416
417 setIfNotNull(
418 request::setMavenOpts, get(InvocationProperty.MAVEN_OPTS, index).orElse(defaultMavenOpts));
419
420 get(InvocationProperty.FAILURE_BEHAVIOR, index)
421 .map(InvocationRequest.ReactorFailureBehavior::valueOfByLongOption)
422 .ifPresent(request::setReactorFailureBehavior);
423
424 get(InvocationProperty.NON_RECURSIVE, index)
425 .map(Boolean::parseBoolean)
426 .map(b -> !b)
427 .ifPresent(request::setRecursive);
428
429 get(InvocationProperty.OFFLINE, index).map(Boolean::parseBoolean).ifPresent(request::setOffline);
430
431 setIfNotNull(
432 request::setDebug,
433 get(InvocationProperty.DEBUG, index).map(Boolean::parseBoolean).orElse(defaultDebug));
434
435 setIfNotNull(
436 request::setQuiet,
437 get(InvocationProperty.QUIET, index).map(Boolean::parseBoolean).orElse(defaultQuiet));
438
439 setIfNotNull(
440 request::setTimeoutInSeconds,
441 get(InvocationProperty.TIMEOUT_IN_SECONDS, index)
442 .map(Integer::parseInt)
443 .orElse(defaultTimeoutInSeconds));
444
445 setIfNotNull(
446 request::setUpdateSnapshots,
447 get(InvocationProperty.UPDATE_SNAPSHOTS, index)
448 .map(Boolean::parseBoolean)
449 .orElse(defaultUpdateSnapshots));
450
451 Optional.ofNullable(defaultEnvironmentVariables).ifPresent(evn -> evn.forEach(request::addShellEnvironment));
452
453 getEnvironmentVariables(index).forEach(request::addShellEnvironment);
454 }
455
456
457
458
459
460
461
462
463
464 public boolean isExpectedResult(int exitCode, int index) {
465 boolean nonZeroExit = "failure"
466 .equalsIgnoreCase(get(InvocationProperty.BUILD_RESULT, index).orElse(null));
467 return (exitCode != 0) == nonZeroExit;
468 }
469
470
471
472
473
474
475
476 public String getSystemPropertiesFile(int index) {
477 return get(InvocationProperty.SYSTEM_PROPERTIES_FILE, index).orElse(null);
478 }
479
480
481
482
483
484
485
486 public String getSettingsFile(int index) {
487 return get(InvocationProperty.SETTINGS_FILE, index).orElse(null);
488 }
489
490
491
492
493
494
495
496
497
498
499
500 Optional<String> get(String key, int index) {
501 if (index < 0) {
502 throw new IllegalArgumentException("invalid invocation index: " + index);
503 }
504
505
506 String value = Optional.ofNullable(properties.getProperty(key + '.' + index))
507 .orElseGet(() -> properties.getProperty(key));
508
509 return Optional.ofNullable(value).map(String::trim).filter(s -> !s.isEmpty());
510 }
511
512 private Optional<String> get(InvocationProperty prop, int index) {
513 return get(prop.toString(), index);
514 }
515 }