1 package org.apache.maven.plugins.invoker;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.File;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Properties;
26
27 import org.apache.maven.shared.invoker.InvocationRequest;
28 import org.apache.maven.shared.invoker.InvocationRequest.ReactorFailureBehavior;
29 import org.codehaus.plexus.util.StringUtils;
30
31 /**
32 * Provides a convenient facade around the <code>invoker.properties</code>.
33 *
34 * @author Benjamin Bentmann
35 * @version $Id: InvokerProperties.java 1779250 2017-01-17 20:20:02Z rfscholte $
36 */
37 class InvokerProperties
38 {
39 private static final String SELECTOR_PREFIX = "selector.";
40
41 private enum InvocationProperty
42 {
43 PROJECT( "invoker.project" ),
44 GOALS( "invoker.goals" ),
45 PROFILES( "invoker.profiles" ),
46 MAVEN_OPTS( "invoker.mavenOpts" ),
47 FAILURE_BEHAVIOR( "invoker.failureBehavior" ),
48 NON_RECURSIVE( "invoker.nonRecursive" ),
49 OFFLINE( "invoker.offline" ),
50 SYSTEM_PROPERTIES_FILE( "invoker.systemPropertiesFile" ),
51 DEBUG( "invoker.debug" ),
52 SETTINGS_FILE ( "invoker.settingsFile" );
53
54 private final String key;
55
56 private InvocationProperty( final String s )
57 {
58 this.key = s;
59 }
60
61 @Override
62 public String toString()
63 {
64 return key;
65 }
66 }
67
68 private enum SelectorProperty
69 {
70 JAVA_VERSION( ".java.version" ),
71 MAVEN_VERSION( ".maven.version" ),
72 OS_FAMLY( ".os.family" );
73
74 private final String suffix;
75
76 private SelectorProperty( String suffix )
77 {
78 this.suffix = suffix;
79 }
80
81 @Override
82 public String toString()
83 {
84 return suffix;
85 }
86 }
87
88 /**
89 * The invoker properties being wrapped.
90 */
91 private final Properties properties;
92
93 /**
94 * Creates a new facade for the specified invoker properties. The properties will not be copied, so any changes to
95 * them will be reflected by the facade.
96 *
97 * @param properties The invoker properties to wrap, may be <code>null</code> if none.
98 */
99 public InvokerProperties( Properties properties )
100 {
101 this.properties = ( properties != null ) ? properties : new Properties();
102 }
103
104 /**
105 * Gets the invoker properties being wrapped.
106 *
107 * @return The invoker properties being wrapped, never <code>null</code>.
108 */
109 public Properties getProperties()
110 {
111 return this.properties;
112 }
113
114 /**
115 * Gets the name of the corresponding build job.
116 *
117 * @return The name of the build job or an empty string if not set.
118 */
119 public String getJobName()
120 {
121 return this.properties.getProperty( "invoker.name", "" );
122 }
123
124 /**
125 * Gets the description of the corresponding build job.
126 *
127 * @return The description of the build job or an empty string if not set.
128 */
129 public String getJobDescription()
130 {
131 return this.properties.getProperty( "invoker.description", "" );
132 }
133
134 /**
135 * Gets the specification of JRE versions on which this build job should be run.
136 *
137 * @return The specification of JRE versions or an empty string if not set.
138 */
139 public String getJreVersion()
140 {
141 return this.properties.getProperty( "invoker.java.version", "" );
142 }
143
144 /**
145 * Gets the specification of JRE versions on which this build job should be run.
146 *
147 * @return The specification of JRE versions or an empty string if not set.
148 */
149 public String getJreVersion( int index )
150 {
151 return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.JAVA_VERSION.suffix,
152 getJreVersion() );
153 }
154
155 /**
156 * Gets the specification of Maven versions on which this build job should be run.
157 *
158 * @return The specification of Maven versions on which this build job should be run.
159 * @since 1.5
160 */
161 public String getMavenVersion()
162 {
163 return this.properties.getProperty( "invoker.maven.version", "" );
164 }
165
166 /**
167 *
168 * @param index the selector index
169 * @return The specification of Maven versions on which this build job should be run.
170 * @since 3.0.0
171 */
172 public String getMavenVersion( int index )
173 {
174 return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.MAVEN_VERSION.suffix,
175 getMavenVersion() );
176 }
177
178 /**
179 * Gets the specification of OS families on which this build job should be run.
180 *
181 * @return The specification of OS families or an empty string if not set.
182 */
183 public String getOsFamily()
184 {
185 return this.properties.getProperty( "invoker.os.family", "" );
186 }
187
188 /**
189 * Gets the specification of OS families on which this build job should be run.
190 *
191 * @param index the selector index
192 * @return The specification of OS families or an empty string if not set.
193 * @since 3.0.0
194 */
195 public String getOsFamily( int index )
196 {
197 return this.properties.getProperty( SELECTOR_PREFIX + index + SelectorProperty.OS_FAMLY.suffix,
198 getOsFamily() );
199 }
200
201
202 /**
203 * Determines whether these invoker properties contain a build definition for the specified invocation index.
204 *
205 * @param index The one-based index of the invocation to check for, must not be negative.
206 * @return <code>true</code> if the invocation with the specified index is defined, <code>false</code> otherwise.
207 */
208 public boolean isInvocationDefined( int index )
209 {
210 for ( InvocationProperty prop : InvocationProperty.values() )
211 {
212 if ( properties.getProperty( prop.toString() + '.' + index ) != null )
213 {
214 return true;
215 }
216 }
217 return false;
218 }
219
220 /**
221 * Determines whether these invoker properties contain a build definition for the specified selector index.
222 *
223 * @param index the index
224 * @return <code>true</code> if the selector with the specified index is defined, <code>false</code> otherwise.
225 * @since 3.0.0
226 */
227 public boolean isSelectorDefined( int index )
228 {
229 for ( SelectorProperty prop : SelectorProperty.values() )
230 {
231 if ( properties.getProperty( SELECTOR_PREFIX + index + prop.suffix ) != null )
232 {
233 return true;
234 }
235 }
236 return false;
237 }
238
239 /**
240 * Configures the specified invocation request from these invoker properties. Settings not present in the invoker
241 * properties will be left unchanged in the invocation request.
242 *
243 * @param request The invocation request to configure, must not be <code>null</code>.
244 * @param index The one-based index of the invocation to configure, must not be negative.
245 */
246 public void configureInvocation( InvocationRequest request, int index )
247 {
248 String project = get( InvocationProperty.PROJECT, index );
249 if ( project != null )
250 {
251 File file = new File( request.getBaseDirectory(), project );
252 if ( file.isFile() )
253 {
254 request.setBaseDirectory( file.getParentFile() );
255 request.setPomFile( file );
256 }
257 else
258 {
259 request.setBaseDirectory( file );
260 request.setPomFile( null );
261 }
262 }
263
264 String goals = get( InvocationProperty.GOALS, index );
265 if ( goals != null )
266 {
267 request.setGoals( new ArrayList<String>( Arrays.asList( StringUtils.split( goals, ", \t\n\r\f" ) ) ) );
268 }
269
270 String profiles = get( InvocationProperty.PROFILES, index );
271 if ( profiles != null )
272 {
273 // CHECKSTYLE_OFF: LineLength
274 request.setProfiles( new ArrayList<String>( Arrays.asList( StringUtils.split( profiles,
275 ", \t\n\r\f" ) ) ) );
276 // CHECKSTYLE_ON: LineLength
277 }
278
279 String mvnOpts = get( InvocationProperty.MAVEN_OPTS, index );
280 if ( mvnOpts != null )
281 {
282 request.setMavenOpts( mvnOpts );
283 }
284
285 String failureBehavior = get( InvocationProperty.FAILURE_BEHAVIOR, index );
286 if ( failureBehavior != null )
287 {
288 ReactorFailureBehavior valueOf =
289 InvocationRequest.ReactorFailureBehavior.valueOfByLongOption( failureBehavior );
290 request.setReactorFailureBehavior( valueOf );
291 }
292
293 String nonRecursive = get( InvocationProperty.NON_RECURSIVE, index );
294 if ( nonRecursive != null )
295 {
296 request.setRecursive( !Boolean.valueOf( nonRecursive ) );
297 }
298
299 String offline = get( InvocationProperty.OFFLINE, index );
300 if ( offline != null )
301 {
302 request.setOffline( Boolean.valueOf( offline ) );
303 }
304
305 String debug = get( InvocationProperty.DEBUG, index );
306 if ( debug != null )
307 {
308 request.setDebug( Boolean.valueOf( debug ) );
309 }
310 }
311
312 /**
313 * Checks whether the specified exit code matches the one expected for the given invocation.
314 *
315 * @param exitCode The exit code of the Maven invocation to check.
316 * @param index The index of the invocation for which to check the exit code, must not be negative.
317 * @return <code>true</code> if the exit code is zero and a success was expected or if the exit code is non-zero and
318 * a failue was expected, <code>false</code> otherwise.
319 */
320 public boolean isExpectedResult( int exitCode, int index )
321 {
322 boolean nonZeroExit = "failure".equalsIgnoreCase( get( "invoker.buildResult", index ) );
323 return ( exitCode != 0 ) == nonZeroExit;
324 }
325
326 /**
327 * Gets the path to the properties file used to set the system properties for the specified invocation.
328 *
329 * @param index The index of the invocation, must not be negative.
330 * @return The path to the properties file or <code>null</code> if not set.
331 */
332 public String getSystemPropertiesFile( int index )
333 {
334 return get( InvocationProperty.SYSTEM_PROPERTIES_FILE, index );
335 }
336
337 /**
338 * Gets the settings file used for the specified invocation.
339 *
340 * @param index The index of the invocation, must not be negative.
341 * @return the value for the settings file or <code>null</code> if not set.
342 */
343 public String getSettingsFile( int index )
344 {
345 return get( InvocationProperty.SETTINGS_FILE, index );
346 }
347
348 /**
349 * Gets a value from the invoker properties. The invoker properties are intended to describe the invocation settings
350 * for multiple builds of the same project. For this reason, the properties are indexed. First, a property named
351 * <code>key.index</code> will be queried. If this property does not exist, the value of the property named
352 * <code>key</code> will finally be returned.
353 *
354 * @param key The (base) key for the invoker property to lookup, must not be <code>null</code>.
355 * @param index The index of the invocation for which to retrieve the value, must not be negative.
356 * @return The value for the requested invoker property or <code>null</code> if not defined.
357 */
358 String get( String key, int index )
359 {
360 if ( index < 0 )
361 {
362 throw new IllegalArgumentException( "invalid invocation index: " + index );
363 }
364
365 String value = properties.getProperty( key + '.' + index );
366 if ( value == null )
367 {
368 value = properties.getProperty( key );
369 }
370 return value;
371 }
372
373 private String get( InvocationProperty prop, int index )
374 {
375 return get( prop.toString(), index );
376 }
377 }