From 975c3ac499a374db2b652eeb6fa5e244731c4ac4 Mon Sep 17 00:00:00 2001 From: Marquis Wong Date: Tue, 4 Apr 2023 16:29:28 -0500 Subject: [PATCH] [MCOMPILER-333] Clean generatedSourcesDirectory along with outputDirectory The generatedSourcesDirectory (by default target/generated-sources/annotations) contains source code generated by annotation processors. These generated sources are also outputs of the compiler, and thus should be cleaned along with the class files in the outputDirectory, in order to correctly do incremental compilations. If this isn't done, then javac may not correctly compile the generated code, since it was there before. See https://docs.oracle.com/en/java/javase/17/docs/specs/man/javac.html#annotation-processing See https://github.com/marquiswang/incremental-compile-dagger-test for a reproducing example. --- .../incremental/IncrementalBuildHelper.java | 157 +++++++++++++----- .../IncrementalBuildHelperRequest.java | 18 ++ 2 files changed, 138 insertions(+), 37 deletions(-) diff --git a/src/main/java/org/apache/maven/shared/incremental/IncrementalBuildHelper.java b/src/main/java/org/apache/maven/shared/incremental/IncrementalBuildHelper.java index 78d09af..ddf39f4 100644 --- a/src/main/java/org/apache/maven/shared/incremental/IncrementalBuildHelper.java +++ b/src/main/java/org/apache/maven/shared/incremental/IncrementalBuildHelper.java @@ -31,7 +31,14 @@ import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardOpenOption; +import java.util.ArrayList; +import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * Various helper methods to support incremental builds @@ -46,6 +53,7 @@ public class IncrementalBuildHelper */ private static final String MAVEN_STATUS_ROOT = "maven-status"; public static final String CREATED_FILES_LST_FILENAME = "createdFiles.lst"; + public static final String GENERATED_FILES_LST_FILENAME = "generatedFiles.lst"; private static final String INPUT_FILES_LST_FILENAME = "inputFiles.lst"; private static final String[] EMPTY_ARRAY = new String[0]; @@ -61,10 +69,15 @@ public class IncrementalBuildHelper private MavenProject mavenProject; /** - * Used for detecting changes between the Mojo execution. + * Used for detecting changes in the output directory between the Mojo execution. * @see #getDirectoryScanner(); */ - private DirectoryScanner directoryScanner; + private DirectoryScanner directoryScanner = new DirectoryScanner(); + + /** + * Used for detecting changes in the generated sources directory between the Mojo execution. + */ + private DirectoryScanner generatedSourcesDirectoryScanner = new DirectoryScanner(); /** * Once the {@link #beforeRebuildExecution(org.apache.maven.shared.incremental.IncrementalBuildHelperRequest)} got @@ -72,6 +85,12 @@ public class IncrementalBuildHelper */ private String[] filesBeforeAction = new String[0]; + /** + * Once the {@link #beforeRebuildExecution(org.apache.maven.shared.incremental.IncrementalBuildHelperRequest)} got + * called, this will contain the list of files in the generated sources directory. + */ + private String[] generatedSourcesBeforeAction = new String[0]; + public IncrementalBuildHelper( MojoExecution mojoExecution, MavenSession mavenSession ) { this( mojoExecution, getMavenProject( mavenSession ) ); @@ -112,11 +131,6 @@ private static MavenProject getMavenProject( MavenSession mavenSession ) */ public DirectoryScanner getDirectoryScanner() { - if ( directoryScanner == null ) - { - directoryScanner = new DirectoryScanner(); - } - return directoryScanner; } @@ -280,18 +294,19 @@ public String[] beforeRebuildExecution( IncrementalBuildHelperRequest incrementa throws MojoExecutionException { File mojoConfigBase = getMojoStatusDirectory(); - File mojoConfigFile = new File( mojoConfigBase, CREATED_FILES_LST_FILENAME ); + File mojoCreatedFiles = new File( mojoConfigBase, CREATED_FILES_LST_FILENAME ); + File mojoGeneratedFile = new File( mojoConfigBase, GENERATED_FILES_LST_FILENAME ); - String[] oldFiles; + List deletedFiles = new ArrayList<>(); try { - oldFiles = FileUtils.fileReadArray( mojoConfigFile ); - for ( String oldFileName : oldFiles ) - { - File oldFile = new File( incrementalBuildHelperRequest.getOutputDirectory(), oldFileName ); - oldFile.delete(); - } + deletedFiles.addAll( + deleteFiles( mojoCreatedFiles, + incrementalBuildHelperRequest.getOutputDirectory() ) ); + deletedFiles.addAll( + deleteFiles( mojoGeneratedFile, + incrementalBuildHelperRequest.getGeneratedSourcesDirectory() ) ); } catch ( IOException e ) { @@ -299,15 +314,12 @@ public String[] beforeRebuildExecution( IncrementalBuildHelperRequest incrementa } // we remember all files which currently exist in the output directory - DirectoryScanner diffScanner = getDirectoryScanner(); - diffScanner.setBasedir( incrementalBuildHelperRequest.getOutputDirectory() ); - if ( incrementalBuildHelperRequest.getOutputDirectory().exists() ) - { - diffScanner.scan(); - filesBeforeAction = diffScanner.getIncludedFiles(); - } + filesBeforeAction = scanDirectory( getDirectoryScanner(), + incrementalBuildHelperRequest.getOutputDirectory() ); + generatedSourcesBeforeAction = scanDirectory( generatedSourcesDirectoryScanner, + incrementalBuildHelperRequest.getGeneratedSourcesDirectory() ); - return oldFiles; + return deletedFiles.toArray( new String[0] ); } /** @@ -323,25 +335,23 @@ public String[] beforeRebuildExecution( IncrementalBuildHelperRequest incrementa public void afterRebuildExecution( IncrementalBuildHelperRequest incrementalBuildHelperRequest ) throws MojoExecutionException { - DirectoryScanner diffScanner = getDirectoryScanner(); - // now scan the same directory again and create a diff - diffScanner.scan(); - DirectoryScanResult scanResult = diffScanner.diffIncludedFiles( filesBeforeAction ); - File mojoConfigBase = getMojoStatusDirectory(); - File mojoConfigFile = new File( mojoConfigBase, CREATED_FILES_LST_FILENAME ); - try - { - FileUtils.fileWriteArray( mojoConfigFile, scanResult.getFilesAdded() ); - } - catch ( IOException e ) - { - throw new MojoExecutionException( "Error while storing the mojo status", e ); - } + writeChangedFiles( + getDirectoryScanner(), + filesBeforeAction, + mojoConfigBase, + CREATED_FILES_LST_FILENAME ); + + writeChangedFiles( + generatedSourcesDirectoryScanner, + generatedSourcesBeforeAction, + mojoConfigBase, + GENERATED_FILES_LST_FILENAME ); // in case of clean compile the file is not created so next compile won't see it // we mus create it here + File mojoConfigFile; mojoConfigFile = new File( mojoConfigBase, INPUT_FILES_LST_FILENAME ); if ( !mojoConfigFile.exists() ) { @@ -358,6 +368,79 @@ public void afterRebuildExecution( IncrementalBuildHelperRequest incrementalBuil } + private void writeChangedFiles( + DirectoryScanner directoryScanner, + String[] filesBeforeAction, + File mojoConfigBase, + String createdFilesListFileName ) throws MojoExecutionException + { + if ( directoryScanner.getBasedir() == null ) + { + return; + } + + DirectoryScanResult outputDirectoryScanResult = scanDirectoryDiff( + directoryScanner, filesBeforeAction ); + + try + { + writeChangedFiles( outputDirectoryScanResult, mojoConfigBase, createdFilesListFileName ); + } + catch ( IOException e ) + { + throw new MojoExecutionException( "Error while storing the mojo status", e ); + } + } + + private static void writeChangedFiles( + DirectoryScanResult outputDirectoryScanResult, + File mojoConfigBase, + String createdFilesListFileName ) + throws IOException + { + File createdFiles = new File( mojoConfigBase, createdFilesListFileName ); + String[] filesAdded = outputDirectoryScanResult.getFilesAdded(); + String filesAddedAsString = Stream.of( filesAdded ).collect( Collectors.joining( "\n" ) ); + + Files.write( + createdFiles.toPath(), + filesAddedAsString.getBytes( StandardCharsets.UTF_8 ), + StandardOpenOption.CREATE ); + } + + private static DirectoryScanResult scanDirectoryDiff( + DirectoryScanner directoryScanner, + String[] filesBeforeAction ) + { + // now scan the same directory again and create a diff + directoryScanner.scan(); + DirectoryScanResult outputScanResult = + directoryScanner.diffIncludedFiles( filesBeforeAction ); + return outputScanResult; + } + + private static List deleteFiles( File fileNameIndex, File parent ) throws IOException + { + List oldFiles = Files.readAllLines( fileNameIndex.toPath() ); + for ( String oldFileName : oldFiles ) + { + File oldFile = new File( parent, oldFileName ); + oldFile.delete(); + } + return oldFiles; + } + + private String[] scanDirectory( DirectoryScanner directoryScanner, File directory ) + { + directoryScanner.setBasedir( directory ); + if ( directory != null && directory.exists() ) + { + directoryScanner.scan(); + return directoryScanner.getIncludedFiles(); + } + return new String[0]; + } + private String[] toArrayOfPath( Set files ) { return ( files == null || files.isEmpty() ) diff --git a/src/main/java/org/apache/maven/shared/incremental/IncrementalBuildHelperRequest.java b/src/main/java/org/apache/maven/shared/incremental/IncrementalBuildHelperRequest.java index 07ef1ab..5408d31 100644 --- a/src/main/java/org/apache/maven/shared/incremental/IncrementalBuildHelperRequest.java +++ b/src/main/java/org/apache/maven/shared/incremental/IncrementalBuildHelperRequest.java @@ -33,6 +33,8 @@ public class IncrementalBuildHelperRequest private File outputDirectory; + private File generatedSourcesDirectory; + public IncrementalBuildHelperRequest() { // no op @@ -73,4 +75,20 @@ public IncrementalBuildHelperRequest outputDirectory( File outputDirectory ) this.outputDirectory = outputDirectory; return this; } + + public File getGeneratedSourcesDirectory() + { + return generatedSourcesDirectory; + } + + public void setGeneratedSourcesDirectory( File generatedSourcesDirectory ) + { + this.generatedSourcesDirectory = generatedSourcesDirectory; + } + + public IncrementalBuildHelperRequest generatedSourcesDirectory( File generatedSourcesDirectory ) + { + this.generatedSourcesDirectory = generatedSourcesDirectory; + return this; + } }