1 package org.apache.maven.plugin.invoker;
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.artifact.Artifact;
23 import org.apache.maven.model.Model;
24 import org.apache.maven.model.Profile;
25 import org.apache.maven.plugin.AbstractMojo;
26 import org.apache.maven.plugin.MojoExecutionException;
27 import org.apache.maven.plugin.MojoFailureException;
28 import org.apache.maven.plugin.invoker.model.BuildJob;
29 import org.apache.maven.plugin.invoker.model.io.xpp3.BuildJobXpp3Writer;
30 import org.apache.maven.plugin.registry.TrackableBase;
31 import org.apache.maven.plugins.annotations.Component;
32 import org.apache.maven.plugins.annotations.Parameter;
33 import org.apache.maven.project.MavenProject;
34 import org.apache.maven.settings.Settings;
35 import org.apache.maven.settings.SettingsUtils;
36 import org.apache.maven.settings.io.xpp3.SettingsXpp3Reader;
37 import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
38 import org.apache.maven.shared.invoker.CommandLineConfigurationException;
39 import org.apache.maven.shared.invoker.DefaultInvocationRequest;
40 import org.apache.maven.shared.invoker.InvocationRequest;
41 import org.apache.maven.shared.invoker.InvocationResult;
42 import org.apache.maven.shared.invoker.Invoker;
43 import org.apache.maven.shared.invoker.MavenCommandLineBuilder;
44 import org.apache.maven.shared.invoker.MavenInvocationException;
45 import org.apache.maven.shared.scriptinterpreter.RunErrorException;
46 import org.apache.maven.shared.scriptinterpreter.RunFailureException;
47 import org.apache.maven.shared.scriptinterpreter.ScriptRunner;
48 import org.codehaus.plexus.interpolation.InterpolationException;
49 import org.codehaus.plexus.interpolation.Interpolator;
50 import org.codehaus.plexus.interpolation.MapBasedValueSource;
51 import org.codehaus.plexus.interpolation.RegexBasedInterpolator;
52 import org.codehaus.plexus.util.DirectoryScanner;
53 import org.codehaus.plexus.util.FileUtils;
54 import org.codehaus.plexus.util.IOUtil;
55 import org.codehaus.plexus.util.InterpolationFilterReader;
56 import org.codehaus.plexus.util.ReaderFactory;
57 import org.codehaus.plexus.util.StringUtils;
58 import org.codehaus.plexus.util.WriterFactory;
59 import org.codehaus.plexus.util.xml.XmlStreamReader;
60 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
61
62 import java.io.BufferedReader;
63 import java.io.File;
64 import java.io.FileInputStream;
65 import java.io.FileOutputStream;
66 import java.io.FileWriter;
67 import java.io.IOException;
68 import java.io.InputStream;
69 import java.io.OutputStreamWriter;
70 import java.io.Reader;
71 import java.io.Writer;
72 import java.text.DecimalFormat;
73 import java.text.DecimalFormatSymbols;
74 import java.util.ArrayList;
75 import java.util.Arrays;
76 import java.util.Collection;
77 import java.util.Collections;
78 import java.util.HashMap;
79 import java.util.LinkedHashMap;
80 import java.util.LinkedHashSet;
81 import java.util.List;
82 import java.util.Locale;
83 import java.util.Map;
84 import java.util.Properties;
85 import java.util.Set;
86 import java.util.StringTokenizer;
87 import java.util.TreeSet;
88 import java.util.concurrent.ExecutorService;
89 import java.util.concurrent.Executors;
90 import java.util.concurrent.TimeUnit;
91
92
93
94
95
96
97
98 public abstract class AbstractInvokerMojo
99 extends AbstractMojo
100 {
101
102
103
104
105
106
107 @Parameter( property = "invoker.skip", defaultValue = "false" )
108 private boolean skipInvocation;
109
110
111
112
113
114
115
116 @Parameter( defaultValue = "false" )
117 protected boolean suppressSummaries;
118
119
120
121
122 @Parameter( property = "invoker.streamLogs", defaultValue = "false" )
123 private boolean streamLogs;
124
125
126
127
128
129
130 @Parameter( property = "invoker.localRepositoryPath", defaultValue = "${settings.localRepository}" )
131 private File localRepositoryPath;
132
133
134
135
136 @Parameter( property = "invoker.projectsDirectory", defaultValue = "${basedir}/src/it/" )
137 private File projectsDirectory;
138
139
140
141
142
143
144
145
146
147 @Parameter( property = "invoker.reportsDirectory", defaultValue = "${project.build.directory}/invoker-reports" )
148 private File reportsDirectory;
149
150
151
152
153
154
155 @Parameter( property = "invoker.disableReports", defaultValue = "false" )
156 private boolean disableReports;
157
158
159
160
161
162
163
164
165 @Parameter
166 private File cloneProjectsTo;
167
168
169
170
171
172
173
174
175
176 @Parameter( defaultValue = "false" )
177 private boolean cloneAllFiles;
178
179
180
181
182
183
184 @Parameter( defaultValue = "false" )
185 private boolean cloneClean;
186
187
188
189
190 @Parameter( property = "invoker.pom" )
191 private File pom;
192
193
194
195
196
197
198
199
200
201
202
203 @Parameter
204 private List<String> pomIncludes = Collections.singletonList( "*/pom.xml" );
205
206
207
208
209
210
211 @Parameter
212 private List<String> pomExcludes = Collections.emptyList();
213
214
215
216
217
218
219
220
221
222
223 @Parameter
224 private List<String> setupIncludes = Collections.singletonList( "setup*/pom.xml" );
225
226
227
228
229 @Parameter
230 private List<String> goals = Collections.singletonList( "package" );
231
232
233
234
235
236
237
238 @Parameter( property = "invoker.goalsFile", defaultValue = "goals.txt" )
239 private String goalsFile;
240
241
242
243 @Component
244 private Invoker invoker;
245
246
247
248
249
250
251
252
253
254
255
256
257
258 @Parameter( property = "invoker.selectorScript", defaultValue = "selector" )
259 private String selectorScript;
260
261
262
263
264
265
266
267
268
269 @Parameter( property = "invoker.preBuildHookScript", defaultValue = "prebuild" )
270 private String preBuildHookScript;
271
272
273
274
275
276
277
278
279 @Parameter( property = "invoker.postBuildHookScript", defaultValue = "postbuild" )
280 private String postBuildHookScript;
281
282
283
284
285 @Parameter( property = "invoker.testPropertiesFile", defaultValue = "test.properties" )
286 private String testPropertiesFile;
287
288
289
290
291
292
293 @Parameter
294 private Properties testProperties;
295
296
297
298
299
300
301 @Parameter
302 private Map<String, String> properties;
303
304
305
306
307 @Parameter( property = "invoker.showErrors", defaultValue = "false" )
308 private boolean showErrors;
309
310
311
312
313 @Parameter( property = "invoker.debug", defaultValue = "false" )
314 private boolean debug;
315
316
317
318
319 @Parameter( property = "invoker.noLog", defaultValue = "false" )
320 private boolean noLog;
321
322
323
324
325
326
327 @Parameter
328 private List<String> profiles;
329
330
331
332
333
334
335
336 @Parameter
337 private Properties interpolationsProperties;
338
339
340
341
342
343
344 @Parameter
345 private Map<String, String> filterProperties;
346
347
348
349
350
351
352 @Component
353 private MavenProject project;
354
355
356
357
358
359
360
361
362
363
364
365 @Parameter( property = "invoker.test" )
366 private String invokerTest;
367
368
369
370
371
372
373
374
375
376 @Parameter( property = "invoker.profilesFile", defaultValue = "profiles.txt" )
377 private String profilesFile;
378
379
380
381
382
383
384
385
386 @Parameter( property = "invoker.settingsFile" )
387 private File settingsFile;
388
389
390
391
392
393
394
395 @Parameter( property = "invoker.mavenOpts" )
396 private String mavenOpts;
397
398
399
400
401
402
403
404 @Parameter( property = "invoker.mavenHome" )
405 private File mavenHome;
406
407
408
409
410
411
412
413 @Parameter( property = "invoker.javaHome" )
414 private File javaHome;
415
416
417
418
419
420
421 @Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
422 private String encoding;
423
424
425
426
427
428
429 @Component
430 private Settings settings;
431
432
433
434
435
436
437
438
439
440
441 @Parameter( property = "invoker.addTestClassPath", defaultValue = "false" )
442 private boolean addTestClassPath;
443
444
445
446
447 @Parameter( defaultValue = "${project.testClasspathElements}", readonly = true )
448 private List<String> testClassPath;
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517 @Parameter( property = "invoker.invokerPropertiesFile", defaultValue = "invoker.properties" )
518 private String invokerPropertiesFile;
519
520
521
522
523
524
525 @Parameter( property = "invoker.showVersion", defaultValue = "false" )
526 private boolean showVersion;
527
528
529
530
531
532
533
534 @Parameter( property = "invoker.parallelThreads", defaultValue = "1" )
535 private int parallelThreads;
536
537
538
539
540 @Parameter( property = "plugin.artifacts", required = true, readonly = true )
541 private List<Artifact> pluginArtifacts;
542
543
544
545
546
547
548
549 @Parameter( property = "invoker.mergeUserSettings", defaultValue = "false" )
550 private boolean mergeUserSettings;
551
552
553
554
555 private ScriptRunner scriptRunner;
556
557
558
559
560
561
562 private String filteredPomPrefix = "interpolated-";
563
564
565
566
567 private final DecimalFormat secFormat = new DecimalFormat( "(0.0 s)", new DecimalFormatSymbols( Locale.ENGLISH ) );
568
569
570
571
572
573
574
575
576
577 public void execute()
578 throws MojoExecutionException, MojoFailureException
579 {
580 if ( skipInvocation )
581 {
582 getLog().info( "Skipping invocation per configuration."
583 + " If this is incorrect, ensure the skipInvocation parameter is not set to true." );
584 return;
585 }
586
587
588 if ( !disableReports && !reportsDirectory.exists() )
589 {
590 reportsDirectory.mkdirs();
591 }
592
593 BuildJob[] buildJobs;
594 if ( pom != null )
595 {
596 try
597 {
598 projectsDirectory = pom.getCanonicalFile().getParentFile();
599 }
600 catch ( IOException e )
601 {
602 throw new MojoExecutionException(
603 "Failed to discover projectsDirectory from pom File parameter." + " Reason: " + e.getMessage(), e );
604 }
605
606 buildJobs = new BuildJob[]{ new BuildJob( pom.getName(), BuildJob.Type.NORMAL ) };
607 }
608 else
609 {
610 try
611 {
612 buildJobs = getBuildJobs();
613 }
614 catch ( final IOException e )
615 {
616 throw new MojoExecutionException(
617 "Error retrieving POM list from includes, excludes, " + "and projects directory. Reason: "
618 + e.getMessage(), e );
619 }
620 }
621
622 if ( ( buildJobs == null ) || ( buildJobs.length < 1 ) )
623 {
624 getLog().info( "No projects were selected for execution." );
625 return;
626 }
627
628 if ( StringUtils.isEmpty( encoding ) )
629 {
630 getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
631 + ", i.e. build is platform dependent!" );
632 }
633
634 final List<String> scriptClassPath;
635 if ( addTestClassPath )
636 {
637 scriptClassPath = new ArrayList<String>( testClassPath );
638 for ( Artifact pluginArtifact : pluginArtifacts )
639 {
640 scriptClassPath.remove( pluginArtifact.getFile().getAbsolutePath() );
641 }
642 }
643 else
644 {
645 scriptClassPath = null;
646 }
647 scriptRunner = new ScriptRunner( getLog() );
648 scriptRunner.setScriptEncoding( encoding );
649 scriptRunner.setGlobalVariable( "localRepositoryPath", localRepositoryPath );
650 scriptRunner.setClassPath( scriptClassPath );
651
652 Collection<String> collectedProjects = new LinkedHashSet<String>();
653 for ( int i = 0; i < buildJobs.length; i++ )
654 {
655 collectProjects( projectsDirectory, buildJobs[i].getProject(), collectedProjects, true );
656 }
657
658 File projectsDir = projectsDirectory;
659
660 if ( cloneProjectsTo != null )
661 {
662 cloneProjects( collectedProjects );
663 projectsDir = cloneProjectsTo;
664 }
665 else
666 {
667 getLog().warn( "Filtering of parent/child POMs is not supported without cloning the projects" );
668 }
669
670 runBuilds( projectsDir, buildJobs );
671
672 processResults( new InvokerSession( buildJobs ) );
673 }
674
675
676
677
678
679
680
681
682 abstract void processResults( InvokerSession invokerSession )
683 throws MojoFailureException;
684
685
686
687
688
689
690
691
692 private Reader newReader( File file )
693 throws IOException
694 {
695 if ( StringUtils.isNotEmpty( encoding ) )
696 {
697 return ReaderFactory.newReader( file, encoding );
698 }
699 else
700 {
701 return ReaderFactory.newPlatformReader( file );
702 }
703 }
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720 private void collectProjects( File projectsDir, String projectPath, Collection<String> projectPaths,
721 boolean included )
722 throws MojoExecutionException
723 {
724 projectPath = projectPath.replace( '\\', '/' );
725 File pomFile = new File( projectsDir, projectPath );
726 if ( pomFile.isDirectory() )
727 {
728 pomFile = new File( pomFile, "pom.xml" );
729 if ( !pomFile.exists() )
730 {
731 if ( included )
732 {
733 projectPaths.add( projectPath );
734 }
735 return;
736 }
737 if ( !projectPath.endsWith( "/" ) )
738 {
739 projectPath += '/';
740 }
741 projectPath += "pom.xml";
742 }
743 else if ( !pomFile.isFile() )
744 {
745 return;
746 }
747 if ( !projectPaths.add( projectPath ) )
748 {
749 return;
750 }
751 getLog().debug( "Collecting parent/child projects of " + projectPath );
752
753 Model model = PomUtils.loadPom( pomFile );
754
755 try
756 {
757 String projectsRoot = projectsDir.getCanonicalPath();
758 String projectDir = pomFile.getParent();
759
760 String parentPath = "../pom.xml";
761 if ( model.getParent() != null && StringUtils.isNotEmpty( model.getParent().getRelativePath() ) )
762 {
763 parentPath = model.getParent().getRelativePath();
764 }
765 String parent = relativizePath( new File( projectDir, parentPath ), projectsRoot );
766 if ( parent != null )
767 {
768 collectProjects( projectsDir, parent, projectPaths, false );
769 }
770
771 Collection<String> modulePaths = new LinkedHashSet<String>();
772
773 modulePaths.addAll( (List<String>) model.getModules() );
774
775 for ( Profile profile : (List<Profile>) model.getProfiles() )
776 {
777 modulePaths.addAll( (List<String>) profile.getModules() );
778 }
779
780 for ( String modulePath : modulePaths )
781 {
782 String module = relativizePath( new File( projectDir, modulePath ), projectsRoot );
783 if ( module != null )
784 {
785 collectProjects( projectsDir, module, projectPaths, false );
786 }
787 }
788 }
789 catch ( IOException e )
790 {
791 throw new MojoExecutionException( "Failed to analyze POM: " + pomFile, e );
792 }
793 }
794
795
796
797
798
799
800
801
802
803
804 private void cloneProjects( Collection<String> projectPaths )
805 throws MojoExecutionException
806 {
807 if ( !cloneProjectsTo.mkdirs() && cloneClean )
808 {
809 try
810 {
811 FileUtils.cleanDirectory( cloneProjectsTo );
812 }
813 catch ( IOException e )
814 {
815 throw new MojoExecutionException(
816 "Could not clean the cloneProjectsTo directory. Reason: " + e.getMessage(), e );
817 }
818 }
819
820
821 Collection<String> dirs = new LinkedHashSet<String>();
822 for ( String projectPath : projectPaths )
823 {
824 if ( !new File( projectsDirectory, projectPath ).isDirectory() )
825 {
826 projectPath = getParentPath( projectPath );
827 }
828 dirs.add( projectPath );
829 }
830
831 boolean filter = false;
832
833
834 try
835 {
836 filter = !cloneProjectsTo.getCanonicalFile().equals( projectsDirectory.getCanonicalFile() );
837
838 List<String> clonedSubpaths = new ArrayList<String>();
839
840 for ( String subpath : dirs )
841 {
842
843 if ( !".".equals( subpath ) && dirs.contains( getParentPath( subpath ) ) )
844 {
845 continue;
846 }
847
848
849 if ( !alreadyCloned( subpath, clonedSubpaths ) )
850 {
851
852 if ( ".".equals( subpath ) )
853 {
854 String cloneSubdir = relativizePath( cloneProjectsTo, projectsDirectory.getCanonicalPath() );
855
856
857 if ( cloneSubdir != null )
858 {
859 File temp = File.createTempFile( "pre-invocation-clone.", "" );
860 temp.delete();
861 temp.mkdirs();
862
863 copyDirectoryStructure( projectsDirectory, temp );
864
865 FileUtils.deleteDirectory( new File( temp, cloneSubdir ) );
866
867 copyDirectoryStructure( temp, cloneProjectsTo );
868 }
869 else
870 {
871 copyDirectoryStructure( projectsDirectory, cloneProjectsTo );
872 }
873 }
874 else
875 {
876 File srcDir = new File( projectsDirectory, subpath );
877 File dstDir = new File( cloneProjectsTo, subpath );
878 copyDirectoryStructure( srcDir, dstDir );
879 }
880
881 clonedSubpaths.add( subpath );
882 }
883 }
884 }
885 catch ( IOException e )
886 {
887 throw new MojoExecutionException(
888 "Failed to clone projects from: " + projectsDirectory + " to: " + cloneProjectsTo + ". Reason: "
889 + e.getMessage(), e );
890 }
891
892
893 if ( filter )
894 {
895 for ( String projectPath : projectPaths )
896 {
897 File pomFile = new File( cloneProjectsTo, projectPath );
898 if ( pomFile.isFile() )
899 {
900 buildInterpolatedFile( pomFile, pomFile );
901 }
902 }
903 filteredPomPrefix = null;
904 }
905 }
906
907
908
909
910
911
912
913 private String getParentPath( String path )
914 {
915 int lastSep = Math.max( path.lastIndexOf( '/' ), path.lastIndexOf( '\\' ) );
916 return ( lastSep < 0 ) ? "." : path.substring( 0, lastSep );
917 }
918
919
920
921
922
923
924
925
926 private void copyDirectoryStructure( File sourceDir, File destDir )
927 throws IOException
928 {
929 DirectoryScanner scanner = new DirectoryScanner();
930 scanner.setBasedir( sourceDir );
931 if ( !cloneAllFiles )
932 {
933 scanner.addDefaultExcludes();
934 }
935 scanner.scan();
936
937
938
939
940 destDir.mkdirs();
941 String[] includedDirs = scanner.getIncludedDirectories();
942 for ( int i = 0; i < includedDirs.length; ++i )
943 {
944 File clonedDir = new File( destDir, includedDirs[i] );
945 clonedDir.mkdirs();
946 }
947
948 String[] includedFiles = scanner.getIncludedFiles();
949 for ( int i = 0; i < includedFiles.length; ++i )
950 {
951 File sourceFile = new File( sourceDir, includedFiles[i] );
952 File destFile = new File( destDir, includedFiles[i] );
953 FileUtils.copyFile( sourceFile, destFile );
954 }
955 }
956
957
958
959
960
961
962
963
964
965
966 static boolean alreadyCloned( String subpath, List<String> clonedSubpaths )
967 {
968 for ( String path : clonedSubpaths )
969 {
970 if ( ".".equals( path ) || subpath.equals( path ) || subpath.startsWith( path + File.separator ) )
971 {
972 return true;
973 }
974 }
975
976 return false;
977 }
978
979
980
981
982
983
984
985
986
987 private void runBuilds( final File projectsDir, BuildJob[] buildJobs )
988 throws MojoExecutionException
989 {
990 if ( !localRepositoryPath.exists() )
991 {
992 localRepositoryPath.mkdirs();
993 }
994
995
996
997
998
999 File interpolatedSettingsFile = null;
1000 if ( settingsFile != null )
1001 {
1002 if ( cloneProjectsTo != null )
1003 {
1004 interpolatedSettingsFile = new File( cloneProjectsTo, "interpolated-" + settingsFile.getName() );
1005 }
1006 else
1007 {
1008 interpolatedSettingsFile =
1009 new File( settingsFile.getParentFile(), "interpolated-" + settingsFile.getName() );
1010 }
1011 buildInterpolatedFile( settingsFile, interpolatedSettingsFile );
1012 }
1013
1014
1015
1016
1017
1018 SettingsXpp3Writer settingsWriter = new SettingsXpp3Writer();
1019
1020 File mergedSettingsFile;
1021 Settings mergedSettings = this.settings;
1022 if ( mergeUserSettings )
1023 {
1024 if ( interpolatedSettingsFile != null )
1025 {
1026
1027 Reader reader = null;
1028 try
1029 {
1030 reader = new XmlStreamReader( interpolatedSettingsFile );
1031 SettingsXpp3Reader settingsReader = new SettingsXpp3Reader();
1032 Settings dominantSettings = settingsReader.read( reader );
1033 Settings recessiveSettings = this.settings;
1034
1035 SettingsUtils.merge( dominantSettings, recessiveSettings, TrackableBase.USER_LEVEL );
1036
1037 mergedSettings = dominantSettings;
1038 getLog().debug( "Merged specified settings file with settings of invoking process" );
1039 }
1040 catch ( XmlPullParserException e )
1041 {
1042 throw new MojoExecutionException( "Could not read specified settings file", e );
1043 }
1044 catch ( IOException e )
1045 {
1046 throw new MojoExecutionException( "Could not read specified settings file", e );
1047 }
1048 finally
1049 {
1050 IOUtil.close( reader );
1051 }
1052 }
1053 }
1054 if ( this.settingsFile != null && !mergeUserSettings )
1055 {
1056 mergedSettingsFile = interpolatedSettingsFile;
1057 }
1058 else
1059 {
1060 try
1061 {
1062 mergedSettingsFile = File.createTempFile( "invoker-settings", ".xml" );
1063
1064 FileWriter fileWriter = null;
1065 try
1066 {
1067 fileWriter = new FileWriter( mergedSettingsFile );
1068 settingsWriter.write( fileWriter, mergedSettings );
1069 }
1070 finally
1071 {
1072 IOUtil.close( fileWriter );
1073 }
1074
1075 if ( getLog().isDebugEnabled() )
1076 {
1077 getLog().debug(
1078 "Created temporary file for invoker settings.xml: " + mergedSettingsFile.getAbsolutePath() );
1079 }
1080
1081 }
1082 catch ( IOException e )
1083 {
1084 throw new MojoExecutionException( "Could not create temporary file for invoker settings.xml", e );
1085 }
1086 }
1087 final File finalSettingsFile = mergedSettingsFile;
1088
1089 try
1090 {
1091 if ( isParallelRun() )
1092 {
1093 getLog().info( "use parallelThreads " + parallelThreads );
1094
1095 ExecutorService executorService = Executors.newFixedThreadPool( parallelThreads );
1096 for ( int i = 0; i < buildJobs.length; i++ )
1097 {
1098 final BuildJob project = buildJobs[i];
1099 executorService.execute( new Runnable()
1100 {
1101
1102 public void run()
1103 {
1104 try
1105 {
1106 runBuild( projectsDir, project, finalSettingsFile );
1107 }
1108 catch ( MojoExecutionException e )
1109 {
1110 throw new RuntimeException( e.getMessage(), e );
1111 }
1112 }
1113 } );
1114 }
1115
1116 try
1117 {
1118 executorService.shutdown();
1119
1120 executorService.awaitTermination( Long.MAX_VALUE, TimeUnit.MILLISECONDS );
1121 }
1122 catch ( InterruptedException e )
1123 {
1124 throw new MojoExecutionException( e.getMessage(), e );
1125 }
1126
1127 }
1128 else
1129 {
1130 for ( int i = 0; i < buildJobs.length; i++ )
1131 {
1132 BuildJob project = buildJobs[i];
1133 runBuild( projectsDir, project, finalSettingsFile );
1134 }
1135 }
1136 }
1137 finally
1138 {
1139 if ( interpolatedSettingsFile != null && cloneProjectsTo == null )
1140 {
1141 interpolatedSettingsFile.delete();
1142 }
1143 if ( mergedSettingsFile != null && mergedSettingsFile.exists() )
1144 {
1145 mergedSettingsFile.delete();
1146 }
1147
1148 }
1149 }
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161 private void runBuild( File projectsDir, BuildJob buildJob, File settingsFile )
1162 throws MojoExecutionException
1163 {
1164 File pomFile = new File( projectsDir, buildJob.getProject() );
1165 File basedir;
1166 if ( pomFile.isDirectory() )
1167 {
1168 basedir = pomFile;
1169 pomFile = new File( basedir, "pom.xml" );
1170 if ( !pomFile.exists() )
1171 {
1172 pomFile = null;
1173 }
1174 else
1175 {
1176 buildJob.setProject( buildJob.getProject() + File.separator + "pom.xml" );
1177 }
1178 }
1179 else
1180 {
1181 basedir = pomFile.getParentFile();
1182 }
1183
1184 getLog().info( "Building: " + buildJob.getProject() );
1185
1186 File interpolatedPomFile = null;
1187 if ( pomFile != null )
1188 {
1189 if ( filteredPomPrefix != null )
1190 {
1191 interpolatedPomFile = new File( basedir, filteredPomPrefix + pomFile.getName() );
1192 buildInterpolatedFile( pomFile, interpolatedPomFile );
1193 }
1194 else
1195 {
1196 interpolatedPomFile = pomFile;
1197 }
1198 }
1199
1200 InvokerProperties invokerProperties = getInvokerProperties( basedir );
1201
1202
1203 buildJob.setName( invokerProperties.getJobName() );
1204 buildJob.setDescription( invokerProperties.getJobDescription() );
1205
1206 try
1207 {
1208 if ( isSelected( invokerProperties ) )
1209 {
1210 long milliseconds = System.currentTimeMillis();
1211 boolean executed;
1212 try
1213 {
1214 executed = runBuild( basedir, interpolatedPomFile, settingsFile, invokerProperties );
1215 }
1216 finally
1217 {
1218 milliseconds = System.currentTimeMillis() - milliseconds;
1219 buildJob.setTime( milliseconds / 1000.0 );
1220 }
1221
1222 if ( executed )
1223 {
1224
1225 buildJob.setResult( BuildJob.Result.SUCCESS );
1226
1227 if ( !suppressSummaries )
1228 {
1229 getLog().info( "..SUCCESS " + formatTime( buildJob.getTime() ) );
1230 }
1231 }
1232 else
1233 {
1234 buildJob.setResult( BuildJob.Result.SKIPPED );
1235
1236 if ( !suppressSummaries )
1237 {
1238 getLog().info( "..SKIPPED " + formatTime( buildJob.getTime() ) );
1239 }
1240 }
1241 }
1242 else
1243 {
1244 buildJob.setResult( BuildJob.Result.SKIPPED );
1245
1246 if ( !suppressSummaries )
1247 {
1248 getLog().info( "..SKIPPED " );
1249 }
1250 }
1251 }
1252 catch ( RunErrorException e )
1253 {
1254 buildJob.setResult( BuildJob.Result.ERROR );
1255 buildJob.setFailureMessage( e.getMessage() );
1256
1257 if ( !suppressSummaries )
1258 {
1259 getLog().info( "..ERROR " + formatTime( buildJob.getTime() ) );
1260 getLog().info( " " + e.getMessage() );
1261 }
1262 }
1263 catch ( RunFailureException e )
1264 {
1265 buildJob.setResult( e.getType() );
1266 buildJob.setFailureMessage( e.getMessage() );
1267
1268 if ( !suppressSummaries )
1269 {
1270 getLog().info( "..FAILED " + formatTime( buildJob.getTime() ) );
1271 getLog().info( " " + e.getMessage() );
1272 }
1273 }
1274 finally
1275 {
1276 if ( interpolatedPomFile != null && StringUtils.isNotEmpty( filteredPomPrefix ) )
1277 {
1278 interpolatedPomFile.delete();
1279 }
1280 writeBuildReport( buildJob );
1281 }
1282 }
1283
1284
1285
1286
1287
1288
1289
1290 private boolean isSelected( InvokerProperties invokerProperties )
1291 {
1292 if ( !SelectorUtils.isMavenVersion( invokerProperties.getMavenVersion() ) )
1293 {
1294 return false;
1295 }
1296
1297 if ( !SelectorUtils.isJreVersion( invokerProperties.getJreVersion() ) )
1298 {
1299 return false;
1300 }
1301
1302 if ( !SelectorUtils.isOsFamily( invokerProperties.getOsFamily() ) )
1303 {
1304 return false;
1305 }
1306
1307 return true;
1308 }
1309
1310
1311
1312
1313
1314
1315
1316
1317 private void writeBuildReport( BuildJob buildJob )
1318 throws MojoExecutionException
1319 {
1320 if ( disableReports )
1321 {
1322 return;
1323 }
1324
1325 String safeFileName = buildJob.getProject().replace( '/', '_' ).replace( '\\', '_' ).replace( ' ', '_' );
1326 if ( safeFileName.endsWith( "_pom.xml" ) )
1327 {
1328 safeFileName = safeFileName.substring( 0, safeFileName.length() - "_pom.xml".length() );
1329 }
1330
1331 File reportFile = new File( reportsDirectory, "BUILD-" + safeFileName + ".xml" );
1332 try
1333 {
1334 FileOutputStream fos = new FileOutputStream( reportFile );
1335 try
1336 {
1337 Writer osw = new OutputStreamWriter( fos, buildJob.getModelEncoding() );
1338 BuildJobXpp3Writer writer = new BuildJobXpp3Writer();
1339 writer.write( osw, buildJob );
1340 osw.close();
1341 }
1342 finally
1343 {
1344 fos.close();
1345 }
1346 }
1347 catch ( IOException e )
1348 {
1349 throw new MojoExecutionException( "Failed to write build report " + reportFile, e );
1350 }
1351 }
1352
1353
1354
1355
1356
1357
1358
1359 private String formatTime( double seconds )
1360 {
1361 return secFormat.format( seconds );
1362 }
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379 private boolean runBuild( File basedir, File pomFile, File settingsFile, InvokerProperties invokerProperties )
1380 throws MojoExecutionException, RunFailureException
1381 {
1382 if ( getLog().isDebugEnabled() && !invokerProperties.getProperties().isEmpty() )
1383 {
1384 Properties props = invokerProperties.getProperties();
1385 getLog().debug( "Using invoker properties:" );
1386 for ( String key : new TreeSet<String>( (Set) props.keySet() ) )
1387 {
1388 String value = props.getProperty( key );
1389 getLog().debug( " " + key + " = " + value );
1390 }
1391 }
1392
1393 List<String> goals = getGoals( basedir );
1394
1395 List<String> profiles = getProfiles( basedir );
1396
1397 Map<String, Object> context = new LinkedHashMap<String, Object>();
1398
1399 FileLogger logger = setupLogger( basedir );
1400 try
1401 {
1402 try
1403 {
1404 scriptRunner.run( "selector script", basedir, selectorScript, context, logger, BuildJob.Result.SKIPPED,
1405 false );
1406 }
1407 catch ( RunErrorException e )
1408 {
1409 throw e;
1410 }
1411 catch ( RunFailureException e )
1412 {
1413 return false;
1414 }
1415
1416 scriptRunner.run( "pre-build script", basedir, preBuildHookScript, context, logger,
1417 BuildJob.Result.FAILURE_PRE_HOOK, false );
1418
1419 final InvocationRequest request = new DefaultInvocationRequest();
1420
1421 request.setLocalRepositoryDirectory( localRepositoryPath );
1422
1423 request.setInteractive( false );
1424
1425 request.setShowErrors( showErrors );
1426
1427 request.setDebug( debug );
1428
1429 request.setShowVersion( showVersion );
1430
1431 if ( logger != null )
1432 {
1433 request.setErrorHandler( logger );
1434
1435 request.setOutputHandler( logger );
1436 }
1437
1438 if ( mavenHome != null )
1439 {
1440 invoker.setMavenHome( mavenHome );
1441 request.addShellEnvironment( "M2_HOME", mavenHome.getAbsolutePath() );
1442 }
1443
1444 if ( javaHome != null )
1445 {
1446 request.setJavaHome( javaHome );
1447 }
1448
1449 for ( int invocationIndex = 1; ; invocationIndex++ )
1450 {
1451 if ( invocationIndex > 1 && !invokerProperties.isInvocationDefined( invocationIndex ) )
1452 {
1453 break;
1454 }
1455
1456 request.setBaseDirectory( basedir );
1457
1458 request.setPomFile( pomFile );
1459
1460 request.setGoals( goals );
1461
1462 request.setProfiles( profiles );
1463
1464 request.setMavenOpts( mavenOpts );
1465
1466 request.setOffline( false );
1467
1468 request.setUserSettingsFile( settingsFile );
1469
1470 Properties systemProperties =
1471 getSystemProperties( basedir, invokerProperties.getSystemPropertiesFile( invocationIndex ) );
1472 request.setProperties( systemProperties );
1473
1474 invokerProperties.configureInvocation( request, invocationIndex );
1475
1476 if ( getLog().isDebugEnabled() )
1477 {
1478 try
1479 {
1480 getLog().debug( "Using MAVEN_OPTS: " + request.getMavenOpts() );
1481 getLog().debug( "Executing: " + new MavenCommandLineBuilder().build( request ) );
1482 }
1483 catch ( CommandLineConfigurationException e )
1484 {
1485 getLog().debug( "Failed to display command line: " + e.getMessage() );
1486 }
1487 }
1488
1489 InvocationResult result;
1490
1491 try
1492 {
1493 result = invoker.execute( request );
1494 }
1495 catch ( final MavenInvocationException e )
1496 {
1497 getLog().debug( "Error invoking Maven: " + e.getMessage(), e );
1498 throw new RunFailureException( "Maven invocation failed. " + e.getMessage(),
1499 BuildJob.Result.FAILURE_BUILD );
1500 }
1501
1502 verify( result, invocationIndex, invokerProperties, logger );
1503 }
1504
1505 scriptRunner.run( "post-build script", basedir, postBuildHookScript, context, logger,
1506 BuildJob.Result.FAILURE_POST_HOOK, true );
1507 }
1508 catch ( IOException e )
1509 {
1510 throw new MojoExecutionException( e.getMessage(), e );
1511 }
1512 finally
1513 {
1514 if ( logger != null )
1515 {
1516 logger.close();
1517 }
1518 }
1519 return true;
1520 }
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530 private FileLogger setupLogger( File basedir )
1531 throws MojoExecutionException
1532 {
1533 FileLogger logger = null;
1534
1535 if ( !noLog )
1536 {
1537 File outputLog = new File( basedir, "build.log" );
1538 try
1539 {
1540 if ( streamLogs )
1541 {
1542 logger = new FileLogger( outputLog, getLog() );
1543 }
1544 else
1545 {
1546 logger = new FileLogger( outputLog );
1547 }
1548
1549 getLog().debug( "build log initialized in: " + outputLog );
1550 }
1551 catch ( IOException e )
1552 {
1553 throw new MojoExecutionException( "Error initializing build logfile in: " + outputLog, e );
1554 }
1555 }
1556
1557 return logger;
1558 }
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570 private Properties getSystemProperties( final File basedir, final String filename )
1571 throws MojoExecutionException
1572 {
1573 Properties collectedTestProperties = new Properties();
1574
1575 if ( testProperties != null )
1576 {
1577 collectedTestProperties.putAll( testProperties );
1578 }
1579
1580 if ( properties != null )
1581 {
1582 collectedTestProperties.putAll( properties );
1583 }
1584
1585 File propertiesFile = null;
1586 if ( filename != null )
1587 {
1588 propertiesFile = new File( basedir, filename );
1589 }
1590 else if ( testPropertiesFile != null )
1591 {
1592 propertiesFile = new File( basedir, testPropertiesFile );
1593 }
1594
1595 if ( propertiesFile != null && propertiesFile.isFile() )
1596 {
1597 InputStream fin = null;
1598 try
1599 {
1600 fin = new FileInputStream( propertiesFile );
1601
1602 Properties loadedProperties = new Properties();
1603 loadedProperties.load( fin );
1604 collectedTestProperties.putAll( loadedProperties );
1605 }
1606 catch ( IOException e )
1607 {
1608 throw new MojoExecutionException( "Error reading system properties from " + propertiesFile );
1609 }
1610 finally
1611 {
1612 IOUtil.close( fin );
1613 }
1614 }
1615
1616 return collectedTestProperties;
1617 }
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629 private void verify( InvocationResult result, int invocationIndex, InvokerProperties invokerProperties,
1630 FileLogger logger )
1631 throws RunFailureException
1632 {
1633 if ( result.getExecutionException() != null )
1634 {
1635 throw new RunFailureException(
1636 "The Maven invocation failed. " + result.getExecutionException().getMessage(), BuildJob.Result.ERROR );
1637 }
1638 else if ( !invokerProperties.isExpectedResult( result.getExitCode(), invocationIndex ) )
1639 {
1640 StringBuffer buffer = new StringBuffer( 256 );
1641 buffer.append( "The build exited with code " ).append( result.getExitCode() ).append( ". " );
1642 if ( logger != null )
1643 {
1644 buffer.append( "See " );
1645 buffer.append( logger.getOutputFile().getAbsolutePath() );
1646 buffer.append( " for details." );
1647 }
1648 else
1649 {
1650 buffer.append( "See console output for details." );
1651 }
1652 throw new RunFailureException( buffer.toString(), BuildJob.Result.FAILURE_BUILD );
1653 }
1654 }
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664 List<String> getGoals( final File basedir )
1665 throws MojoExecutionException
1666 {
1667 try
1668 {
1669 return getTokens( basedir, goalsFile, goals );
1670 }
1671 catch ( IOException e )
1672 {
1673 throw new MojoExecutionException( "error reading goals", e );
1674 }
1675 }
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685 List<String> getProfiles( File basedir )
1686 throws MojoExecutionException
1687 {
1688 try
1689 {
1690 return getTokens( basedir, profilesFile, profiles );
1691 }
1692 catch ( IOException e )
1693 {
1694 throw new MojoExecutionException( "error reading profiles", e );
1695 }
1696 }
1697
1698
1699
1700
1701
1702
1703
1704 BuildJob[] getBuildJobs()
1705 throws IOException
1706 {
1707 BuildJob[] buildJobs;
1708
1709 if ( ( pom != null ) && pom.exists() )
1710 {
1711 buildJobs = new BuildJob[]{ new BuildJob( pom.getAbsolutePath(), BuildJob.Type.NORMAL ) };
1712 }
1713 else if ( invokerTest != null )
1714 {
1715 String[] testRegexes = StringUtils.split( invokerTest, "," );
1716 List<String> includes = new ArrayList<String>( testRegexes.length );
1717
1718 for ( int i = 0, size = testRegexes.length; i < size; i++ )
1719 {
1720
1721 includes.add( testRegexes[i] );
1722 }
1723
1724
1725
1726 buildJobs = scanProjectsDirectory( includes, null, BuildJob.Type.DIRECT );
1727 }
1728 else
1729 {
1730 List<String> excludes =
1731 ( pomExcludes != null ) ? new ArrayList<String>( pomExcludes ) : new ArrayList<String>();
1732 if ( this.settingsFile != null )
1733 {
1734 String exclude = relativizePath( this.settingsFile, projectsDirectory.getCanonicalPath() );
1735 if ( exclude != null )
1736 {
1737 excludes.add( exclude.replace( '\\', '/' ) );
1738 getLog().debug( "Automatically excluded " + exclude + " from project scanning" );
1739 }
1740 }
1741
1742 BuildJob[] setupPoms = scanProjectsDirectory( setupIncludes, excludes, BuildJob.Type.SETUP );
1743 getLog().debug( "Setup projects: " + Arrays.asList( setupPoms ) );
1744
1745 BuildJob[] normalPoms = scanProjectsDirectory( pomIncludes, excludes, BuildJob.Type.NORMAL );
1746
1747 Map<String, BuildJob> uniquePoms = new LinkedHashMap<String, BuildJob>();
1748 for ( int i = 0; i < setupPoms.length; i++ )
1749 {
1750 uniquePoms.put( setupPoms[i].getProject(), setupPoms[i] );
1751 }
1752 for ( int i = 0; i < normalPoms.length; i++ )
1753 {
1754 if ( !uniquePoms.containsKey( normalPoms[i].getProject() ) )
1755 {
1756 uniquePoms.put( normalPoms[i].getProject(), normalPoms[i] );
1757 }
1758 }
1759
1760 buildJobs = uniquePoms.values().toArray( new BuildJob[uniquePoms.size()] );
1761 }
1762
1763 relativizeProjectPaths( buildJobs );
1764
1765 return buildJobs;
1766 }
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780 private BuildJob[] scanProjectsDirectory( List<String> includes, List<String> excludes, String type )
1781 throws IOException
1782 {
1783 if ( !projectsDirectory.isDirectory() )
1784 {
1785 return new BuildJob[0];
1786 }
1787
1788 DirectoryScanner scanner = new DirectoryScanner();
1789 scanner.setBasedir( projectsDirectory.getCanonicalFile() );
1790 scanner.setFollowSymlinks( false );
1791 if ( includes != null )
1792 {
1793 scanner.setIncludes( includes.toArray( new String[includes.size()] ) );
1794 }
1795 if ( excludes != null )
1796 {
1797 scanner.setExcludes( excludes.toArray( new String[excludes.size()] ) );
1798 }
1799 scanner.addDefaultExcludes();
1800 scanner.scan();
1801
1802 Map<String, BuildJob> matches = new LinkedHashMap<String, BuildJob>();
1803
1804 String[] includedFiles = scanner.getIncludedFiles();
1805 for ( int i = 0; i < includedFiles.length; i++ )
1806 {
1807 matches.put( includedFiles[i], new BuildJob( includedFiles[i], type ) );
1808 }
1809
1810 String[] includedDirs = scanner.getIncludedDirectories();
1811 for ( int i = 0; i < includedDirs.length; i++ )
1812 {
1813 String includedFile = includedDirs[i] + File.separatorChar + "pom.xml";
1814 if ( new File( scanner.getBasedir(), includedFile ).isFile() )
1815 {
1816 matches.put( includedFile, new BuildJob( includedFile, type ) );
1817 }
1818 else
1819 {
1820 matches.put( includedDirs[i], new BuildJob( includedDirs[i], type ) );
1821 }
1822 }
1823
1824 return matches.values().toArray( new BuildJob[matches.size()] );
1825 }
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836 private void relativizeProjectPaths( BuildJob[] buildJobs )
1837 throws IOException
1838 {
1839 String projectsDirPath = projectsDirectory.getCanonicalPath();
1840
1841 for ( int i = 0; i < buildJobs.length; i++ )
1842 {
1843 String projectPath = buildJobs[i].getProject();
1844
1845 File file = new File( projectPath );
1846
1847 if ( !file.isAbsolute() )
1848 {
1849 file = new File( projectsDirectory, projectPath );
1850 }
1851
1852 String relativizedPath = relativizePath( file, projectsDirPath );
1853
1854 if ( relativizedPath == null )
1855 {
1856 relativizedPath = projectPath;
1857 }
1858
1859 buildJobs[i].setProject( relativizedPath );
1860 }
1861 }
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873 private String relativizePath( File path, String basedir )
1874 throws IOException
1875 {
1876 String relativizedPath = path.getCanonicalPath();
1877
1878 if ( relativizedPath.startsWith( basedir ) )
1879 {
1880 relativizedPath = relativizedPath.substring( basedir.length() );
1881 if ( relativizedPath.startsWith( File.separator ) )
1882 {
1883 relativizedPath = relativizedPath.substring( File.separator.length() );
1884 }
1885
1886 return relativizedPath;
1887 }
1888 else
1889 {
1890 return null;
1891 }
1892 }
1893
1894
1895
1896
1897
1898
1899 private Map<String, Object> getInterpolationValueSource()
1900 {
1901 Map<String, Object> props = new HashMap<String, Object>();
1902 if ( interpolationsProperties != null )
1903 {
1904 props.putAll( (Map) interpolationsProperties );
1905 }
1906 if ( filterProperties != null )
1907 {
1908 props.putAll( filterProperties );
1909 }
1910 props.put( "basedir", this.project.getBasedir().getAbsolutePath() );
1911 props.put( "baseurl", toUrl( this.project.getBasedir().getAbsolutePath() ) );
1912 if ( settings.getLocalRepository() != null )
1913 {
1914 props.put( "localRepository", settings.getLocalRepository() );
1915 props.put( "localRepositoryUrl", toUrl( settings.getLocalRepository() ) );
1916 }
1917 return new CompositeMap( this.project, props );
1918 }
1919
1920
1921
1922
1923
1924
1925
1926
1927 private static String toUrl( String filename )
1928 {
1929
1930
1931
1932
1933 String url = "file://" + new File( filename ).toURI().getPath();
1934 if ( url.endsWith( "/" ) )
1935 {
1936 url = url.substring( 0, url.length() - 1 );
1937 }
1938 return url;
1939 }
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953 private List<String> getTokens( File basedir, String filename, List<String> defaultTokens )
1954 throws IOException
1955 {
1956 List<String> tokens = ( defaultTokens != null ) ? defaultTokens : new ArrayList<String>();
1957
1958 if ( StringUtils.isNotEmpty( filename ) )
1959 {
1960 File tokenFile = new File( basedir, filename );
1961
1962 if ( tokenFile.exists() )
1963 {
1964 tokens = readTokens( tokenFile );
1965 }
1966 }
1967
1968 return tokens;
1969 }
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979 private List<String> readTokens( final File tokenFile )
1980 throws IOException
1981 {
1982 List<String> result = new ArrayList<String>();
1983
1984 BufferedReader reader = null;
1985 try
1986 {
1987 Map<String, Object> composite = getInterpolationValueSource();
1988 reader = new BufferedReader( new InterpolationFilterReader( newReader( tokenFile ), composite ) );
1989
1990 String line = null;
1991 while ( ( line = reader.readLine() ) != null )
1992 {
1993 result.addAll( collectListFromCSV( line ) );
1994 }
1995 }
1996 finally
1997 {
1998 IOUtil.close( reader );
1999 }
2000
2001 return result;
2002 }
2003
2004
2005
2006
2007
2008
2009
2010 private List<String> collectListFromCSV( final String csv )
2011 {
2012 final List<String> result = new ArrayList<String>();
2013
2014 if ( ( csv != null ) && ( csv.trim().length() > 0 ) )
2015 {
2016 final StringTokenizer st = new StringTokenizer( csv, "," );
2017
2018 while ( st.hasMoreTokens() )
2019 {
2020 result.add( st.nextToken().trim() );
2021 }
2022 }
2023
2024 return result;
2025 }
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037 void buildInterpolatedFile( File originalFile, File interpolatedFile )
2038 throws MojoExecutionException
2039 {
2040 getLog().debug( "Interpolate " + originalFile.getPath() + " to " + interpolatedFile.getPath() );
2041
2042 try
2043 {
2044 String xml;
2045
2046 Reader reader = null;
2047 try
2048 {
2049
2050 Map<String, Object> composite = getInterpolationValueSource();
2051 reader = ReaderFactory.newXmlReader( originalFile );
2052 reader = new InterpolationFilterReader( reader, composite, "@", "@" );
2053 xml = IOUtil.toString( reader );
2054 }
2055 finally
2056 {
2057 IOUtil.close( reader );
2058 }
2059
2060 Writer writer = null;
2061 try
2062 {
2063 interpolatedFile.getParentFile().mkdirs();
2064 writer = WriterFactory.newXmlWriter( interpolatedFile );
2065 writer.write( xml );
2066 writer.flush();
2067 }
2068 finally
2069 {
2070 IOUtil.close( writer );
2071 }
2072 }
2073 catch ( IOException e )
2074 {
2075 throw new MojoExecutionException( "Failed to interpolate file " + originalFile.getPath(), e );
2076 }
2077 }
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087 private InvokerProperties getInvokerProperties( final File projectDirectory )
2088 throws MojoExecutionException
2089 {
2090 Properties props = new Properties();
2091 if ( invokerPropertiesFile != null )
2092 {
2093 File propertiesFile = new File( projectDirectory, invokerPropertiesFile );
2094 if ( propertiesFile.isFile() )
2095 {
2096 InputStream in = null;
2097 try
2098 {
2099 in = new FileInputStream( propertiesFile );
2100 props.load( in );
2101 }
2102 catch ( IOException e )
2103 {
2104 throw new MojoExecutionException( "Failed to read invoker properties: " + propertiesFile, e );
2105 }
2106 finally
2107 {
2108 IOUtil.close( in );
2109 }
2110 }
2111
2112 Interpolator interpolator = new RegexBasedInterpolator();
2113 interpolator.addValueSource( new MapBasedValueSource( getInterpolationValueSource() ) );
2114 for ( String key : (Set<String>) ( (Map) props ).keySet() )
2115 {
2116 String value = props.getProperty( key );
2117 try
2118 {
2119 value = interpolator.interpolate( value, "" );
2120 }
2121 catch ( InterpolationException e )
2122 {
2123 throw new MojoExecutionException( "Failed to interpolate invoker properties: " + propertiesFile,
2124 e );
2125 }
2126 props.setProperty( key, value );
2127 }
2128 }
2129 return new InvokerProperties( props );
2130 }
2131
2132 protected boolean isParallelRun()
2133 {
2134 return parallelThreads > 1;
2135 }
2136
2137 }