Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
BuildTool |
|
| 2.9;2,9 | ||||
BuildTool$LoggerHandler |
|
| 2.9;2,9 |
1 | package org.apache.maven.shared.test.plugin; | |
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.io.FileWriter; | |
24 | import java.io.IOException; | |
25 | import java.util.List; | |
26 | import java.util.Properties; | |
27 | ||
28 | import org.apache.maven.shared.invoker.DefaultInvocationRequest; | |
29 | import org.apache.maven.shared.invoker.DefaultInvoker; | |
30 | import org.apache.maven.shared.invoker.InvocationOutputHandler; | |
31 | import org.apache.maven.shared.invoker.InvocationRequest; | |
32 | import org.apache.maven.shared.invoker.InvocationResult; | |
33 | import org.apache.maven.shared.invoker.Invoker; | |
34 | import org.apache.maven.shared.invoker.MavenInvocationException; | |
35 | import org.codehaus.plexus.personality.plexus.lifecycle.phase.Disposable; | |
36 | import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable; | |
37 | import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException; | |
38 | import org.codehaus.plexus.util.IOUtil; | |
39 | import org.codehaus.plexus.util.cli.CommandLineUtils; | |
40 | ||
41 | /** | |
42 | * Test-tool used to execute Maven builds in order to test plugin functionality. | |
43 | * | |
44 | * @plexus.component role="org.apache.maven.shared.test.plugin.BuildTool" role-hint="default" | |
45 | * @author jdcasey | |
46 | * @version $Id: BuildTool.java 881035 2009-11-16 23:12:42Z bentmann $ | |
47 | */ | |
48 | 3 | public class BuildTool |
49 | implements Initializable, Disposable | |
50 | { | |
51 | /** Plexus role */ | |
52 | 1 | public static final String ROLE = BuildTool.class.getName(); |
53 | ||
54 | private Invoker mavenInvoker; | |
55 | ||
56 | /** | |
57 | * Build a standard InvocationRequest using the specified test-build POM, command-line properties, | |
58 | * goals, and output logfile. Then, execute Maven using this standard request. Return the result | |
59 | * of the invocation. | |
60 | * | |
61 | * @param pom The test-build POM | |
62 | * @param properties command-line properties to fine-tune the test build, or test parameter | |
63 | * extraction from CLI properties | |
64 | * @param goals The list of goals and/or lifecycle phases to execute during this build | |
65 | * @param buildLogFile The logfile used to capture build output | |
66 | * @return The result of the Maven invocation, including exit value and any execution exceptions | |
67 | * resulting from the Maven invocation. | |
68 | * @throws TestToolsException if any | |
69 | */ | |
70 | public InvocationResult executeMaven( File pom, Properties properties, List goals, File buildLogFile ) | |
71 | throws TestToolsException | |
72 | { | |
73 | 2 | InvocationRequest request = createBasicInvocationRequest( pom, properties, goals, buildLogFile ); |
74 | ||
75 | 2 | return executeMaven( request ); |
76 | } | |
77 | ||
78 | /** | |
79 | * Execute a test build using a customized InvocationRequest. Normally, this request would be | |
80 | * created using the <code>createBasicInvocationRequest</code> method in this class. | |
81 | * | |
82 | * @param request The customized InvocationRequest containing the configuration used to execute | |
83 | * the current test build | |
84 | * @return The result of the Maven invocation, containing exit value, along with any execution | |
85 | * exceptions resulting from the [attempted] Maven invocation. | |
86 | * @throws TestToolsException if any | |
87 | */ | |
88 | public InvocationResult executeMaven( InvocationRequest request ) | |
89 | throws TestToolsException | |
90 | { | |
91 | try | |
92 | { | |
93 | 2 | return mavenInvoker.execute( request ); |
94 | } | |
95 | 0 | catch ( MavenInvocationException e ) |
96 | { | |
97 | 0 | throw new TestToolsException( "Error executing maven.", e ); |
98 | } | |
99 | finally | |
100 | { | |
101 | 2 | closeHandlers( request ); |
102 | } | |
103 | } | |
104 | ||
105 | /** | |
106 | * Detect the location of the local Maven installation, and start up the MavenInvoker using that | |
107 | * path. Detection uses the system property <code>maven.home</code>, and falls back to the shell | |
108 | * environment variable <code>M2_HOME</code>. | |
109 | * | |
110 | * @throws IOException in case the shell environment variables cannot be read | |
111 | */ | |
112 | private void startInvoker() | |
113 | throws IOException | |
114 | { | |
115 | 3 | if ( mavenInvoker == null ) |
116 | { | |
117 | 3 | mavenInvoker = new DefaultInvoker(); |
118 | ||
119 | 3 | if ( System.getProperty( "maven.home" ) == null ) |
120 | { | |
121 | 0 | Properties envars = CommandLineUtils.getSystemEnvVars(); |
122 | ||
123 | 0 | String mavenHome = envars.getProperty( "M2_HOME" ); |
124 | ||
125 | 0 | if ( mavenHome != null ) |
126 | { | |
127 | 0 | mavenInvoker.setMavenHome( new File( mavenHome ) ); |
128 | } | |
129 | } | |
130 | } | |
131 | 3 | } |
132 | ||
133 | /** | |
134 | * If we're logging output to a logfile using standard output handlers, make sure these are | |
135 | * closed. | |
136 | * | |
137 | * @param request | |
138 | */ | |
139 | private void closeHandlers( InvocationRequest request ) | |
140 | { | |
141 | 2 | InvocationOutputHandler outHandler = request.getOutputHandler( null ); |
142 | ||
143 | 2 | if ( outHandler != null && ( outHandler instanceof LoggerHandler ) ) |
144 | { | |
145 | 2 | ( (LoggerHandler) outHandler ).close(); |
146 | } | |
147 | ||
148 | 2 | InvocationOutputHandler errHandler = request.getErrorHandler( null ); |
149 | ||
150 | 2 | if ( errHandler != null && ( outHandler == null || errHandler != outHandler ) |
151 | && ( errHandler instanceof LoggerHandler ) ) | |
152 | { | |
153 | 0 | ( (LoggerHandler) errHandler ).close(); |
154 | } | |
155 | 2 | } |
156 | ||
157 | /** | |
158 | * Construct a standardized InvocationRequest given the test-build POM, a set of CLI properties, | |
159 | * a list of goals to execute, and the location of a log file to which build output should be | |
160 | * directed. The resulting InvocationRequest can then be customized by the test class before | |
161 | * being used to execute a test build. Both standard-out and standard-error will be directed | |
162 | * to the specified log file. | |
163 | * | |
164 | * @param pom The POM for the test build | |
165 | * @param properties The command-line properties for use in this test build | |
166 | * @param goals The goals and/or lifecycle phases to execute during the test build | |
167 | * @param buildLogFile Location to which build output should be logged | |
168 | * @return The standardized InvocationRequest for the test build, ready for any necessary | |
169 | * customizations. | |
170 | */ | |
171 | public InvocationRequest createBasicInvocationRequest( File pom, Properties properties, List goals, | |
172 | File buildLogFile ) | |
173 | { | |
174 | 2 | InvocationRequest request = new DefaultInvocationRequest(); |
175 | ||
176 | 2 | request.setPomFile( pom ); |
177 | ||
178 | 2 | request.setGoals( goals ); |
179 | ||
180 | 2 | request.setProperties( properties ); |
181 | ||
182 | 2 | LoggerHandler handler = new LoggerHandler( buildLogFile ); |
183 | ||
184 | 2 | request.setOutputHandler( handler ); |
185 | 2 | request.setErrorHandler( handler ); |
186 | ||
187 | 2 | return request; |
188 | } | |
189 | ||
190 | 3 | private static final class LoggerHandler |
191 | implements InvocationOutputHandler | |
192 | { | |
193 | 1 | private static final String LS = System.getProperty( "line.separator" ); |
194 | ||
195 | private final File output; | |
196 | ||
197 | private FileWriter writer; | |
198 | ||
199 | LoggerHandler( File logFile ) | |
200 | 2 | { |
201 | 2 | output = logFile; |
202 | 2 | } |
203 | ||
204 | /** {@inheritDoc} */ | |
205 | public void consumeLine( String line ) | |
206 | { | |
207 | 66 | if ( writer == null ) |
208 | { | |
209 | try | |
210 | { | |
211 | 2 | output.getParentFile().mkdirs(); |
212 | 2 | writer = new FileWriter( output ); |
213 | } | |
214 | 0 | catch ( IOException e ) |
215 | { | |
216 | 0 | throw new IllegalStateException( "Failed to open build log: " + output + "\n\nError: " |
217 | + e.getMessage() ); | |
218 | 2 | } |
219 | } | |
220 | ||
221 | try | |
222 | { | |
223 | 66 | writer.write( line + LS ); |
224 | 66 | writer.flush(); |
225 | } | |
226 | 0 | catch ( IOException e ) |
227 | { | |
228 | 0 | throw new IllegalStateException( "Failed to write to build log: " + output + " output:\n\n\'" + line |
229 | + "\'\n\nError: " + e.getMessage() ); | |
230 | 66 | } |
231 | 66 | } |
232 | ||
233 | void close() | |
234 | { | |
235 | 2 | IOUtil.close( writer ); |
236 | 2 | } |
237 | } | |
238 | ||
239 | /** | |
240 | * Initialize this tool once it's been instantiated and composed, in order to start up the | |
241 | * MavenInvoker instance. | |
242 | * | |
243 | * @throws InitializationException if any | |
244 | */ | |
245 | public void initialize() | |
246 | throws InitializationException | |
247 | { | |
248 | try | |
249 | { | |
250 | 3 | startInvoker(); |
251 | } | |
252 | 0 | catch ( IOException e ) |
253 | { | |
254 | 0 | throw new InitializationException( "Error detecting maven home.", e ); |
255 | 3 | } |
256 | 3 | } |
257 | ||
258 | /** | |
259 | * Not currently used; when this API switches to use the Maven Embedder, it will be used to | |
260 | * shutdown the embedder and its associated container, to free up JVM memory. | |
261 | */ | |
262 | public void dispose() | |
263 | { | |
264 | // TODO: When we switch to the embedder, use this to deallocate the MavenEmbedder, along | |
265 | // with the PlexusContainer and ClassRealm that it wraps. | |
266 | 3 | } |
267 | } |