You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by st...@apache.org on 2012/08/27 14:56:09 UTC
svn commit: r1377661 - in /maven/plugins/trunk/maven-compiler-plugin: ./
src/main/java/org/apache/maven/plugin/
Author: struberg
Date: Mon Aug 27 12:56:09 2012
New Revision: 1377661
URL: http://svn.apache.org/viewvc?rev=1377661&view=rev
Log:
MCOMPILER-21 improve incremental build support.
* detect dependency files which got changed during the build.
In that case a re-compile is needed for all sources.
* This also fixes the detection of the 'staleSources'. We now actually
re-compile all sources as it's almost impossible to detect cross-refs
properly.
Modified:
maven/plugins/trunk/maven-compiler-plugin/pom.xml
maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/AbstractCompilerMojo.java
maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/CompilerMojo.java
maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/TestCompilerMojo.java
Modified: maven/plugins/trunk/maven-compiler-plugin/pom.xml
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-compiler-plugin/pom.xml?rev=1377661&r1=1377660&r2=1377661&view=diff
==============================================================================
--- maven/plugins/trunk/maven-compiler-plugin/pom.xml (original)
+++ maven/plugins/trunk/maven-compiler-plugin/pom.xml Mon Aug 27 12:56:09 2012
@@ -168,13 +168,13 @@ under the License.
<dependency>
<groupId>org.codehaus.plexus</groupId>
<artifactId>plexus-container-default</artifactId>
- <version>1.0-alpha-9-stable-1</version>
+ <version>1.5.5</version>
</dependency>
<dependency>
- <groupId>org.apache.maven.shared</groupId>
+ <groupId>org.apache.maven.plugin-testing</groupId>
<artifactId>maven-plugin-testing-harness</artifactId>
- <version>1.1</version>
+ <version>2.0-alpha-1</version>
<scope>test</scope>
</dependency>
</dependencies>
Modified: maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/AbstractCompilerMojo.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/AbstractCompilerMojo.java?rev=1377661&r1=1377660&r2=1377661&view=diff
==============================================================================
--- maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/AbstractCompilerMojo.java (original)
+++ maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/AbstractCompilerMojo.java Mon Aug 27 12:56:09 2012
@@ -19,6 +19,7 @@ package org.apache.maven.plugin;
* under the License.
*/
+import org.apache.maven.artifact.Artifact;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.Parameter;
@@ -42,6 +43,8 @@ import org.codehaus.plexus.util.StringUt
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -315,6 +318,13 @@ public abstract class AbstractCompilerMo
@Parameter( defaultValue = "false", property = "maven.compiler.skipMultiThreadWarning" )
private boolean skipMultiThreadWarning;
+ /**
+ * We need this to determine the start timestamp of the build.
+ * @since 2.6
+ */
+ @Component
+ protected MavenSession mavenSession;
+
protected abstract SourceInclusionScanner getSourceInclusionScanner( int staleMillis );
protected abstract SourceInclusionScanner getSourceInclusionScanner( String inputFileEnding );
@@ -550,33 +560,27 @@ public abstract class AbstractCompilerMo
getLog().debug( "CompilerReuseStrategy: " + compilerConfiguration.getCompilerReuseStrategy().getStrategy() );
- // TODO: have an option to always compile (without need to clean)
- Set<File> staleSources;
-
boolean canUpdateTarget;
try
{
- staleSources =
- computeStaleSources( compilerConfiguration, compiler, getSourceInclusionScanner( staleMillis ) );
-
canUpdateTarget = compiler.canUpdateTarget( compilerConfiguration );
- if ( compiler.getCompilerOutputStyle().equals( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
- && !canUpdateTarget )
+ if ( ( compiler.getCompilerOutputStyle().equals( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
+ && !canUpdateTarget )
+ || isDependencyChanged(getArtifacts())
+ || isSourceChanged(compilerConfiguration, compiler) )
{
- getLog().info( "RESCANNING!" );
- // TODO: This second scan for source files is sub-optimal
- String inputFileEnding = compiler.getInputFileEnding( compilerConfiguration );
-
- Set<File> sources = computeStaleSources( compilerConfiguration, compiler,
- getSourceInclusionScanner( inputFileEnding ) );
+ getLog().info( "Recompiling the module!" );
+ Set<File> sources = getCompileSources( compiler, compilerConfiguration );
compilerConfiguration.setSourceFiles( sources );
}
else
{
- compilerConfiguration.setSourceFiles( staleSources );
+ getLog().info( "Nothing to compile - all classes are up to date" );
+
+ return;
}
}
catch ( CompilerException e )
@@ -584,12 +588,6 @@ public abstract class AbstractCompilerMo
throw new MojoExecutionException( "Error while computing stale sources.", e );
}
- if ( staleSources.isEmpty() )
- {
- getLog().info( "Nothing to compile - all classes are up to date" );
-
- return;
- }
// ----------------------------------------------------------------------
// Dump configuration
@@ -719,6 +717,64 @@ public abstract class AbstractCompilerMo
}
/**
+ * @return all source files for the compiler
+ */
+ private Set<File> getCompileSources( Compiler compiler, CompilerConfiguration compilerConfiguration ) throws MojoExecutionException, CompilerException
+ {
+ String inputFileEnding = compiler.getInputFileEnding( compilerConfiguration );
+ SourceInclusionScanner scanner = getSourceInclusionScanner( inputFileEnding );
+
+ SourceMapping mapping = getSourceMapping( compilerConfiguration, compiler );
+
+ scanner.addSourceMapping( mapping );
+
+ Set<File> compileSources = new HashSet<File>();
+
+ for ( String sourceRoot : getCompileSourceRoots() )
+ {
+ File rootFile = new File( sourceRoot );
+
+ if ( !rootFile.isDirectory() )
+ {
+ continue;
+ }
+
+ try
+ {
+ compileSources.addAll( scanner.getIncludedSources( rootFile, null ) );
+ }
+ catch ( InclusionScanException e )
+ {
+ throw new MojoExecutionException(
+ "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e );
+ }
+ }
+
+ return compileSources;
+ }
+
+ /**
+ *
+ * @return <code>true</code> if at least a single source file is newer than it's class file
+ * @param compilerConfiguration
+ * @param compiler
+ */
+ private boolean isSourceChanged( CompilerConfiguration compilerConfiguration, Compiler compiler )
+ throws CompilerException, MojoExecutionException
+ {
+ Set<File> staleSources =
+ computeStaleSources( compilerConfiguration, compiler, getSourceInclusionScanner( staleMillis ) );
+
+ return staleSources != null && staleSources.size() > 0;
+ }
+
+
+ /**
+ * Get all the project artifacts for the current scope
+ */
+ protected abstract Collection<Artifact> getArtifacts();
+
+ /**
* try to get thread count if a Maven 3 build, using reflection as the plugin must not be maven3 api dependant
*
* @return number of thread for this build or 1 if not multi-thread build
@@ -727,7 +783,7 @@ public abstract class AbstractCompilerMo
{
try
{
- Method getRequestMethod = this.session.getClass().getMethod( "getRequest" );
+ Method getRequestMethod = session.getClass().getMethod( "getRequest" );
Object mavenExecutionRequest = getRequestMethod.invoke( this.session );
Method getThreadCountMethod = mavenExecutionRequest.getClass().getMethod( "getThreadCount" );
String threadCount = (String) getThreadCountMethod.invoke( mavenExecutionRequest );
@@ -740,6 +796,26 @@ public abstract class AbstractCompilerMo
return 1;
}
+ protected Date getBuildStartTime()
+ {
+ try
+ {
+ Method getRequestMethod = session.getClass().getMethod( "getRequest" );
+ Object mavenExecutionRequest = getRequestMethod.invoke( session );
+ Method getStartTimeMethod = mavenExecutionRequest.getClass().getMethod( "getStartTime" );
+ Date buildStartTime = (Date) getStartTimeMethod.invoke( mavenExecutionRequest );
+ return buildStartTime;
+ }
+ catch ( Exception e )
+ {
+ getLog().debug( "unable to get start time for the current build: " + e.getMessage() );
+ }
+
+ return new Date();
+ }
+
+
+
private String getMemoryValue( String setting )
{
String value = null;
@@ -788,29 +864,18 @@ public abstract class AbstractCompilerMo
SourceInclusionScanner scanner )
throws MojoExecutionException, CompilerException
{
- CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
+ SourceMapping mapping = getSourceMapping( compilerConfiguration, compiler );
- SourceMapping mapping;
File outputDirectory;
-
- if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE )
- {
- mapping = new SuffixMapping( compiler.getInputFileEnding( compilerConfiguration ),
- compiler.getOutputFileEnding( compilerConfiguration ) );
-
- outputDirectory = getOutputDirectory();
- }
- else if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
+ CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
+ if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
{
- mapping = new SingleTargetSourceMapping( compiler.getInputFileEnding( compilerConfiguration ),
- compiler.getOutputFile( compilerConfiguration ) );
-
outputDirectory = buildDirectory;
}
else
{
- throw new MojoExecutionException( "Unknown compiler output style: '" + outputStyle + "'." );
+ outputDirectory = getOutputDirectory();
}
scanner.addSourceMapping( mapping );
@@ -840,6 +905,30 @@ public abstract class AbstractCompilerMo
return staleSources;
}
+ private SourceMapping getSourceMapping( CompilerConfiguration compilerConfiguration, Compiler compiler )
+ throws CompilerException, MojoExecutionException
+ {
+ CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
+
+ SourceMapping mapping;
+ if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE )
+ {
+ mapping = new SuffixMapping( compiler.getInputFileEnding( compilerConfiguration ),
+ compiler.getOutputFileEnding( compilerConfiguration ) );
+ }
+ else if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
+ {
+ mapping = new SingleTargetSourceMapping( compiler.getInputFileEnding( compilerConfiguration ),
+ compiler.getOutputFile( compilerConfiguration ) );
+
+ }
+ else
+ {
+ throw new MojoExecutionException( "Unknown compiler output style: '" + outputStyle + "'." );
+ }
+ return mapping;
+ }
+
/**
* @todo also in ant plugin. This should be resolved at some point so that it does not need to
* be calculated continuously - or should the plugins accept empty source roots as is?
@@ -860,4 +949,65 @@ public abstract class AbstractCompilerMo
}
return newCompileSourceRootsList;
}
+
+ /**
+ * We just compare the timestamps of all local dependency files (inter-module dependency classpath)
+ * and if we got a file which is >= the buid-started timestamp, then we catched a file which got
+ * changed during this build.
+ *
+ * @return <code>true</code> if at least one single dependency has changed.
+ */
+ protected boolean isDependencyChanged(Collection<Artifact> artifacts)
+ {
+ if ( mavenSession == null )
+ {
+ // we just cannot determine it, so don't do anything beside logging
+ getLog().info( "Cannot determine build start date, skipping incremental build detection." );
+ return false;
+ }
+
+ Date buildStartTime = getBuildStartTime();
+
+ for ( Artifact artifact : artifacts )
+ {
+ // ProjectArtifacts are artifacts which are available in the local project
+ // that's the only ones we are interested in now.
+ File artifactPath = artifact.getFile();
+ if ( artifactPath != null && artifactPath.isDirectory() )
+ {
+ if ( hasNewFile( artifactPath, buildStartTime ) )
+ {
+ return true;
+ }
+ }
+ }
+
+ // obviously there was no new file detected.
+ return false;
+ }
+
+ private boolean hasNewFile( File classPathEntry, Date buildStartTime )
+ {
+ if ( ! classPathEntry.exists() )
+ {
+ return false;
+ }
+
+ if ( classPathEntry.isFile() )
+ {
+ return classPathEntry.lastModified() >= buildStartTime.getTime();
+ }
+
+ File[] children = classPathEntry.listFiles();
+
+ for ( File child : children )
+ {
+ if ( hasNewFile( child, buildStartTime ) )
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
Modified: maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/CompilerMojo.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/CompilerMojo.java?rev=1377661&r1=1377660&r2=1377661&view=diff
==============================================================================
--- maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/CompilerMojo.java (original)
+++ maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/CompilerMojo.java Mon Aug 27 12:56:09 2012
@@ -28,6 +28,7 @@ import org.codehaus.plexus.compiler.util
import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
import java.io.File;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -65,7 +66,7 @@ public class CompilerMojo
private File outputDirectory;
/**
- * Project artifacts.
+ * Projects main artifact.
*
* @todo this is an export variable, really
*/
@@ -73,6 +74,12 @@ public class CompilerMojo
private Artifact projectArtifact;
/**
+ * We need all the projects artifacts to determine whether we shall force a re-compile.
+ */
+ @Parameter( defaultValue = "${project.artifacts}", readonly = true, required = true )
+ private Set<Artifact> projectArtifacts;
+
+ /**
* A list of inclusion filters for the compiler.
*/
@Parameter
@@ -142,13 +149,20 @@ public class CompilerMojo
return scanner;
}
+ @Override
+ protected Collection<Artifact> getArtifacts()
+ {
+ return projectArtifacts;
+ }
+
protected SourceInclusionScanner getSourceInclusionScanner( String inputFileEnding )
{
SourceInclusionScanner scanner = null;
if ( includes.isEmpty() && excludes.isEmpty() )
{
- includes = Collections.singleton( "**/*." + inputFileEnding );
+ String includePattern = "**/*" + ( inputFileEnding.startsWith( "." ) ? "" : "." ) + inputFileEnding;
+ includes = Collections.singleton( includePattern );
scanner = new SimpleSourceInclusionScanner( includes, Collections.EMPTY_SET );
}
else
@@ -188,4 +202,4 @@ public class CompilerMojo
return generatedSourcesDirectory;
}
-}
\ No newline at end of file
+}
Modified: maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/TestCompilerMojo.java
URL: http://svn.apache.org/viewvc/maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/TestCompilerMojo.java?rev=1377661&r1=1377660&r2=1377661&view=diff
==============================================================================
--- maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/TestCompilerMojo.java (original)
+++ maven/plugins/trunk/maven-compiler-plugin/src/main/java/org/apache/maven/plugin/TestCompilerMojo.java Mon Aug 27 12:56:09 2012
@@ -19,6 +19,7 @@ package org.apache.maven.plugin;
* under the License.
*/
+import org.apache.maven.artifact.Artifact;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Parameter;
@@ -27,6 +28,7 @@ import org.codehaus.plexus.compiler.util
import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
import java.io.File;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -139,6 +141,13 @@ public class TestCompilerMojo
private File generatedTestSourcesDirectory;
+ /**
+ * We need all the projects test artifacts to determine whether we shall force a re-compile.
+ */
+ @Parameter( defaultValue = "${project.testArtifacts}", readonly = true, required = true )
+ private List<Artifact> testArtifacts;
+
+
public void execute()
throws MojoExecutionException, CompilationFailureException
{
@@ -193,7 +202,8 @@ public class TestCompilerMojo
if ( testIncludes.isEmpty() && testExcludes.isEmpty() )
{
- testIncludes = Collections.singleton( "**/*." + inputFileEnding );
+ String includePattern = "**/*" + ( inputFileEnding.startsWith( "." ) ? "" : "." ) + inputFileEnding;
+ testIncludes = Collections.singleton( includePattern );
scanner = new SimpleSourceInclusionScanner( testIncludes, Collections.EMPTY_SET );
}
else
@@ -208,6 +218,11 @@ public class TestCompilerMojo
return scanner;
}
+ @Override
+ protected Collection<Artifact> getArtifacts() {
+ return testArtifacts;
+ }
+
protected String getSource()
{
return testSource == null ? source : testSource;