Coverage Report - org.apache.maven.shared.test.plugin.BuildTool
 
Classes in this File Line Coverage Branch Coverage Complexity
BuildTool
76%
29/38
38%
7/18
2,9
BuildTool$LoggerHandler
77%
14/18
100%
2/2
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  
 }