Coverage Report - org.apache.maven.shared.incremental.IncrementalBuildHelper
 
Classes in this File Line Coverage Branch Coverage Complexity
IncrementalBuildHelper
0 %
0/85
0 %
0/30
3,9
 
 1  
 package org.apache.maven.shared.incremental;
 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  
 
 23  
 import org.apache.maven.execution.MavenSession;
 24  
 import org.apache.maven.plugin.MojoExecution;
 25  
 import org.apache.maven.plugin.MojoExecutionException;
 26  
 import org.apache.maven.project.MavenProject;
 27  
 import org.apache.maven.shared.utils.io.DirectoryScanResult;
 28  
 import org.apache.maven.shared.utils.io.DirectoryScanner;
 29  
 import org.apache.maven.shared.utils.io.FileUtils;
 30  
 
 31  
 import java.io.File;
 32  
 import java.io.IOException;
 33  
 import java.util.Set;
 34  
 
 35  
 /**
 36  
  * Various helper methods to support incremental builds
 37  
  *
 38  
  */
 39  
 public class IncrementalBuildHelper
 40  
 {
 41  
     /**
 42  
      * the root directory to store status information about maven executions in.
 43  
      */
 44  
     private static final String MAVEN_STATUS_ROOT = "maven-status";
 45  
     public static final String CREATED_FILES_LST_FILENAME = "createdFiles.lst";
 46  
     private static final String INPUT_FILES_LST_FILENAME = "inputFiles.lst";
 47  
 
 48  
     /**
 49  
      * Needed for storing the status for the incremental build support.
 50  
      */
 51  
     private MojoExecution mojoExecution;
 52  
 
 53  
     /**
 54  
      * Needed for storing the status for the incremental build support.
 55  
      */
 56  
     private MavenProject mavenProject;
 57  
 
 58  
     /**
 59  
      * Used for detecting changes between the Mojo execution.
 60  
      * @see #getDirectoryScanner();
 61  
      */
 62  
     private DirectoryScanner directoryScanner;
 63  
 
 64  
     /**
 65  
      * Once the {@link #beforeRebuildExecution(java.io.File)} gots called
 66  
      * this will contain the list of files in the build directory.
 67  
      */
 68  0
     private String[] filesBeforeAction = new String[0];
 69  
 
 70  
     public IncrementalBuildHelper( MojoExecution mojoExecution, MavenSession mavenSession )
 71  
     {
 72  0
         this( mojoExecution, getMavenProject( mavenSession ) );
 73  0
     }
 74  
 
 75  
     public IncrementalBuildHelper( MojoExecution mojoExecution, MavenProject mavenProject )
 76  0
     {
 77  0
         if ( mavenProject == null )
 78  
         {
 79  0
             throw new IllegalArgumentException( "MavenProject must not be null!" );
 80  
         }
 81  0
         if ( mojoExecution == null )
 82  
         {
 83  0
             throw new IllegalArgumentException( "MojoExecution must not be null!" );
 84  
         }
 85  
 
 86  0
         this.mavenProject = mavenProject;
 87  0
         this.mojoExecution = mojoExecution;
 88  0
     }
 89  
 
 90  
     /**
 91  
      * small helper method to allow for the nullcheck in the ct invocation
 92  
      */
 93  
     private static MavenProject getMavenProject( MavenSession mavenSession )
 94  
     {
 95  0
         if ( mavenSession == null )
 96  
         {
 97  0
             throw new IllegalArgumentException( "MavenSession must not be null!" );
 98  
         }
 99  
 
 100  0
         return mavenSession.getCurrentProject();
 101  
     }
 102  
 
 103  
     /**
 104  
      * Get the existing DirectoryScanner used by this helper,
 105  
      * or create new a DirectoryScanner if none is yet set.
 106  
      * The DirectoryScanner is used for detecting changes in a directory
 107  
      */
 108  
     public DirectoryScanner getDirectoryScanner()
 109  
     {
 110  0
         if ( directoryScanner == null )
 111  
         {
 112  0
             directoryScanner = new DirectoryScanner();
 113  
         }
 114  
 
 115  0
         return directoryScanner;
 116  
     }
 117  
 
 118  
     /**
 119  
      * Set the DirectoryScanner which shall get used by this build helper.
 120  
      * @param directoryScanner
 121  
      */
 122  
     public void setDirectoryScanner( DirectoryScanner directoryScanner )
 123  
     {
 124  0
         this.directoryScanner = directoryScanner;
 125  0
     }
 126  
 
 127  
     /**
 128  
      * We use a specific status directory for each mojo execution to store state
 129  
      * which is needed during the next build invocation run.
 130  
      * @return the directory for storing status information of the current mojo execution.
 131  
      */
 132  
     public File getMojoStatusDirectory() throws MojoExecutionException
 133  
     {
 134  0
         if ( mojoExecution == null )
 135  
         {
 136  0
             throw new MojoExecutionException( "MojoExecution could not get resolved" );
 137  
         }
 138  
 
 139  0
         File buildOutputDirectory = new File( mavenProject.getBuild().getDirectory() );
 140  
 
 141  
         //X TODO the executionId contains -cli and -mojoname
 142  
         //X we should remove those postfixes as it should not make
 143  
         //X any difference whether being run on the cli or via build
 144  0
         String mojoStatusPath = MAVEN_STATUS_ROOT + File.separator
 145  
                                 + mojoExecution.getMojoDescriptor().getPluginDescriptor().getArtifactId() + File.separator
 146  
                                 + mojoExecution.getMojoDescriptor().getGoal() + File.separator
 147  
                                 + mojoExecution.getExecutionId();
 148  
 
 149  0
         File mojoStatusDir = new File( buildOutputDirectory, mojoStatusPath );
 150  
 
 151  0
         if ( !mojoStatusDir.exists() )
 152  
         {
 153  0
             mojoStatusDir.mkdirs();
 154  
         }
 155  
 
 156  0
         return mojoStatusDir;
 157  
     }
 158  
 
 159  
     /**
 160  
      * Detect whether the list of detected files has changed since the last build.
 161  
      * We simply load the list of files for the previous build from a status file
 162  
      * and compare it with the new list. Afterwards we store the new list in the status file.
 163  
      *
 164  
      * @param inputFiles
 165  
      * @return <code>true</code> if the set of inputFiles got changed since the last build.
 166  
      * @throws MojoExecutionException
 167  
      */
 168  
     public boolean inputFileTreeChanged( Set<File> inputFiles ) throws MojoExecutionException
 169  
     {
 170  0
         File mojoConfigBase = getMojoStatusDirectory();
 171  0
         File mojoConfigFile = new File( mojoConfigBase, INPUT_FILES_LST_FILENAME );
 172  
 
 173  0
         String[] oldInputFiles = new String[0];
 174  
 
 175  0
         if ( mojoConfigFile.exists() )
 176  
         {
 177  
             try
 178  
             {
 179  0
                 oldInputFiles = FileUtils.fileReadArray( mojoConfigFile );
 180  
             }
 181  0
             catch( IOException e )
 182  
             {
 183  0
                 throw new MojoExecutionException( "Error reading old mojo status " + mojoConfigFile, e );
 184  0
             }
 185  
         }
 186  
 
 187  0
         String[] inputFileNames = new String[ inputFiles.size() ];
 188  0
         int i = 0;
 189  0
         for ( File inputFile : inputFiles )
 190  
         {
 191  0
             inputFileNames[ i++ ] = inputFile.getAbsolutePath();
 192  
         }
 193  
 
 194  0
         DirectoryScanResult dsr = DirectoryScanner.diffFiles( oldInputFiles, inputFileNames );
 195  
 
 196  
 
 197  
         try
 198  
         {
 199  0
             FileUtils.fileWriteArray( mojoConfigFile, inputFileNames );
 200  
         }
 201  0
         catch( IOException e )
 202  
         {
 203  0
             throw new MojoExecutionException( "Error while storing the mojo status", e );
 204  0
         }
 205  
 
 206  0
         return ( dsr.getFilesAdded().length > 0 || dsr.getFilesRemoved().length > 0 );
 207  
     }
 208  
 
 209  
     /**
 210  
      * Detect whether the list of detected files picked up by the DirectoryScanner
 211  
      * has changed since the last build.
 212  
      * We simply load the list of files for the previous build from a status file
 213  
      * and compare it with the result of the new DirectoryScanner#scan().
 214  
      * Afterwards we store the new list in the status file.
 215  
      *
 216  
      * @param dirScanner
 217  
      * @return <code>true</code> if the set of inputFiles got changed since the last build.
 218  
      * @throws MojoExecutionException
 219  
      */
 220  
     public boolean inputFileTreeChanged( DirectoryScanner dirScanner ) throws MojoExecutionException
 221  
     {
 222  0
         File mojoConfigBase = getMojoStatusDirectory();
 223  0
         File mojoConfigFile = new File( mojoConfigBase, INPUT_FILES_LST_FILENAME );
 224  
 
 225  0
         String[] oldInputFiles = new String[0];
 226  
 
 227  0
         if ( mojoConfigFile.exists() )
 228  
         {
 229  
             try
 230  
             {
 231  0
                 oldInputFiles = FileUtils.fileReadArray( mojoConfigFile );
 232  
             }
 233  0
             catch( IOException e )
 234  
             {
 235  0
                 throw new MojoExecutionException( "Error reading old mojo status " + mojoConfigFile, e );
 236  0
             }
 237  
         }
 238  
 
 239  0
         dirScanner.scan();
 240  
 
 241  
         try
 242  
         {
 243  
             // store away the list of input files
 244  0
             FileUtils.fileWriteArray( mojoConfigFile, dirScanner.getIncludedFiles() );
 245  
         }
 246  0
         catch( IOException e )
 247  
         {
 248  0
             throw new MojoExecutionException( "Error while storing new mojo status" + mojoConfigFile, e );
 249  0
         }
 250  
 
 251  0
         DirectoryScanResult dsr = dirScanner.diffIncludedFiles( oldInputFiles );
 252  
 
 253  0
         return ( dsr.getFilesAdded().length > 0 || dsr.getFilesRemoved().length > 0 );
 254  
     }
 255  
 
 256  
     /**
 257  
      * <p>This method shall get invoked before the actual mojo task gets triggered,
 258  
      * e.g. the actual compile in maven-compiler-plugin.</p>
 259  
      *
 260  
      * <p><b>Attention:</b> This method shall only get invoked if the plugin re-creates <b>all</b> the output.</p>
 261  
      *
 262  
      * <p>It first picks up the list of files created in the previous build and delete them.
 263  
      * This step is necessary to prevent left-overs. After that we take a 'directory snapshot'
 264  
      * (list of all files which exist in the outputDirectory after the clean). </p>
 265  
      *
 266  
      * <p>After the actual mojo task got executed you should invoke the method
 267  
      * {@link #afterRebuildExecution()} to collect the list of files which got changed
 268  
      * by this task.</p>
 269  
      *
 270  
      *
 271  
      * @param outputDirectory
 272  
      * @return all files which got created in the previous build and have been deleted now.
 273  
      * @throws MojoExecutionException
 274  
      */
 275  
     public String[] beforeRebuildExecution( File outputDirectory ) throws MojoExecutionException
 276  
     {
 277  0
         File mojoConfigBase = getMojoStatusDirectory();
 278  0
         File mojoConfigFile = new File( mojoConfigBase, CREATED_FILES_LST_FILENAME );
 279  
 
 280  
         String[] oldFiles;
 281  
 
 282  
         try
 283  
         {
 284  0
             oldFiles = FileUtils.fileReadArray( mojoConfigFile );
 285  0
             for ( String oldFileName : oldFiles )
 286  
             {
 287  0
                 File oldFile = new File( outputDirectory, oldFileName );
 288  0
                 oldFile.delete();
 289  
             }
 290  
         }
 291  0
         catch( IOException e )
 292  
         {
 293  0
             throw new MojoExecutionException( "Error reading old mojo status", e );
 294  0
         }
 295  
 
 296  
         // we remember all files which currently exist in the output directory
 297  0
         DirectoryScanner diffScanner = getDirectoryScanner();
 298  0
         diffScanner.setBasedir( outputDirectory );
 299  0
         if ( outputDirectory.exists() )
 300  
         {
 301  0
             diffScanner.scan();
 302  0
             filesBeforeAction = diffScanner.getIncludedFiles();
 303  
         }
 304  
 
 305  0
         return oldFiles;
 306  
     }
 307  
 
 308  
     /**
 309  
      * <p>This method collects and stores all information about files changed since
 310  
      * the call to {@link #beforeRebuildExecution(java.io.File)}.</p>
 311  
      *
 312  
      * <p><b>Attention:</b> This method shall only get invoked if the plugin re-creates <b>all</b> the output.</p>
 313  
      *
 314  
      * @throws MojoExecutionException
 315  
      */
 316  
     public void afterRebuildExecution() throws MojoExecutionException
 317  
     {
 318  0
         DirectoryScanner diffScanner = getDirectoryScanner();
 319  
         // now scan the same directory again and create a diff
 320  0
         diffScanner.scan();
 321  0
         DirectoryScanResult scanResult = diffScanner.diffIncludedFiles( filesBeforeAction );
 322  
 
 323  0
         File mojoConfigBase = getMojoStatusDirectory();
 324  0
         File mojoConfigFile = new File( mojoConfigBase, CREATED_FILES_LST_FILENAME );
 325  
 
 326  
         try
 327  
         {
 328  0
             FileUtils.fileWriteArray( mojoConfigFile, scanResult.getFilesAdded() );
 329  
         }
 330  0
         catch( IOException e )
 331  
         {
 332  0
             throw new MojoExecutionException( "Error while storing the mojo status", e );
 333  0
         }
 334  
 
 335  0
     }
 336  
 }