Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
CommandExecutor |
|
| 1.6486486486486487;1.649 | ||||
CommandExecutor$1 |
|
| 1.6486486486486487;1.649 | ||||
CommandExecutor$ErrorListener |
|
| 1.6486486486486487;1.649 | ||||
CommandExecutor$Factory |
|
| 1.6486486486486487;1.649 | ||||
CommandExecutor$Factory$DefaultCommandExecutor |
|
| 1.6486486486486487;1.649 | ||||
CommandExecutor$Factory$ErrorStreamConsumer |
|
| 1.6486486486486487;1.649 | ||||
CommandExecutor$Factory$StreamConsumerImpl |
|
| 1.6486486486486487;1.649 |
1 | /* | |
2 | * Copyright (C) 2009 Jayway AB | |
3 | * Copyright (C) 2007-2008 JVending Masa | |
4 | * | |
5 | * Licensed under the Apache License, Version 2.0 (the "License"); | |
6 | * you may not use this file except in compliance with the License. | |
7 | * You may obtain a copy of the License at | |
8 | * | |
9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
10 | * | |
11 | * Unless required by applicable law or agreed to in writing, software | |
12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 | * See the License for the specific language governing permissions and | |
15 | * limitations under the License. | |
16 | */ | |
17 | package com.simpligility.maven.plugins.androidndk; | |
18 | ||
19 | import java.io.File; | |
20 | import java.util.ArrayList; | |
21 | import java.util.HashMap; | |
22 | import java.util.List; | |
23 | import java.util.Map; | |
24 | ||
25 | import org.apache.maven.plugin.logging.Log; | |
26 | import org.codehaus.plexus.util.cli.CommandLineException; | |
27 | import org.codehaus.plexus.util.cli.CommandLineUtils; | |
28 | import org.codehaus.plexus.util.cli.Commandline; | |
29 | import org.codehaus.plexus.util.cli.StreamConsumer; | |
30 | import org.codehaus.plexus.util.cli.shell.Shell; | |
31 | ||
32 | /** | |
33 | * | |
34 | */ | |
35 | public interface CommandExecutor | |
36 | { | |
37 | /** | |
38 | * Sets the plexus logger. | |
39 | * | |
40 | * @param logger | |
41 | * the plexus logger | |
42 | */ | |
43 | void setLogger( Log logger ); | |
44 | ||
45 | /** | |
46 | * Executes the command for the specified executable and list of command options. | |
47 | * | |
48 | * @param executable | |
49 | * the name of the executable (csc, xsd, etc). | |
50 | * @param commands | |
51 | * the command options for the compiler/executable | |
52 | * @throws ExecutionException | |
53 | * if compiler or executable writes anything to the standard error stream or if the process returns a | |
54 | * process result != 0. | |
55 | */ | |
56 | void executeCommand( String executable, List< String > commands ) throws ExecutionException; | |
57 | ||
58 | /** | |
59 | * Executes the command for the specified executable and list of command options. | |
60 | * | |
61 | * @param executable | |
62 | * the name of the executable (csc, xsd, etc). | |
63 | * @param commands | |
64 | * the commands options for the compiler/executable | |
65 | * @param failsOnErrorOutput | |
66 | * if true, throws an <code>ExecutionException</code> if there the compiler or executable writes anything | |
67 | * to the error output stream. By default, this value is true | |
68 | * @throws ExecutionException | |
69 | * if compiler or executable writes anything to the standard error stream (provided the | |
70 | * failsOnErrorOutput is not false) or if the process returns a process result != 0. | |
71 | */ | |
72 | void executeCommand( String executable, List< String > commands, boolean failsOnErrorOutput ) | |
73 | throws ExecutionException; | |
74 | ||
75 | /** | |
76 | * Executes the command for the specified executable and list of command options. If the compiler or executable is | |
77 | * not within the environmental path, you should use this method to specify the working directory. Always use this | |
78 | * method for executables located within the local maven repository. | |
79 | * | |
80 | * @param executable | |
81 | * the name of the executable (csc, xsd, etc). | |
82 | * @param commands | |
83 | * the command options for the compiler/executable | |
84 | * @param workingDirectory | |
85 | * the directory where the command will be executed | |
86 | * @throws ExecutionException | |
87 | * if compiler or executable writes anything to the standard error stream (provided the | |
88 | * failsOnErrorOutput is not false) or if the process returns a process result != 0. | |
89 | */ | |
90 | void executeCommand( String executable, List< String > commands, File workingDirectory, boolean failsOnErrorOutput ) | |
91 | throws ExecutionException; | |
92 | ||
93 | /** | |
94 | * Returns the process result of executing the command. Typically a value of 0 means that the process executed | |
95 | * successfully. | |
96 | * | |
97 | * @return the process result of executing the command | |
98 | */ | |
99 | int getResult(); | |
100 | ||
101 | /** | |
102 | * @return the process id for the executed command. | |
103 | */ | |
104 | long getPid(); | |
105 | ||
106 | /** | |
107 | * Returns the standard output from executing the command. | |
108 | * | |
109 | * @return the standard output from executing the command | |
110 | */ | |
111 | String getStandardOut(); | |
112 | ||
113 | /** | |
114 | * Returns the standard error from executing the command. | |
115 | * | |
116 | * @return the standard error from executing the command | |
117 | */ | |
118 | String getStandardError(); | |
119 | ||
120 | /** | |
121 | * Adds an environment variable with the specified name and value to the executor. | |
122 | */ | |
123 | void addEnvironment( String name, String value ); | |
124 | ||
125 | void setErrorListener( ErrorListener errorListener ); | |
126 | ||
127 | void setCustomShell( Shell s ); | |
128 | ||
129 | void setCaptureStdOut( boolean captureStdOut ); | |
130 | void setCaptureStdErr( boolean captureStdErr ); | |
131 | ||
132 | /** | |
133 | * | |
134 | */ | |
135 | public interface ErrorListener | |
136 | { | |
137 | boolean isError( String error ); | |
138 | } | |
139 | ||
140 | /** | |
141 | * Provides factory services for creating a default instance of the command executor. | |
142 | */ | |
143 | class Factory | |
144 | { | |
145 | ||
146 | /** | |
147 | * Constructor | |
148 | */ | |
149 | private Factory() | |
150 | 0 | { |
151 | 0 | } |
152 | ||
153 | 0 | private static final class DefaultCommandExecutor implements CommandExecutor |
154 | { | |
155 | private Map< String, String > environment; | |
156 | /** | |
157 | * Instance of a plugin logger. | |
158 | */ | |
159 | private Log logger; | |
160 | /** | |
161 | * Standard Out | |
162 | */ | |
163 | private StreamConsumer stdOut; | |
164 | /** | |
165 | * Standard Error | |
166 | */ | |
167 | private ErrorStreamConsumer stdErr; | |
168 | /** | |
169 | * Process result | |
170 | */ | |
171 | private int result; | |
172 | /* | |
173 | */ | |
174 | private ErrorListener errorListener; | |
175 | long pid; | |
176 | private Commandline commandline; | |
177 | private Shell customShell; | |
178 | ||
179 | private boolean captureStdOut; | |
180 | private boolean captureStdErr; | |
181 | ||
182 | @Override | |
183 | public void setLogger( Log logger ) | |
184 | { | |
185 | 0 | this.logger = logger; |
186 | 0 | } |
187 | ||
188 | @Override | |
189 | public void executeCommand( String executable, List< String > commands ) throws ExecutionException | |
190 | { | |
191 | 0 | executeCommand( executable, commands, null, true ); |
192 | 0 | } |
193 | ||
194 | @Override | |
195 | public void executeCommand( String executable, List< String > commands, boolean failsOnErrorOutput ) | |
196 | throws ExecutionException | |
197 | { | |
198 | 0 | executeCommand( executable, commands, null, failsOnErrorOutput ); |
199 | 0 | } |
200 | ||
201 | @Override | |
202 | public void executeCommand( String executable, List< String > commands, File workingDirectory, | |
203 | boolean failsOnErrorOutput ) throws ExecutionException | |
204 | { | |
205 | 0 | if ( commands == null ) |
206 | { | |
207 | 0 | commands = new ArrayList< String >(); |
208 | } | |
209 | 0 | stdOut = new StreamConsumerImpl( logger, captureStdOut ); |
210 | 0 | stdErr = new ErrorStreamConsumer( logger, errorListener, captureStdErr ); |
211 | 0 | commandline = new Commandline(); |
212 | 0 | if ( customShell != null ) |
213 | { | |
214 | 0 | commandline.setShell( customShell ); |
215 | } | |
216 | 0 | commandline.setExecutable( executable ); |
217 | ||
218 | // Add the environment variables as needed | |
219 | 0 | if ( environment != null ) |
220 | { | |
221 | 0 | for ( Map.Entry< String, String > entry : environment.entrySet() ) |
222 | { | |
223 | 0 | commandline.addEnvironment( entry.getKey(), entry.getValue() ); |
224 | 0 | } |
225 | } | |
226 | ||
227 | 0 | commandline.addArguments( commands.toArray( new String[ commands.size() ] ) ); |
228 | 0 | if ( workingDirectory != null && workingDirectory.exists() ) |
229 | { | |
230 | 0 | commandline.setWorkingDirectory( workingDirectory.getAbsolutePath() ); |
231 | } | |
232 | try | |
233 | { | |
234 | 0 | logger.debug( "ANDROID-040-000: Executing command: Commandline = " + commandline ); |
235 | 0 | result = CommandLineUtils.executeCommandLine( commandline, stdOut, stdErr ); |
236 | 0 | if ( logger != null ) |
237 | { | |
238 | 0 | logger.debug( "ANDROID-040-000: Executed command: Commandline = " + commandline + ", Result = " |
239 | + result ); | |
240 | } | |
241 | else | |
242 | { | |
243 | 0 | System.out.println( "ANDROID-040-000: Executed command: Commandline = " + commandline |
244 | + ", Result = " + result ); | |
245 | } | |
246 | 0 | if ( failsOnErrorOutput && stdErr.hasError() || result != 0 ) |
247 | { | |
248 | 0 | throw new ExecutionException( "ANDROID-040-001: Could not execute: Command = " |
249 | + commandline.toString() + ", Result = " + result ); | |
250 | } | |
251 | } | |
252 | 0 | catch ( CommandLineException e ) |
253 | { | |
254 | 0 | throw new ExecutionException( "ANDROID-040-002: Could not execute: Command = " |
255 | + commandline.toString() + ", Error message = " + e.getMessage() ); | |
256 | 0 | } |
257 | 0 | setPid( commandline.getPid() ); |
258 | 0 | } |
259 | ||
260 | @Override | |
261 | public int getResult() | |
262 | { | |
263 | 0 | return result; |
264 | } | |
265 | ||
266 | @Override | |
267 | public String getStandardOut() | |
268 | { | |
269 | 0 | if ( ! captureStdOut ) |
270 | { | |
271 | 0 | throw new IllegalStateException( "Unable to provide StdOut since it was not captured" ); |
272 | } | |
273 | 0 | return stdOut.toString(); |
274 | } | |
275 | ||
276 | @Override | |
277 | public String getStandardError() | |
278 | { | |
279 | 0 | if ( ! captureStdErr ) |
280 | { | |
281 | 0 | throw new IllegalStateException( "Unable to provide StdOut since it was not captured" ); |
282 | } | |
283 | 0 | return stdErr.toString(); |
284 | } | |
285 | ||
286 | @Override | |
287 | public void addEnvironment( String name, String value ) | |
288 | { | |
289 | 0 | if ( environment == null ) |
290 | { | |
291 | 0 | environment = new HashMap< String, String >(); |
292 | } | |
293 | 0 | environment.put( name, value ); |
294 | 0 | } |
295 | ||
296 | @Override | |
297 | public void setErrorListener( ErrorListener errorListener ) | |
298 | { | |
299 | 0 | this.errorListener = errorListener; |
300 | 0 | } |
301 | ||
302 | public void setPid( long pid ) | |
303 | { | |
304 | 0 | this.pid = pid; |
305 | 0 | } |
306 | ||
307 | @Override | |
308 | public long getPid() | |
309 | { | |
310 | 0 | return pid; |
311 | } | |
312 | ||
313 | @Override | |
314 | public void setCustomShell( Shell shell ) | |
315 | { | |
316 | 0 | this.customShell = shell; |
317 | 0 | } |
318 | ||
319 | @Override | |
320 | public void setCaptureStdOut( boolean captureStdOut ) | |
321 | { | |
322 | 0 | this.captureStdOut = captureStdOut; |
323 | 0 | } |
324 | ||
325 | @Override | |
326 | public void setCaptureStdErr( boolean captureStdErr ) | |
327 | { | |
328 | 0 | this.captureStdErr = captureStdErr; |
329 | 0 | } |
330 | } | |
331 | ||
332 | /** | |
333 | * StreamConsumer instance that buffers the entire output | |
334 | */ | |
335 | static class StreamConsumerImpl implements StreamConsumer | |
336 | { | |
337 | 0 | private StringBuffer sb = new StringBuffer(); |
338 | private final Log logger; | |
339 | private boolean captureStdOut; | |
340 | ||
341 | StreamConsumerImpl( Log logger, boolean captureStdOut ) | |
342 | 0 | { |
343 | 0 | this.logger = logger; |
344 | 0 | this.captureStdOut = captureStdOut; |
345 | 0 | } |
346 | ||
347 | @Override | |
348 | public void consumeLine( String line ) | |
349 | { | |
350 | 0 | if ( captureStdOut ) |
351 | { | |
352 | 0 | sb.append( line ); |
353 | } | |
354 | 0 | if ( logger != null ) |
355 | { | |
356 | 0 | logger.debug( line ); |
357 | } | |
358 | 0 | } |
359 | ||
360 | /** | |
361 | * Returns the stream | |
362 | * | |
363 | * @return the stream | |
364 | */ | |
365 | @Override | |
366 | public String toString() | |
367 | { | |
368 | 0 | return sb.toString(); |
369 | } | |
370 | } | |
371 | ||
372 | /** | |
373 | * Provides behavior for determining whether the command utility wrote anything to the Standard Error Stream. | |
374 | * NOTE: I am using this to decide whether to fail the NMaven build. If the compiler implementation chooses to | |
375 | * write warnings to the error stream, then the build will fail on warnings!!! | |
376 | */ | |
377 | static class ErrorStreamConsumer implements StreamConsumer | |
378 | { | |
379 | /** Is true if there was anything consumed from the stream, otherwise false */ | |
380 | private boolean error; | |
381 | /** Buffer to store the stream */ | |
382 | 0 | private StringBuffer sbe = new StringBuffer(); |
383 | private final Log logger; | |
384 | private final ErrorListener errorListener; | |
385 | private boolean captureStdErr; | |
386 | ||
387 | ErrorStreamConsumer( Log logger, ErrorListener errorListener, boolean captureStdErr ) | |
388 | 0 | { |
389 | 0 | this.logger = logger; |
390 | 0 | this.errorListener = errorListener; |
391 | 0 | this.captureStdErr = captureStdErr; |
392 | ||
393 | 0 | if ( logger == null ) |
394 | { | |
395 | 0 | System.out.println( "ANDROID-040-003: Error Log not set: Will not output error logs" ); |
396 | } | |
397 | 0 | error = false; |
398 | 0 | } |
399 | ||
400 | @Override | |
401 | public void consumeLine( String line ) | |
402 | { | |
403 | 0 | if ( captureStdErr ) |
404 | { | |
405 | 0 | sbe.append( line ); |
406 | } | |
407 | 0 | if ( logger != null ) |
408 | { | |
409 | 0 | logger.info( line ); |
410 | } | |
411 | 0 | if ( errorListener != null ) |
412 | { | |
413 | 0 | error = errorListener.isError( line ); |
414 | } | |
415 | else | |
416 | { | |
417 | 0 | error = true; |
418 | } | |
419 | 0 | } |
420 | ||
421 | /** | |
422 | * Returns false if the command utility wrote to the Standard Error Stream, otherwise returns true. | |
423 | * | |
424 | * @return false if the command utility wrote to the Standard Error Stream, otherwise returns true. | |
425 | */ | |
426 | public boolean hasError() | |
427 | { | |
428 | 0 | return error; |
429 | } | |
430 | ||
431 | /** | |
432 | * Returns the error stream | |
433 | * | |
434 | * @return error stream | |
435 | */ | |
436 | @Override | |
437 | public String toString() | |
438 | { | |
439 | 0 | return sbe.toString(); |
440 | } | |
441 | } | |
442 | ||
443 | /** | |
444 | * Returns a default instance of the command executor | |
445 | * | |
446 | * @return a default instance of the command executor | |
447 | */ | |
448 | public static CommandExecutor createDefaultCommmandExecutor() | |
449 | { | |
450 | 0 | return new DefaultCommandExecutor(); |
451 | ||
452 | } | |
453 | } | |
454 | } |