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