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