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