1 package org.apache.maven.plugin.antrun;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.io.IOException;
24 import java.io.LineNumberReader;
25 import java.io.StringWriter;
26 import java.util.ArrayList;
27 import java.util.Collection;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Properties;
31 import java.util.Set;
32
33 import org.apache.maven.artifact.Artifact;
34 import org.apache.maven.artifact.DependencyResolutionRequiredException;
35 import org.apache.maven.artifact.repository.ArtifactRepository;
36 import org.apache.maven.plugin.AbstractMojo;
37 import org.apache.maven.plugin.MojoExecutionException;
38 import org.apache.maven.plugins.annotations.Component;
39 import org.apache.maven.plugins.annotations.Mojo;
40 import org.apache.maven.plugins.annotations.Parameter;
41 import org.apache.maven.plugins.annotations.ResolutionScope;
42 import org.apache.maven.project.MavenProject;
43 import org.apache.maven.project.MavenProjectHelper;
44 import org.apache.tools.ant.BuildException;
45 import org.apache.tools.ant.DefaultLogger;
46 import org.apache.tools.ant.Project;
47 import org.apache.tools.ant.ProjectHelper;
48 import org.apache.tools.ant.taskdefs.Typedef;
49 import org.apache.tools.ant.types.Path;
50 import org.codehaus.plexus.configuration.PlexusConfiguration;
51 import org.codehaus.plexus.configuration.PlexusConfigurationException;
52 import org.codehaus.plexus.util.FileUtils;
53 import org.codehaus.plexus.util.IOUtil;
54 import org.codehaus.plexus.util.ReaderFactory;
55 import org.codehaus.plexus.util.StringUtils;
56
57
58
59
60
61
62
63
64
65
66
67 @Mojo( name = "run", threadSafe = true, requiresDependencyResolution = ResolutionScope.TEST )
68 public class AntRunMojo
69 extends AbstractMojo
70 {
71
72
73
74 public static final String DEFAULT_MAVEN_PROJECT_REFID = "maven.project";
75
76
77
78
79 public static final String DEFAULT_MAVEN_PROJECT_HELPER_REFID = "maven.project.helper";
80
81
82
83
84 public static final String DEFAULT_ANT_TARGET_NAME = "main";
85
86
87
88
89 public static final String UTF_8 = "UTF-8";
90
91
92
93
94 private String antTargetName;
95
96
97
98
99 public static final String ANTLIB = "org/apache/maven/ant/tasks/antlib.xml";
100
101
102
103
104 public static final String TASK_URI = "antlib:org.apache.maven.ant.tasks";
105
106
107
108
109 @Parameter( defaultValue = "${project}", readonly = true, required = true )
110 private MavenProject project;
111
112
113
114
115 @Component
116 private MavenProjectHelper projectHelper;
117
118
119
120
121 @Parameter( property = "plugin.artifacts", required = true, readonly = true )
122 private List<Artifact> pluginArtifacts;
123
124
125
126
127 @Parameter( property = "localRepository", readonly = true )
128 protected ArtifactRepository localRepository;
129
130
131
132
133
134
135 @Parameter( defaultValue = "" )
136 private String propertyPrefix;
137
138
139
140
141
142
143
144
145 @Parameter( defaultValue = "" )
146 private String customTaskPrefix = "";
147
148
149
150
151
152 @Parameter( defaultValue = "maven.project.dependencies.versions" )
153 private String versionsPropertyName;
154
155
156
157
158
159
160
161 @Parameter
162 private PlexusConfiguration tasks;
163
164
165
166
167
168
169
170 @Parameter
171 private PlexusConfiguration target;
172
173
174
175
176
177
178
179 @Parameter( property = "sourceRoot" )
180 private File sourceRoot;
181
182
183
184
185
186
187
188 @Parameter( property = "testSourceRoot" )
189 private File testSourceRoot;
190
191
192
193
194
195
196 @Parameter( property = "maven.antrun.skip", defaultValue = "false" )
197 private boolean skip;
198
199
200
201
202
203
204 @Parameter( defaultValue = "false" )
205 private boolean exportAntProperties;
206
207
208
209
210
211
212
213
214 @Parameter( defaultValue = "true" )
215 private boolean failOnError;
216
217
218 public void execute()
219 throws MojoExecutionException
220 {
221 if ( skip )
222 {
223 getLog().info( "Skipping Antrun execution" );
224 return;
225 }
226
227 MavenProject mavenProject = getMavenProject();
228
229 if ( tasks != null )
230 {
231 getLog().warn( "Parameter tasks is deprecated, use target instead" );
232 target = tasks;
233 }
234
235 if ( target == null )
236 {
237 getLog().info( "No Ant target defined - SKIPPED" );
238 return;
239 }
240
241 if ( propertyPrefix == null )
242 {
243 propertyPrefix = "";
244 }
245
246 try
247 {
248 Project antProject = new Project();
249 File antBuildFile = this.writeTargetToProjectFile();
250 ProjectHelper.configureProject( antProject, antBuildFile );
251 antProject.init();
252
253 DefaultLogger antLogger = new DefaultLogger();
254 antLogger.setOutputPrintStream( System.out );
255 antLogger.setErrorPrintStream( System.err );
256
257 if ( getLog().isDebugEnabled() )
258 {
259 antLogger.setMessageOutputLevel( Project.MSG_DEBUG );
260 }
261 else if ( getLog().isInfoEnabled() )
262 {
263 antLogger.setMessageOutputLevel( Project.MSG_INFO );
264 }
265 else if ( getLog().isWarnEnabled() )
266 {
267 antLogger.setMessageOutputLevel( Project.MSG_WARN );
268 }
269 else if ( getLog().isErrorEnabled() )
270 {
271 antLogger.setMessageOutputLevel( Project.MSG_ERR );
272 }
273 else
274 {
275 antLogger.setMessageOutputLevel( Project.MSG_VERBOSE );
276 }
277
278 antProject.addBuildListener( antLogger );
279 antProject.setBaseDir( mavenProject.getBasedir() );
280
281 Path p = new Path( antProject );
282 p.setPath( StringUtils.join( mavenProject.getCompileClasspathElements().iterator(), File.pathSeparator ) );
283
284
285 antProject.addReference( "maven.dependency.classpath", p );
286 antProject.addReference( "maven.compile.classpath", p );
287
288 p = new Path( antProject );
289 p.setPath( StringUtils.join( mavenProject.getRuntimeClasspathElements().iterator(), File.pathSeparator ) );
290 antProject.addReference( "maven.runtime.classpath", p );
291
292 p = new Path( antProject );
293 p.setPath( StringUtils.join( mavenProject.getTestClasspathElements().iterator(), File.pathSeparator ) );
294 antProject.addReference( "maven.test.classpath", p );
295
296
297 antProject.addReference( "maven.plugin.classpath", getPathFromArtifacts( pluginArtifacts, antProject ) );
298
299 antProject.addReference( DEFAULT_MAVEN_PROJECT_REFID, getMavenProject() );
300 antProject.addReference( DEFAULT_MAVEN_PROJECT_HELPER_REFID, projectHelper );
301 antProject.addReference( "maven.local.repository", localRepository );
302 initMavenTasks( antProject );
303
304
305
306 copyProperties( mavenProject, antProject );
307
308 if ( getLog().isInfoEnabled() )
309 {
310 getLog().info( "Executing tasks" );
311 }
312
313 antProject.executeTarget( antTargetName );
314
315 if ( getLog().isInfoEnabled() )
316 {
317 getLog().info( "Executed tasks" );
318 }
319
320 copyProperties( antProject, mavenProject );
321 }
322 catch ( DependencyResolutionRequiredException e )
323 {
324 throw new MojoExecutionException( "DependencyResolutionRequiredException: " + e.getMessage(), e );
325 }
326 catch ( BuildException e )
327 {
328 StringBuilder sb = new StringBuilder();
329 sb.append( "An Ant BuildException has occured: " ).append( e.getMessage() );
330 String fragment = findFragment( e );
331 if ( fragment != null )
332 {
333 sb.append( "\n" ).append( fragment );
334 }
335 if ( !failOnError )
336 {
337 getLog().info( sb.toString(), e );
338 return;
339 }
340 else
341 {
342 throw new MojoExecutionException( sb.toString(), e );
343 }
344 }
345 catch ( Throwable e )
346 {
347 throw new MojoExecutionException( "Error executing Ant tasks: " + e.getMessage(), e );
348 }
349
350 if ( sourceRoot != null )
351 {
352 getLog().info( "Registering compile source root " + sourceRoot );
353 getMavenProject().addCompileSourceRoot( sourceRoot.toString() );
354 }
355
356 if ( testSourceRoot != null )
357 {
358 getLog().info( "Registering compile test source root " + testSourceRoot );
359 getMavenProject().addTestCompileSourceRoot( testSourceRoot.toString() );
360 }
361 }
362
363
364
365
366
367
368
369
370 public Path getPathFromArtifacts( Collection<Artifact> artifacts, Project antProject )
371 throws DependencyResolutionRequiredException
372 {
373 if ( artifacts == null )
374 {
375 return new Path( antProject );
376 }
377
378 List<String> list = new ArrayList<String>( artifacts.size() );
379 for ( Artifact a : artifacts )
380 {
381 File file = a.getFile();
382 if ( file == null )
383 {
384 throw new DependencyResolutionRequiredException( a );
385 }
386 list.add( file.getPath() );
387 }
388
389 Path p = new Path( antProject );
390 p.setPath( StringUtils.join( list.iterator(), File.pathSeparator ) );
391
392 return p;
393 }
394
395
396
397
398
399
400
401 public void copyProperties( MavenProject mavenProject, Project antProject )
402 {
403 Properties mavenProps = mavenProject.getProperties();
404 for ( Map.Entry<?, ?> entry : mavenProps.entrySet() )
405 {
406 antProject.setProperty( (String) entry.getKey(), (String) entry.getValue() );
407 }
408
409
410 antProject.setProperty( "ant.file", mavenProject.getFile().getAbsolutePath() );
411
412
413 getLog().debug( "Setting properties with prefix: " + propertyPrefix );
414 antProject.setProperty( ( propertyPrefix + "project.groupId" ), mavenProject.getGroupId() );
415 antProject.setProperty( ( propertyPrefix + "project.artifactId" ), mavenProject.getArtifactId() );
416 antProject.setProperty( ( propertyPrefix + "project.name" ), mavenProject.getName() );
417 if ( mavenProject.getDescription() != null )
418 {
419 antProject.setProperty( ( propertyPrefix + "project.description" ), mavenProject.getDescription() );
420 }
421 antProject.setProperty( ( propertyPrefix + "project.version" ), mavenProject.getVersion() );
422 antProject.setProperty( ( propertyPrefix + "project.packaging" ), mavenProject.getPackaging() );
423 antProject.setProperty( ( propertyPrefix + "project.build.directory" ),
424 mavenProject.getBuild().getDirectory() );
425 antProject.setProperty( ( propertyPrefix + "project.build.outputDirectory" ),
426 mavenProject.getBuild().getOutputDirectory() );
427 antProject.setProperty( ( propertyPrefix + "project.build.testOutputDirectory" ),
428 mavenProject.getBuild().getTestOutputDirectory() );
429 antProject.setProperty( ( propertyPrefix + "project.build.sourceDirectory" ),
430 mavenProject.getBuild().getSourceDirectory() );
431 antProject.setProperty( ( propertyPrefix + "project.build.testSourceDirectory" ),
432 mavenProject.getBuild().getTestSourceDirectory() );
433 antProject.setProperty( ( propertyPrefix + "localRepository" ), localRepository.toString() );
434 antProject.setProperty( ( propertyPrefix + "settings.localRepository" ), localRepository.getBasedir() );
435
436
437 @SuppressWarnings( "unchecked" )
438 Set<Artifact> depArtifacts = mavenProject.getArtifacts();
439 for ( Artifact artifact : depArtifacts )
440 {
441 String propName = artifact.getDependencyConflictId();
442
443 antProject.setProperty( propertyPrefix + propName, artifact.getFile().getPath() );
444 }
445
446
447 StringBuilder versionsBuffer = new StringBuilder();
448 for ( Artifact artifact : depArtifacts )
449 {
450 versionsBuffer.append( artifact.getVersion() ).append( File.pathSeparator );
451 }
452 antProject.setProperty( versionsPropertyName, versionsBuffer.toString() );
453
454
455
456 for ( Artifact artifact : depArtifacts )
457 {
458 String propName = getDependencyArtifactPropertyName( artifact );
459
460 antProject.setProperty( propName, artifact.getFile().getPath() );
461 }
462 }
463
464
465
466
467
468
469
470
471 public void copyProperties( Project antProject, MavenProject mavenProject )
472 {
473 if ( !exportAntProperties )
474 {
475 return;
476 }
477
478 getLog().debug( "Propagated Ant properties to Maven properties" );
479 Map<?, ?> antProps = antProject.getProperties();
480 Properties mavenProperties = mavenProject.getProperties();
481
482 for ( Map.Entry<?, ?> entry : antProps.entrySet() )
483 {
484 String key = (String) entry.getKey();
485 if ( mavenProperties.getProperty( key ) != null )
486 {
487 getLog().debug( "Ant property '" + key + "=" + mavenProperties.getProperty( key )
488 + "' clashs with an existing Maven property, "
489 + "SKIPPING this Ant property propagation." );
490 continue;
491 }
492 mavenProperties.setProperty( key, (String) entry.getValue() );
493 }
494 }
495
496
497
498
499
500
501 public static final String DEPENDENCY_PREFIX = "maven.dependency.";
502
503
504
505
506
507
508
509
510
511 public static String getDependencyArtifactPropertyName( Artifact artifact )
512 {
513 return DEPENDENCY_PREFIX + artifact.getGroupId() + "." + artifact.getArtifactId()
514 + ( artifact.getClassifier() != null ? "." + artifact.getClassifier() : "" )
515 + ( artifact.getType() != null ? "." + artifact.getType() : "" ) + ".path";
516 }
517
518
519
520
521
522
523 public MavenProject getMavenProject()
524 {
525 return this.project;
526 }
527
528
529
530
531 public void initMavenTasks( Project antProject )
532 {
533 getLog().debug( "Initialize Maven Ant Tasks" );
534 Typedef typedef = new Typedef();
535 typedef.setProject( antProject );
536 typedef.setResource( ANTLIB );
537 if ( !customTaskPrefix.equals( "" ) )
538 {
539 typedef.setURI( TASK_URI );
540 }
541 typedef.execute();
542 }
543
544
545
546
547
548
549 private File writeTargetToProjectFile()
550 throws IOException, PlexusConfigurationException
551 {
552
553 StringWriter writer = new StringWriter();
554 AntrunXmlPlexusConfigurationWriter xmlWriter = new AntrunXmlPlexusConfigurationWriter();
555 xmlWriter.write( target, writer );
556
557 StringBuilder antProjectConfig = new StringBuilder( writer.getBuffer() );
558
559
560 stringReplace( antProjectConfig, "<tasks", "<target" );
561 stringReplace( antProjectConfig, "</tasks", "</target" );
562
563 antTargetName = target.getAttribute( "name" );
564
565 if ( antTargetName == null )
566 {
567 antTargetName = DEFAULT_ANT_TARGET_NAME;
568 stringReplace( antProjectConfig, "<target", "<target name=\"" + DEFAULT_ANT_TARGET_NAME + "\"" );
569 }
570
571 String xmlns = "";
572 if ( !customTaskPrefix.trim().equals( "" ) )
573 {
574 xmlns = "xmlns:" + customTaskPrefix + "=\"" + TASK_URI + "\"";
575 }
576
577 final String xmlHeader = "<?xml version=\"1.0\" encoding=\"" + UTF_8 + "\" ?>\n";
578 antProjectConfig.insert( 0, xmlHeader );
579 final String projectOpen =
580 "<project name=\"maven-antrun-\" default=\"" + antTargetName + "\" " + xmlns + " >\n";
581 int index = antProjectConfig.indexOf( "<target" );
582 antProjectConfig.insert( index, projectOpen );
583
584 final String projectClose = "\n</project>";
585 antProjectConfig.append( projectClose );
586
587
588 String fileName = "build-" + antTargetName + ".xml";
589 File buildFile = new File( project.getBuild().getDirectory(), "/antrun/" + fileName );
590
591
592 buildFile.getParentFile().mkdirs();
593 FileUtils.fileWrite( buildFile.getAbsolutePath(), UTF_8, antProjectConfig.toString() );
594 return buildFile;
595 }
596
597
598
599
600
601
602
603
604 public void stringReplace( StringBuilder text, String match, String with )
605 {
606 int index = text.indexOf( match );
607 if ( index != -1 )
608 {
609 text.replace( index, index + match.length(), with );
610 }
611 }
612
613
614
615
616
617
618 public String checkTargetName( PlexusConfiguration antTargetConfig )
619 throws PlexusConfigurationException
620 {
621 String targetName = antTargetConfig.getAttribute( "name" );
622 if ( targetName == null )
623 {
624 targetName = DEFAULT_ANT_TARGET_NAME;
625 }
626 return targetName;
627 }
628
629
630
631
632
633
634 private String findFragment( BuildException buildException )
635 {
636 if ( buildException == null || buildException.getLocation() == null
637 || buildException.getLocation().getFileName() == null )
638 {
639 return null;
640 }
641
642 File antFile = new File( buildException.getLocation().getFileName() );
643 if ( !antFile.exists() )
644 {
645 return null;
646 }
647
648 LineNumberReader reader = null;
649 try
650 {
651 reader = new LineNumberReader( ReaderFactory.newXmlReader( antFile ) );
652 String line;
653 while ( ( line = reader.readLine() ) != null )
654 {
655 if ( reader.getLineNumber() == buildException.getLocation().getLineNumber() )
656 {
657 return "around Ant part ..." + line.trim() + "... @ " + buildException.getLocation().getLineNumber()
658 + ":" + buildException.getLocation().getColumnNumber() + " in " + antFile.getAbsolutePath();
659 }
660 }
661 }
662 catch ( Exception e )
663 {
664 getLog().debug( e.getMessage(), e );
665 return null;
666 }
667 finally
668 {
669 IOUtil.close( reader );
670 }
671
672 return null;
673 }
674 }