Coverage Report - com.simpligility.maven.plugins.androidndk.CommandExecutor
 
Classes in this File Line Coverage Branch Coverage Complexity
CommandExecutor
N/A
N/A
1.649
CommandExecutor$1
N/A
N/A
1.649
CommandExecutor$ErrorListener
N/A
N/A
1.649
CommandExecutor$Factory
0%
0/3
N/A
1.649
CommandExecutor$Factory$DefaultCommandExecutor
0%
0/56
0%
0/26
1.649
CommandExecutor$Factory$ErrorStreamConsumer
0%
0/19
0%
0/8
1.649
CommandExecutor$Factory$StreamConsumerImpl
0%
0/11
0%
0/4
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  
 }