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