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