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