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