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.maven.shared.invoker.InvocationRequest;
35 import org.codehaus.plexus.util.StringUtils;
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(File defaultMavenExecutable) {
157 this.defaultMavenExecutable = defaultMavenExecutable;
158 }
159
160
161
162
163
164 public void setDefaultMavenOpts(String defaultMavenOpts) {
165 this.defaultMavenOpts = defaultMavenOpts;
166 }
167
168
169
170
171
172 public void setDefaultTimeoutInSeconds(int defaultTimeoutInSeconds) {
173 this.defaultTimeoutInSeconds = defaultTimeoutInSeconds;
174 }
175
176
177
178
179
180 public void setDefaultEnvironmentVariables(Map<String, String> defaultEnvironmentVariables) {
181 this.defaultEnvironmentVariables = defaultEnvironmentVariables;
182 }
183
184
185
186
187
188 public void setDefaultUpdateSnapshots(boolean defaultUpdateSnapshots) {
189 this.defaultUpdateSnapshots = defaultUpdateSnapshots;
190 }
191
192
193
194
195
196
197 public Properties getProperties() {
198 return this.properties;
199 }
200
201
202
203
204
205
206 public String getJobName() {
207 return this.properties.getProperty("invoker.name", "");
208 }
209
210
211
212
213
214
215 public String getJobDescription() {
216 return this.properties.getProperty("invoker.description", "");
217 }
218
219
220
221
222
223
224 public int getOrdinal() {
225 return Integer.parseInt(this.properties.getProperty("invoker.ordinal", "0"));
226 }
227
228
229
230
231
232
233 public String getJreVersion() {
234 return this.properties.getProperty("invoker.java.version", "");
235 }
236
237
238
239
240
241
242 public String getJreVersion(int index) {
243 return this.properties.getProperty(SELECTOR_PREFIX + index + SelectorProperty.JAVA_VERSION, getJreVersion());
244 }
245
246
247
248
249
250
251
252 public String getMavenVersion() {
253 return this.properties.getProperty("invoker.maven.version", "");
254 }
255
256
257
258
259
260
261 public String getMavenVersion(int index) {
262 return this.properties.getProperty(SELECTOR_PREFIX + index + SelectorProperty.MAVEN_VERSION, getMavenVersion());
263 }
264
265
266
267
268
269
270 public String getOsFamily() {
271 return this.properties.getProperty("invoker.os.family", "");
272 }
273
274
275
276
277
278
279
280
281 public String getOsFamily(int index) {
282 return this.properties.getProperty(SELECTOR_PREFIX + index + SelectorProperty.OS_FAMLY, getOsFamily());
283 }
284
285 public Collection<InvokerToolchain> getToolchains() {
286 return getToolchains(Pattern.compile("invoker\\.toolchain\\.([^.]+)\\.(.+)"));
287 }
288
289 public Collection<InvokerToolchain> getToolchains(int index) {
290 return getToolchains(Pattern.compile("selector\\." + index + "\\.invoker\\.toolchain\\.([^.]+)\\.(.+)"));
291 }
292
293 private Collection<InvokerToolchain> getToolchains(Pattern p) {
294 Map<String, InvokerToolchain> toolchains = new HashMap<>();
295 for (Map.Entry<Object, Object> entry : this.properties.entrySet()) {
296 Matcher m = p.matcher(entry.getKey().toString());
297 if (m.matches()) {
298 String type = m.group(1);
299 String providesKey = m.group(2);
300 String providesValue = entry.getValue().toString();
301
302 InvokerToolchain tc = toolchains.get(type);
303 if (tc == null) {
304 tc = new InvokerToolchain(type);
305 toolchains.put(type, tc);
306 }
307 tc.addProvides(providesKey, providesValue);
308 }
309 }
310 return toolchains.values();
311 }
312
313
314
315
316
317
318
319
320 private Map<String, String> getEnvironmentVariables(int index) {
321
322 Map<String, String> envItems = new HashMap<>();
323
324 for (Map.Entry<Object, Object> entry : properties.entrySet()) {
325 Matcher matcher =
326 ENVIRONMENT_VARIABLES_PATTERN.matcher(entry.getKey().toString());
327 if (matcher.matches()) {
328
329 if (String.valueOf(index).equals(matcher.group(3))) {
330
331 envItems.put(matcher.group(1), entry.getValue().toString());
332 } else if (matcher.group(3) == null) {
333
334 if (!envItems.containsKey(matcher.group(1))) {
335 envItems.put(matcher.group(1), entry.getValue().toString());
336 }
337 }
338 }
339 }
340 return envItems;
341 }
342
343
344
345
346
347
348
349 public boolean isInvocationDefined(int index) {
350 return Arrays.stream(InvocationProperty.values())
351 .map(InvocationProperty::toString)
352 .map(v -> properties.getProperty(v + '.' + index))
353 .anyMatch(Objects::nonNull);
354 }
355
356
357
358
359
360
361
362
363 public boolean isSelectorDefined(int index) {
364 return Arrays.stream(SelectorProperty.values())
365 .map(v -> v.suffix)
366 .map(v -> properties.getProperty(SELECTOR_PREFIX + index + v))
367 .anyMatch(Objects::nonNull);
368 }
369
370 private <T> void setIfNotNull(Consumer<T> consumer, T value) {
371 if (value != null) {
372 consumer.accept(value);
373 }
374 }
375
376
377
378
379
380
381
382
383 public void configureInvocation(InvocationRequest request, int index) {
384 get(InvocationProperty.PROJECT, index).ifPresent(project -> {
385 File file = new File(request.getBaseDirectory(), project);
386 if (file.isFile()) {
387 request.setBaseDirectory(file.getParentFile());
388 request.setPomFile(file);
389 } else {
390 request.setBaseDirectory(file);
391 request.setPomFile(null);
392 }
393 });
394
395 setIfNotNull(
396 request::setGoals,
397 get(InvocationProperty.GOALS, index)
398 .map(s -> StringUtils.split(s, ", \t\n\r\f"))
399 .map(Arrays::asList)
400 .filter(l -> !l.isEmpty())
401 .orElse(defaultGoals));
402
403 setIfNotNull(
404 request::setProfiles,
405 get(InvocationProperty.PROFILES, index)
406 .map(s -> StringUtils.split(s, ", \t\n\r\f"))
407 .map(Arrays::asList)
408 .filter(l -> !l.isEmpty())
409 .orElse(defaultProfiles));
410
411 setIfNotNull(
412 request::setMavenExecutable,
413 get(InvocationProperty.MAVEN_EXECUTABLE, index).map(File::new).orElse(defaultMavenExecutable));
414
415 setIfNotNull(
416 request::setMavenOpts, get(InvocationProperty.MAVEN_OPTS, index).orElse(defaultMavenOpts));
417
418 get(InvocationProperty.FAILURE_BEHAVIOR, index)
419 .map(InvocationRequest.ReactorFailureBehavior::valueOfByLongOption)
420 .ifPresent(request::setReactorFailureBehavior);
421
422 get(InvocationProperty.NON_RECURSIVE, index)
423 .map(Boolean::parseBoolean)
424 .map(b -> !b)
425 .ifPresent(request::setRecursive);
426
427 get(InvocationProperty.OFFLINE, index).map(Boolean::parseBoolean).ifPresent(request::setOffline);
428
429 setIfNotNull(
430 request::setDebug,
431 get(InvocationProperty.DEBUG, index).map(Boolean::parseBoolean).orElse(defaultDebug));
432
433 setIfNotNull(
434 request::setQuiet,
435 get(InvocationProperty.QUIET, index).map(Boolean::parseBoolean).orElse(defaultQuiet));
436
437 setIfNotNull(
438 request::setTimeoutInSeconds,
439 get(InvocationProperty.TIMEOUT_IN_SECONDS, index)
440 .map(Integer::parseInt)
441 .orElse(defaultTimeoutInSeconds));
442
443 setIfNotNull(
444 request::setUpdateSnapshots,
445 get(InvocationProperty.UPDATE_SNAPSHOTS, index)
446 .map(Boolean::parseBoolean)
447 .orElse(defaultUpdateSnapshots));
448
449 Optional.ofNullable(defaultEnvironmentVariables).ifPresent(evn -> evn.forEach(request::addShellEnvironment));
450
451 getEnvironmentVariables(index).forEach(request::addShellEnvironment);
452 }
453
454
455
456
457
458
459
460
461
462 public boolean isExpectedResult(int exitCode, int index) {
463 boolean nonZeroExit = "failure"
464 .equalsIgnoreCase(get(InvocationProperty.BUILD_RESULT, index).orElse(null));
465 return (exitCode != 0) == nonZeroExit;
466 }
467
468
469
470
471
472
473
474 public String getSystemPropertiesFile(int index) {
475 return get(InvocationProperty.SYSTEM_PROPERTIES_FILE, index).orElse(null);
476 }
477
478
479
480
481
482
483
484 public String getSettingsFile(int index) {
485 return get(InvocationProperty.SETTINGS_FILE, index).orElse(null);
486 }
487
488
489
490
491
492
493
494
495
496
497
498 Optional<String> get(String key, int index) {
499 if (index < 0) {
500 throw new IllegalArgumentException("invalid invocation index: " + index);
501 }
502
503
504 String value = Optional.ofNullable(properties.getProperty(key + '.' + index))
505 .orElseGet(() -> properties.getProperty(key));
506
507 return Optional.ofNullable(value).map(String::trim).filter(s -> !s.isEmpty());
508 }
509
510 private Optional<String> get(InvocationProperty prop, int index) {
511 return get(prop.toString(), index);
512 }
513 }