1 package org.apache.maven.plugin.compiler;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.execution.MavenSession;
23 import org.apache.maven.plugin.AbstractMojo;
24 import org.apache.maven.plugin.MojoExecution;
25 import org.apache.maven.plugin.MojoExecutionException;
26 import org.apache.maven.plugins.annotations.Component;
27 import org.apache.maven.plugins.annotations.Parameter;
28 import org.apache.maven.shared.incremental.IncrementalBuildHelper;
29 import org.apache.maven.shared.utils.ReaderFactory;
30 import org.apache.maven.shared.utils.StringUtils;
31 import org.apache.maven.toolchain.Toolchain;
32 import org.apache.maven.toolchain.ToolchainManager;
33 import org.codehaus.plexus.compiler.Compiler;
34 import org.codehaus.plexus.compiler.CompilerConfiguration;
35 import org.codehaus.plexus.compiler.CompilerError;
36 import org.codehaus.plexus.compiler.CompilerException;
37 import org.codehaus.plexus.compiler.CompilerMessage;
38 import org.codehaus.plexus.compiler.CompilerNotImplementedException;
39 import org.codehaus.plexus.compiler.CompilerOutputStyle;
40 import org.codehaus.plexus.compiler.CompilerResult;
41 import org.codehaus.plexus.compiler.manager.CompilerManager;
42 import org.codehaus.plexus.compiler.manager.NoSuchCompilerException;
43 import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
44 import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
45 import org.codehaus.plexus.compiler.util.scan.mapping.SingleTargetSourceMapping;
46 import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
47 import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
48
49 import java.io.File;
50 import java.lang.reflect.Method;
51 import java.util.ArrayList;
52 import java.util.Date;
53 import java.util.HashSet;
54 import java.util.LinkedHashMap;
55 import java.util.List;
56 import java.util.Map;
57 import java.util.Set;
58
59
60
61
62
63
64
65
66
67
68
69
70 public abstract class AbstractCompilerMojo
71 extends AbstractMojo
72 {
73
74
75
76
77
78
79
80
81
82 @Parameter ( property = "maven.compiler.failOnError", defaultValue = "true" )
83 private boolean failOnError = true;
84
85
86
87
88 @Parameter ( property = "maven.compiler.debug", defaultValue = "true" )
89 private boolean debug = true;
90
91
92
93
94 @Parameter ( property = "maven.compiler.verbose", defaultValue = "false" )
95 private boolean verbose;
96
97
98
99
100 @Parameter ( property = "maven.compiler.showDeprecation", defaultValue = "false" )
101 private boolean showDeprecation;
102
103
104
105
106 @Parameter ( property = "maven.compiler.optimize", defaultValue = "false" )
107 private boolean optimize;
108
109
110
111
112 @Parameter ( property = "maven.compiler.showWarnings", defaultValue = "false" )
113 private boolean showWarnings;
114
115
116
117
118 @Parameter ( property = "maven.compiler.source", defaultValue = "1.5" )
119 protected String source;
120
121
122
123
124 @Parameter ( property = "maven.compiler.target", defaultValue = "1.5" )
125 protected String target;
126
127
128
129
130
131
132 @Parameter ( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
133 private String encoding;
134
135
136
137
138
139 @Parameter ( property = "lastModGranularityMs", defaultValue = "0" )
140 private int staleMillis;
141
142
143
144
145
146 @Parameter ( property = "maven.compiler.compilerId", defaultValue = "javac" )
147 private String compilerId;
148
149
150
151
152 @Parameter ( property = "maven.compiler.compilerVersion" )
153 private String compilerVersion;
154
155
156
157
158
159 @Parameter ( property = "maven.compiler.fork", defaultValue = "false" )
160 private boolean fork;
161
162
163
164
165
166
167
168 @Parameter ( property = "maven.compiler.meminitial" )
169 private String meminitial;
170
171
172
173
174
175
176
177 @Parameter ( property = "maven.compiler.maxmem" )
178 private String maxmem;
179
180
181
182
183 @Parameter ( property = "maven.compiler.executable" )
184 private String executable;
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199 @Parameter
200 private String proc;
201
202
203
204
205
206
207
208
209
210 @Parameter
211 private String[] annotationProcessors;
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235 @Parameter
236 protected Map<String, String> compilerArguments;
237
238
239
240
241
242
243
244
245
246
247
248 @Parameter
249 protected String compilerArgument;
250
251
252
253
254
255
256
257 @Parameter
258 private String outputFileName;
259
260
261
262
263
264
265
266
267
268 @Parameter ( property = "maven.compiler.debuglevel" )
269 private String debuglevel;
270
271
272
273
274 @Component
275 private ToolchainManager toolchainManager;
276
277
278
279
280
281
282
283
284 @Parameter ( defaultValue = "${basedir}", required = true, readonly = true )
285 private File basedir;
286
287
288
289
290 @Parameter ( defaultValue = "${project.build.directory}", required = true, readonly = true )
291 private File buildDirectory;
292
293
294
295
296 @Component
297 private CompilerManager compilerManager;
298
299
300
301
302 @Component
303 private MavenSession session;
304
305
306
307
308
309
310
311
312
313
314
315
316
317 @Parameter ( defaultValue = "${reuseCreated}", property = "maven.compiler.compilerReuseStrategy" )
318 private String compilerReuseStrategy = "reuseCreated";
319
320
321
322
323 @Parameter ( defaultValue = "false", property = "maven.compiler.skipMultiThreadWarning" )
324 private boolean skipMultiThreadWarning;
325
326
327
328
329
330
331
332 @Parameter ( defaultValue = "false", property = "maven.compiler.forceJavacCompilerUse" )
333 private boolean forceJavacCompilerUse;
334
335
336
337
338 @Parameter ( property = "mojoExecution" )
339 private MojoExecution mojoExecution;
340
341
342
343
344
345
346 @Component
347 protected MavenSession mavenSession;
348
349 protected abstract SourceInclusionScanner getSourceInclusionScanner( int staleMillis );
350
351 protected abstract SourceInclusionScanner getSourceInclusionScanner( String inputFileEnding );
352
353 protected abstract List<String> getClasspathElements();
354
355 protected abstract List<String> getCompileSourceRoots();
356
357 protected abstract File getOutputDirectory();
358
359 protected abstract String getSource();
360
361 protected abstract String getTarget();
362
363 protected abstract String getCompilerArgument();
364
365 protected abstract Map<String, String> getCompilerArguments();
366
367 protected abstract File getGeneratedSourcesDirectory();
368
369 public void execute()
370 throws MojoExecutionException, CompilationFailureException
371 {
372
373
374
375
376
377
378 Compiler compiler;
379
380 getLog().debug( "Using compiler '" + compilerId + "'." );
381
382 try
383 {
384 compiler = compilerManager.getCompiler( compilerId );
385 }
386 catch ( NoSuchCompilerException e )
387 {
388 throw new MojoExecutionException( "No such compiler '" + e.getCompilerId() + "'." );
389 }
390
391
392
393 Toolchain tc = getToolchain();
394 if ( tc != null )
395 {
396 getLog().info( "Toolchain in compiler-plugin: " + tc );
397 if ( executable != null )
398 {
399 getLog().warn( "Toolchains are ignored, 'executable' parameter is set to " + executable );
400 }
401 else
402 {
403 fork = true;
404
405 executable = tc.findTool( compilerId );
406 }
407 }
408
409
410
411
412 List<String> compileSourceRoots = removeEmptyCompileSourceRoots( getCompileSourceRoots() );
413
414 if ( compileSourceRoots.isEmpty() )
415 {
416 getLog().info( "No sources to compile" );
417
418 return;
419 }
420
421 if ( getLog().isDebugEnabled() )
422 {
423 getLog().debug( "Source directories: " + compileSourceRoots.toString().replace( ',', '\n' ) );
424 getLog().debug( "Classpath: " + getClasspathElements().toString().replace( ',', '\n' ) );
425 getLog().debug( "Output directory: " + getOutputDirectory() );
426 }
427
428
429
430
431
432 CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
433
434 compilerConfiguration.setOutputLocation( getOutputDirectory().getAbsolutePath() );
435
436 compilerConfiguration.setClasspathEntries( getClasspathElements() );
437
438 compilerConfiguration.setSourceLocations( compileSourceRoots );
439
440 compilerConfiguration.setOptimize( optimize );
441
442 compilerConfiguration.setDebug( debug );
443
444 if ( debug && StringUtils.isNotEmpty( debuglevel ) )
445 {
446 String[] split = StringUtils.split( debuglevel, "," );
447 for ( int i = 0; i < split.length; i++ )
448 {
449 if ( !( split[i].equalsIgnoreCase( "none" ) || split[i].equalsIgnoreCase( "lines" )
450 || split[i].equalsIgnoreCase( "vars" ) || split[i].equalsIgnoreCase( "source" ) ) )
451 {
452 throw new IllegalArgumentException( "The specified debug level: '" + split[i] + "' is unsupported. "
453 + "Legal values are 'none', 'lines', 'vars', and 'source'." );
454 }
455 }
456 compilerConfiguration.setDebugLevel( debuglevel );
457 }
458
459 compilerConfiguration.setVerbose( verbose );
460
461 compilerConfiguration.setShowWarnings( showWarnings );
462
463 compilerConfiguration.setShowDeprecation( showDeprecation );
464
465 compilerConfiguration.setSourceVersion( getSource() );
466
467 compilerConfiguration.setTargetVersion( getTarget() );
468
469 compilerConfiguration.setProc( proc );
470
471 compilerConfiguration.setGeneratedSourcesDirectory( getGeneratedSourcesDirectory() );
472
473 compilerConfiguration.setAnnotationProcessors( annotationProcessors );
474
475 compilerConfiguration.setSourceEncoding( encoding );
476
477 Map<String, String> effectiveCompilerArguments = getCompilerArguments();
478
479 String effectiveCompilerArgument = getCompilerArgument();
480
481 if ( ( effectiveCompilerArguments != null ) || ( effectiveCompilerArgument != null ) )
482 {
483 LinkedHashMap<String, String> cplrArgsCopy = new LinkedHashMap<String, String>();
484 if ( effectiveCompilerArguments != null )
485 {
486 for ( Map.Entry<String, String> me : effectiveCompilerArguments.entrySet() )
487 {
488 String key = me.getKey();
489 String value = me.getValue();
490 if ( !key.startsWith( "-" ) )
491 {
492 key = "-" + key;
493 }
494
495 if ( key.startsWith( "-A" ) && StringUtils.isNotEmpty( value ) )
496 {
497 cplrArgsCopy.put( key + "=" + value, null );
498 }
499 else
500 {
501 cplrArgsCopy.put( key, value );
502 }
503 }
504 }
505 if ( !StringUtils.isEmpty( effectiveCompilerArgument ) )
506 {
507 cplrArgsCopy.put( effectiveCompilerArgument, null );
508 }
509 compilerConfiguration.setCustomCompilerArguments( cplrArgsCopy );
510 }
511
512 compilerConfiguration.setFork( fork );
513
514 if ( fork )
515 {
516 if ( !StringUtils.isEmpty( meminitial ) )
517 {
518 String value = getMemoryValue( meminitial );
519
520 if ( value != null )
521 {
522 compilerConfiguration.setMeminitial( value );
523 }
524 else
525 {
526 getLog().info( "Invalid value for meminitial '" + meminitial + "'. Ignoring this option." );
527 }
528 }
529
530 if ( !StringUtils.isEmpty( maxmem ) )
531 {
532 String value = getMemoryValue( maxmem );
533
534 if ( value != null )
535 {
536 compilerConfiguration.setMaxmem( value );
537 }
538 else
539 {
540 getLog().info( "Invalid value for maxmem '" + maxmem + "'. Ignoring this option." );
541 }
542 }
543 }
544
545 compilerConfiguration.setExecutable( executable );
546
547 compilerConfiguration.setWorkingDirectory( basedir );
548
549 compilerConfiguration.setCompilerVersion( compilerVersion );
550
551 compilerConfiguration.setBuildDirectory( buildDirectory );
552
553 compilerConfiguration.setOutputFileName( outputFileName );
554
555 if ( CompilerConfiguration.CompilerReuseStrategy.AlwaysNew.getStrategy().equals( this.compilerReuseStrategy ) )
556 {
557 compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.AlwaysNew );
558 }
559 else if ( CompilerConfiguration.CompilerReuseStrategy.ReuseSame.getStrategy().equals(
560 this.compilerReuseStrategy ) )
561 {
562 if ( getRequestThreadCount() > 1 )
563 {
564 if ( !skipMultiThreadWarning )
565 {
566 StringBuilder sb = new StringBuilder(
567 "You are in a multi-thread build and compilerReuseStrategy is set to reuseSame. This can cause issues in some environments (os/jdk)! Consider using reuseCreated strategy." );
568 sb.append( System.getProperty( "line.separator" ) );
569 sb.append(
570 "If your env is fine with reuseSame, you can skip this warning with the configuration field skipMultiThreadWarning or -Dmaven.compiler.skipMultiThreadWarning=true" );
571 getLog().warn( sb.toString() );
572 }
573 }
574 compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.ReuseSame );
575 }
576 else
577 {
578
579 compilerConfiguration.setCompilerReuseStrategy( CompilerConfiguration.CompilerReuseStrategy.ReuseCreated );
580 }
581
582 getLog().debug( "CompilerReuseStrategy: " + compilerConfiguration.getCompilerReuseStrategy().getStrategy() );
583
584 compilerConfiguration.setForceJavacCompilerUse( forceJavacCompilerUse );
585
586 boolean canUpdateTarget;
587
588 IncrementalBuildHelper incrementalBuildHelper = new IncrementalBuildHelper( mojoExecution, mavenSession );
589
590 try
591 {
592 canUpdateTarget = compiler.canUpdateTarget( compilerConfiguration );
593 Set<File> sources = getCompileSources( compiler, compilerConfiguration );
594
595 if ( ( compiler.getCompilerOutputStyle().equals( CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
596 && !canUpdateTarget ) || isDependencyChanged() || isSourceChanged( compilerConfiguration, compiler )
597 || incrementalBuildHelper.inputFileTreeChanged( sources ) )
598 {
599 getLog().info( "Changes detected - recompiling the module!" );
600
601 compilerConfiguration.setSourceFiles( sources );
602 }
603 else
604 {
605 getLog().info( "Nothing to compile - all classes are up to date" );
606
607 return;
608 }
609 }
610 catch ( CompilerException e )
611 {
612 throw new MojoExecutionException( "Error while computing stale sources.", e );
613 }
614
615
616
617
618
619 if ( getLog().isDebugEnabled() )
620 {
621 getLog().debug( "Classpath:" );
622
623 for ( String s : getClasspathElements() )
624 {
625 getLog().debug( " " + s );
626 }
627
628 getLog().debug( "Source roots:" );
629
630 for ( String root : getCompileSourceRoots() )
631 {
632 getLog().debug( " " + root );
633 }
634
635 try
636 {
637 if ( fork )
638 {
639 if ( compilerConfiguration.getExecutable() != null )
640 {
641 getLog().debug( "Excutable: " );
642 getLog().debug( " " + compilerConfiguration.getExecutable() );
643 }
644 }
645
646 String[] cl = compiler.createCommandLine( compilerConfiguration );
647 if ( cl != null && cl.length > 0 )
648 {
649 StringBuilder sb = new StringBuilder();
650 sb.append( cl[0] );
651 for ( int i = 1; i < cl.length; i++ )
652 {
653 sb.append( " " );
654 sb.append( cl[i] );
655 }
656 getLog().debug( "Command line options:" );
657 getLog().debug( sb );
658 }
659 }
660 catch ( CompilerException ce )
661 {
662 getLog().debug( ce );
663 }
664 }
665
666
667
668
669
670 if ( StringUtils.isEmpty( compilerConfiguration.getSourceEncoding() ) )
671 {
672 getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
673 + ", i.e. build is platform dependent!" );
674 }
675
676 CompilerResult compilerResult;
677
678 incrementalBuildHelper.beforeRebuildExecution( getOutputDirectory() );
679
680 try
681 {
682 try
683 {
684 compilerResult = compiler.performCompile( compilerConfiguration );
685 }
686 catch ( CompilerNotImplementedException cnie )
687 {
688 List<CompilerError> messages = compiler.compile( compilerConfiguration );
689 compilerResult = convertToCompilerResult( messages );
690 }
691 }
692 catch ( Exception e )
693 {
694
695 throw new MojoExecutionException( "Fatal error compiling", e );
696 }
697
698
699 incrementalBuildHelper.afterRebuildExecution();
700
701 List<CompilerMessage> warnings = new ArrayList<CompilerMessage>();
702 List<CompilerMessage> errors = new ArrayList<CompilerMessage>();
703 for ( CompilerMessage message : compilerResult.getCompilerMessages() )
704 {
705 if ( message.isError() )
706 {
707 errors.add( message );
708 }
709 else
710 {
711 warnings.add( message );
712 }
713 }
714
715 if ( failOnError && !compilerResult.isSuccess() )
716 {
717 if ( !warnings.isEmpty() )
718 {
719 getLog().info( "-------------------------------------------------------------" );
720 getLog().warn( "COMPILATION WARNING : " );
721 getLog().info( "-------------------------------------------------------------" );
722 for ( CompilerMessage warning : warnings )
723 {
724 getLog().warn( warning.toString() );
725 }
726 getLog().info( warnings.size() + ( ( warnings.size() > 1 ) ? " warnings " : " warning" ) );
727 getLog().info( "-------------------------------------------------------------" );
728 }
729
730 if ( !errors.isEmpty() )
731 {
732 getLog().info( "-------------------------------------------------------------" );
733 getLog().error( "COMPILATION ERROR : " );
734 getLog().info( "-------------------------------------------------------------" );
735 for ( CompilerMessage error : errors )
736 {
737 getLog().error( error.toString() );
738 }
739 getLog().info( errors.size() + ( ( errors.size() > 1 ) ? " errors " : " error" ) );
740 getLog().info( "-------------------------------------------------------------" );
741 }
742
743 if ( !errors.isEmpty() )
744 {
745 throw new CompilationFailureException( errors );
746 }
747 else
748 {
749 throw new CompilationFailureException( warnings );
750 }
751 }
752 else
753 {
754 for ( CompilerMessage message : compilerResult.getCompilerMessages() )
755 {
756 getLog().warn( message.toString() );
757 }
758 }
759 }
760
761 protected CompilerResult convertToCompilerResult( List<CompilerError> compilerErrors )
762 {
763 if ( compilerErrors == null )
764 {
765 return new CompilerResult();
766 }
767 List<CompilerMessage> messages = new ArrayList<CompilerMessage>( compilerErrors.size() );
768 boolean success = true;
769 for ( CompilerError compilerError : compilerErrors )
770 {
771 messages.add(
772 new CompilerMessage( compilerError.getFile(), compilerError.getKind(), compilerError.getStartLine(),
773 compilerError.getStartColumn(), compilerError.getEndLine(),
774 compilerError.getEndColumn(), compilerError.getMessage() ) );
775 if ( compilerError.isError() )
776 {
777 success = false;
778 }
779 }
780
781 return new CompilerResult( success, messages );
782 }
783
784
785
786
787 private Set<File> getCompileSources( Compiler compiler, CompilerConfiguration compilerConfiguration )
788 throws MojoExecutionException, CompilerException
789 {
790 String inputFileEnding = compiler.getInputFileEnding( compilerConfiguration );
791 SourceInclusionScanner scanner = getSourceInclusionScanner( inputFileEnding );
792
793 SourceMapping mapping = getSourceMapping( compilerConfiguration, compiler );
794
795 scanner.addSourceMapping( mapping );
796
797 Set<File> compileSources = new HashSet<File>();
798
799 for ( String sourceRoot : getCompileSourceRoots() )
800 {
801 File rootFile = new File( sourceRoot );
802
803 if ( !rootFile.isDirectory() )
804 {
805 continue;
806 }
807
808 try
809 {
810 compileSources.addAll( scanner.getIncludedSources( rootFile, null ) );
811 }
812 catch ( InclusionScanException e )
813 {
814 throw new MojoExecutionException(
815 "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e );
816 }
817 }
818
819 return compileSources;
820 }
821
822
823
824
825
826
827 private boolean isSourceChanged( CompilerConfiguration compilerConfiguration, Compiler compiler )
828 throws CompilerException, MojoExecutionException
829 {
830 Set<File> staleSources =
831 computeStaleSources( compilerConfiguration, compiler, getSourceInclusionScanner( staleMillis ) );
832
833 return staleSources != null && staleSources.size() > 0;
834 }
835
836
837
838
839
840
841
842 protected int getRequestThreadCount()
843 {
844 try
845 {
846 Method getRequestMethod = session.getClass().getMethod( "getRequest" );
847 Object mavenExecutionRequest = getRequestMethod.invoke( this.session );
848 Method getThreadCountMethod = mavenExecutionRequest.getClass().getMethod( "getThreadCount" );
849 String threadCount = (String) getThreadCountMethod.invoke( mavenExecutionRequest );
850 return Integer.valueOf( threadCount );
851 }
852 catch ( Exception e )
853 {
854 getLog().debug( "unable to get threadCount for the current build: " + e.getMessage() );
855 }
856 return 1;
857 }
858
859 protected Date getBuildStartTime()
860 {
861 try
862 {
863 Method getRequestMethod = session.getClass().getMethod( "getRequest" );
864 Object mavenExecutionRequest = getRequestMethod.invoke( session );
865 Method getStartTimeMethod = mavenExecutionRequest.getClass().getMethod( "getStartTime" );
866 Date buildStartTime = (Date) getStartTimeMethod.invoke( mavenExecutionRequest );
867 return buildStartTime;
868 }
869 catch ( Exception e )
870 {
871 getLog().debug( "unable to get start time for the current build: " + e.getMessage() );
872 }
873
874 return new Date();
875 }
876
877
878 private String getMemoryValue( String setting )
879 {
880 String value = null;
881
882
883 if ( isDigits( setting ) )
884 {
885 value = setting + "m";
886 }
887 else
888 {
889 if ( ( isDigits( setting.substring( 0, setting.length() - 1 ) ) ) && ( setting.toLowerCase().endsWith(
890 "m" ) ) )
891 {
892 value = setting;
893 }
894 }
895 return value;
896 }
897
898
899
900 private Toolchain getToolchain()
901 {
902 Toolchain tc = null;
903 if ( toolchainManager != null )
904 {
905 tc = toolchainManager.getToolchainFromBuildContext( "jdk", session );
906 }
907 return tc;
908 }
909
910 private boolean isDigits( String string )
911 {
912 for ( int i = 0; i < string.length(); i++ )
913 {
914 if ( !Character.isDigit( string.charAt( i ) ) )
915 {
916 return false;
917 }
918 }
919 return true;
920 }
921
922 private Set<File> computeStaleSources( CompilerConfiguration compilerConfiguration, Compiler compiler,
923 SourceInclusionScanner scanner )
924 throws MojoExecutionException, CompilerException
925 {
926 SourceMapping mapping = getSourceMapping( compilerConfiguration, compiler );
927
928 File outputDirectory;
929 CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
930 if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
931 {
932 outputDirectory = buildDirectory;
933 }
934 else
935 {
936 outputDirectory = getOutputDirectory();
937 }
938
939 scanner.addSourceMapping( mapping );
940
941 Set<File> staleSources = new HashSet<File>();
942
943 for ( String sourceRoot : getCompileSourceRoots() )
944 {
945 File rootFile = new File( sourceRoot );
946
947 if ( !rootFile.isDirectory() )
948 {
949 continue;
950 }
951
952 try
953 {
954 staleSources.addAll( scanner.getIncludedSources( rootFile, outputDirectory ) );
955 }
956 catch ( InclusionScanException e )
957 {
958 throw new MojoExecutionException(
959 "Error scanning source root: \'" + sourceRoot + "\' for stale files to recompile.", e );
960 }
961 }
962
963 return staleSources;
964 }
965
966 private SourceMapping getSourceMapping( CompilerConfiguration compilerConfiguration, Compiler compiler )
967 throws CompilerException, MojoExecutionException
968 {
969 CompilerOutputStyle outputStyle = compiler.getCompilerOutputStyle();
970
971 SourceMapping mapping;
972 if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_PER_INPUT_FILE )
973 {
974 mapping = new SuffixMapping( compiler.getInputFileEnding( compilerConfiguration ),
975 compiler.getOutputFileEnding( compilerConfiguration ) );
976 }
977 else if ( outputStyle == CompilerOutputStyle.ONE_OUTPUT_FILE_FOR_ALL_INPUT_FILES )
978 {
979 mapping = new SingleTargetSourceMapping( compiler.getInputFileEnding( compilerConfiguration ),
980 compiler.getOutputFile( compilerConfiguration ) );
981
982 }
983 else
984 {
985 throw new MojoExecutionException( "Unknown compiler output style: '" + outputStyle + "'." );
986 }
987 return mapping;
988 }
989
990
991
992
993
994 private static List<String> removeEmptyCompileSourceRoots( List<String> compileSourceRootsList )
995 {
996 List<String> newCompileSourceRootsList = new ArrayList<String>();
997 if ( compileSourceRootsList != null )
998 {
999
1000 for ( String srcDir : compileSourceRootsList )
1001 {
1002 if ( !newCompileSourceRootsList.contains( srcDir ) && new File( srcDir ).exists() )
1003 {
1004 newCompileSourceRootsList.add( srcDir );
1005 }
1006 }
1007 }
1008 return newCompileSourceRootsList;
1009 }
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019 protected boolean isDependencyChanged()
1020 {
1021 if ( mavenSession == null )
1022 {
1023
1024 getLog().info( "Cannot determine build start date, skipping incremental build detection." );
1025 return false;
1026 }
1027
1028 Date buildStartTime = getBuildStartTime();
1029
1030 for ( String classPathElement : getClasspathElements() )
1031 {
1032
1033
1034 File artifactPath = new File( classPathElement );
1035 if ( artifactPath.isDirectory() )
1036 {
1037 if ( hasNewFile( artifactPath, buildStartTime ) )
1038 {
1039 return true;
1040 }
1041 }
1042 }
1043
1044
1045 return false;
1046 }
1047
1048 private boolean hasNewFile( File classPathEntry, Date buildStartTime )
1049 {
1050 if ( !classPathEntry.exists() )
1051 {
1052 return false;
1053 }
1054
1055 if ( classPathEntry.isFile() )
1056 {
1057 return classPathEntry.lastModified() >= buildStartTime.getTime();
1058 }
1059
1060 File[] children = classPathEntry.listFiles();
1061
1062 for ( File child : children )
1063 {
1064 if ( hasNewFile( child, buildStartTime ) )
1065 {
1066 return true;
1067 }
1068 }
1069
1070 return false;
1071 }
1072 }