1 package org.apache.maven.plugins.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.util.ArrayList;
26 import java.util.Collection;
27 import java.util.Hashtable;
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.execution.MavenSession;
37 import org.apache.maven.plugin.AbstractMojo;
38 import org.apache.maven.plugin.MojoExecutionException;
39 import org.apache.maven.plugin.MojoFailureException;
40 import org.apache.maven.plugins.annotations.Component;
41 import org.apache.maven.plugins.annotations.Mojo;
42 import org.apache.maven.plugins.annotations.Parameter;
43 import org.apache.maven.plugins.annotations.ResolutionScope;
44 import org.apache.maven.project.MavenProject;
45 import org.apache.maven.project.MavenProjectHelper;
46 import org.apache.tools.ant.BuildException;
47 import org.apache.tools.ant.DefaultLogger;
48 import org.apache.tools.ant.Project;
49 import org.apache.tools.ant.ProjectHelper;
50 import org.apache.tools.ant.taskdefs.Typedef;
51 import org.apache.tools.ant.types.Path;
52 import org.codehaus.plexus.configuration.PlexusConfiguration;
53 import org.codehaus.plexus.util.ReaderFactory;
54 import org.codehaus.plexus.util.StringUtils;
55
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
75 public static final String MAVEN_REFID_PREFIX = "maven.";
76
77
78
79
80
81
82 public static final String DEFAULT_MAVEN_PROJECT_REFID = MAVEN_REFID_PREFIX + "project";
83
84
85
86
87
88
89
90 public static final String DEFAULT_MAVEN_PROJECT_REF_REFID = MAVEN_REFID_PREFIX + "project.ref";
91
92
93
94
95 public static final String DEFAULT_MAVEN_PROJECT_HELPER_REFID = MAVEN_REFID_PREFIX + "project.helper";
96
97
98
99
100 public static final String DEFAULT_ANT_TARGET_NAME = "main";
101
102
103
104
105 public static final String UTF_8 = "UTF-8";
106
107
108
109
110 public static final String ANTLIB = "org/apache/maven/ant/tasks/antlib.xml";
111
112
113
114
115 public static final String TASK_URI = "antlib:org.apache.maven.ant.tasks";
116
117
118
119
120 @Parameter( defaultValue = "${project}", readonly = true, required = true )
121 private MavenProject mavenProject;
122
123
124
125
126 @Parameter( defaultValue = "${session}", readonly = true, required = true )
127 private MavenSession session;
128
129
130
131
132 @Component
133 private MavenProjectHelper projectHelper;
134
135
136
137
138 @Parameter( property = "plugin.artifacts", required = true, readonly = true )
139 private List<Artifact> pluginArtifacts;
140
141
142
143
144 @Parameter( property = "localRepository", readonly = true )
145 protected ArtifactRepository localRepository;
146
147
148
149
150
151
152 @Parameter( defaultValue = "" )
153 private String propertyPrefix;
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171 @Deprecated
172 @Parameter
173 private String customTaskPrefix;
174
175
176
177
178
179 @Parameter( defaultValue = "maven.project.dependencies.versions" )
180 private String versionsPropertyName;
181
182
183
184
185
186
187
188
189 @Deprecated
190 @Parameter
191 private PlexusConfiguration tasks;
192
193
194
195
196
197
198
199 @Parameter
200 private PlexusConfiguration target;
201
202
203
204
205
206
207
208
209 @SuppressWarnings( "DeprecatedIsStillUsed" )
210 @Deprecated
211 @Parameter( property = "sourceRoot" )
212 private File sourceRoot;
213
214
215
216
217
218
219
220
221 @SuppressWarnings( "DeprecatedIsStillUsed" )
222 @Deprecated
223 @Parameter( property = "testSourceRoot" )
224 private File testSourceRoot;
225
226
227
228
229
230
231 @Parameter( property = "maven.antrun.skip", defaultValue = "false" )
232 private boolean skip;
233
234
235
236
237
238
239 @Parameter( defaultValue = "false" )
240 private boolean exportAntProperties;
241
242
243
244
245
246
247
248
249 @Parameter( defaultValue = "true" )
250 private boolean failOnError;
251
252 @Override
253 public void execute()
254 throws MojoExecutionException, MojoFailureException
255 {
256 checkDeprecatedParameterUsage( tasks, "tasks", "target" );
257 checkDeprecatedParameterUsage( sourceRoot, "sourceRoot", "the build-helper-maven-plugin" );
258 checkDeprecatedParameterUsage( testSourceRoot, "testSourceRoot", "the build-helper-maven-plugin" );
259 if ( skip )
260 {
261 getLog().info( "Skipping Antrun execution" );
262 return;
263 }
264
265 if ( target == null )
266 {
267 getLog().info( "No Ant target defined - SKIPPED" );
268 return;
269 }
270
271 if ( propertyPrefix == null )
272 {
273 propertyPrefix = "";
274 }
275
276 String antTargetName = target.getAttribute( "name", DEFAULT_ANT_TARGET_NAME );
277 target.setAttribute( "name", antTargetName );
278
279 Project antProject = new Project();
280 antProject.addBuildListener( getConfiguredBuildLogger() );
281 try
282 {
283 File antBuildFile = writeTargetToProjectFile( antTargetName );
284 ProjectHelper.configureProject( antProject, antBuildFile );
285 antProject.init();
286
287 antProject.setBaseDir( mavenProject.getBasedir() );
288
289 addAntProjectReferences( mavenProject, antProject );
290 initMavenTasks( antProject );
291
292
293
294 copyProperties( mavenProject, antProject );
295
296 getLog().info( "Executing tasks" );
297 antProject.executeTarget( antTargetName );
298 getLog().info( "Executed tasks" );
299
300 copyProperties( antProject, mavenProject );
301 }
302 catch ( BuildException e )
303 {
304 StringBuilder sb = new StringBuilder();
305 sb.append( "An Ant BuildException has occured: " ).append( e.getMessage() );
306 String fragment = findFragment( e );
307 if ( fragment != null )
308 {
309 sb.append( "\n" ).append( fragment );
310 }
311 if ( !failOnError )
312 {
313 getLog().info( sb.toString(), e );
314 return;
315 }
316 else
317 {
318 throw new MojoExecutionException( sb.toString(), e );
319 }
320 }
321 catch ( Throwable e )
322 {
323 throw new MojoExecutionException( "Error executing Ant tasks: " + e.getMessage(), e );
324 }
325 }
326
327 private void checkDeprecatedParameterUsage( Object parameter, String name, String replacement )
328 throws MojoFailureException
329 {
330 if ( parameter != null )
331 {
332 throw new MojoFailureException( "You are using '" + name + "' which has been removed"
333 + " from the maven-antrun-plugin. Please use '" + replacement
334 + "' and refer to the >>Major Version Upgrade to version 3.0.0<< " + "on the plugin site." );
335 }
336 }
337
338 private DefaultLogger getConfiguredBuildLogger()
339 {
340 DefaultLogger antLogger = new MavenLogger( getLog() );
341 if ( getLog().isDebugEnabled() )
342 {
343 antLogger.setMessageOutputLevel( Project.MSG_DEBUG );
344 }
345 else if ( getLog().isInfoEnabled() )
346 {
347 antLogger.setMessageOutputLevel( Project.MSG_INFO );
348 }
349 else if ( getLog().isWarnEnabled() )
350 {
351 antLogger.setMessageOutputLevel( Project.MSG_WARN );
352 }
353 else if ( getLog().isErrorEnabled() )
354 {
355 antLogger.setMessageOutputLevel( Project.MSG_ERR );
356 }
357 else
358 {
359 antLogger.setMessageOutputLevel( Project.MSG_VERBOSE );
360 }
361 return antLogger;
362 }
363
364 private void addAntProjectReferences( MavenProject mavenProject, Project antProject )
365 throws DependencyResolutionRequiredException
366 {
367 Path p = new Path( antProject );
368 p.setPath( StringUtils.join( mavenProject.getCompileClasspathElements().iterator(), File.pathSeparator ) );
369
370
371 antProject.addReference( MAVEN_REFID_PREFIX + "dependency.classpath", p );
372 antProject.addReference( MAVEN_REFID_PREFIX + "compile.classpath", p );
373
374 p = new Path( antProject );
375 p.setPath( StringUtils.join( mavenProject.getRuntimeClasspathElements().iterator(), File.pathSeparator ) );
376 antProject.addReference( MAVEN_REFID_PREFIX + "runtime.classpath", p );
377
378 p = new Path( antProject );
379 p.setPath( StringUtils.join( mavenProject.getTestClasspathElements().iterator(), File.pathSeparator ) );
380 antProject.addReference( MAVEN_REFID_PREFIX + "test.classpath", p );
381
382
383 antProject.addReference( MAVEN_REFID_PREFIX + "plugin.classpath",
384 getPathFromArtifacts( pluginArtifacts, antProject ) );
385
386 antProject.addReference( DEFAULT_MAVEN_PROJECT_REFID, mavenProject );
387 antProject.addReference( DEFAULT_MAVEN_PROJECT_REF_REFID, new MavenAntRunProject( mavenProject ) );
388 antProject.addReference( DEFAULT_MAVEN_PROJECT_HELPER_REFID, projectHelper );
389 antProject.addReference( MAVEN_REFID_PREFIX + "local.repository", localRepository );
390 }
391
392
393
394
395
396
397
398 private Path getPathFromArtifacts( Collection<Artifact> artifacts, Project antProject )
399 throws DependencyResolutionRequiredException
400 {
401 if ( artifacts == null )
402 {
403 return new Path( antProject );
404 }
405
406 List<String> list = new ArrayList<>( artifacts.size() );
407 for ( Artifact a : artifacts )
408 {
409 File file = a.getFile();
410 if ( file == null )
411 {
412 throw new DependencyResolutionRequiredException( a );
413 }
414 list.add( file.getPath() );
415 }
416
417 Path p = new Path( antProject );
418 p.setPath( StringUtils.join( list.iterator(), File.pathSeparator ) );
419
420 return p;
421 }
422
423
424
425
426
427
428
429 public void copyProperties( MavenProject mavenProject, Project antProject )
430 {
431 Properties mavenProps = mavenProject.getProperties();
432 Properties userProps = session.getUserProperties();
433 List<String> allPropertyKeys = new ArrayList<>( mavenProps.stringPropertyNames() );
434 allPropertyKeys.addAll( userProps.stringPropertyNames() );
435 for ( String key : allPropertyKeys )
436 {
437 String value = userProps.getProperty( key, mavenProps.getProperty( key ) );
438 antProject.setProperty( key, value );
439 }
440
441
442 antProject.setProperty( "ant.file", mavenProject.getFile().getAbsolutePath() );
443
444
445 getLog().debug( "Setting properties with prefix: " + propertyPrefix );
446 antProject.setProperty( ( propertyPrefix + "project.groupId" ), mavenProject.getGroupId() );
447 antProject.setProperty( ( propertyPrefix + "project.artifactId" ), mavenProject.getArtifactId() );
448 antProject.setProperty( ( propertyPrefix + "project.name" ), mavenProject.getName() );
449 if ( mavenProject.getDescription() != null )
450 {
451 antProject.setProperty( ( propertyPrefix + "project.description" ), mavenProject.getDescription() );
452 }
453 antProject.setProperty( ( propertyPrefix + "project.version" ), mavenProject.getVersion() );
454 antProject.setProperty( ( propertyPrefix + "project.packaging" ), mavenProject.getPackaging() );
455 antProject.setProperty( ( propertyPrefix + "project.build.directory" ),
456 mavenProject.getBuild().getDirectory() );
457 antProject.setProperty( ( propertyPrefix + "project.build.outputDirectory" ),
458 mavenProject.getBuild().getOutputDirectory() );
459 antProject.setProperty( ( propertyPrefix + "project.build.testOutputDirectory" ),
460 mavenProject.getBuild().getTestOutputDirectory() );
461 antProject.setProperty( ( propertyPrefix + "project.build.sourceDirectory" ),
462 mavenProject.getBuild().getSourceDirectory() );
463 antProject.setProperty( ( propertyPrefix + "project.build.testSourceDirectory" ),
464 mavenProject.getBuild().getTestSourceDirectory() );
465 antProject.setProperty( ( propertyPrefix + "localRepository" ), localRepository.toString() );
466 antProject.setProperty( ( propertyPrefix + "settings.localRepository" ), localRepository.getBasedir() );
467
468
469 Set<Artifact> depArtifacts = mavenProject.getArtifacts();
470 for ( Artifact artifact : depArtifacts )
471 {
472 String propName = artifact.getDependencyConflictId();
473
474 antProject.setProperty( propertyPrefix + propName, artifact.getFile().getPath() );
475 }
476
477
478 StringBuilder versionsBuffer = new StringBuilder();
479 for ( Artifact artifact : depArtifacts )
480 {
481 versionsBuffer.append( artifact.getVersion() ).append( File.pathSeparator );
482 }
483 antProject.setProperty( versionsPropertyName, versionsBuffer.toString() );
484 }
485
486
487
488
489
490
491
492
493 public void copyProperties( Project antProject, MavenProject mavenProject )
494 {
495 if ( !exportAntProperties )
496 {
497 return;
498 }
499
500 getLog().debug( "Propagated Ant properties to Maven properties" );
501 Hashtable<String, Object> antProps = antProject.getProperties();
502 Properties mavenProperties = mavenProject.getProperties();
503
504 for ( Map.Entry<String, Object> entry : antProps.entrySet() )
505 {
506 String key = entry.getKey();
507 if ( mavenProperties.getProperty( key ) != null )
508 {
509 getLog().debug( "Ant property '" + key + "=" + mavenProperties.getProperty( key )
510 + "' clashs with an existing Maven property, SKIPPING this Ant property propagation." );
511 continue;
512 }
513
514 mavenProperties.setProperty( key, entry.getValue().toString() );
515 }
516 }
517
518
519
520
521 public void initMavenTasks( Project antProject )
522 {
523 getLog().debug( "Initialize Maven Ant Tasks" );
524 Typedef typedef = new Typedef();
525 typedef.setProject( antProject );
526 typedef.setResource( ANTLIB );
527
528 if ( getTaskPrefix() != null )
529 {
530 typedef.setURI( TASK_URI );
531 }
532 typedef.execute();
533 }
534
535
536
537
538
539
540 private File writeTargetToProjectFile( String targetName )
541 throws IOException
542 {
543
544 File buildFile = new File( mavenProject.getBuild().getDirectory(), "antrun/build-" + targetName + ".xml" );
545
546 buildFile.getParentFile().mkdirs();
547
548 AntrunXmlPlexusConfigurationWriter xmlWriter = new AntrunXmlPlexusConfigurationWriter();
549
550 String taskPrefix = getTaskPrefix();
551 if ( taskPrefix != null )
552 {
553
554 target.setAttribute( "xmlns:" + taskPrefix, TASK_URI );
555 }
556
557 xmlWriter.write( target, buildFile, "", targetName );
558
559 return buildFile;
560 }
561
562 private String getTaskPrefix()
563 {
564 String taskPrefix = this.customTaskPrefix;
565 if ( taskPrefix == null )
566 {
567 for ( String name : target.getAttributeNames() )
568 {
569 if ( name.startsWith( "xmlns:" )
570 && "http://maven.apache.org/ANTRUN".equals( target.getAttribute( name ) ) )
571 {
572 taskPrefix = name.substring( "xmlns:".length() );
573 break;
574 }
575 }
576 }
577 return taskPrefix;
578 }
579
580
581
582
583
584
585 private String findFragment( BuildException buildException )
586 {
587 if ( buildException == null || buildException.getLocation() == null
588 || buildException.getLocation().getFileName() == null )
589 {
590 return null;
591 }
592
593 File antFile = new File( buildException.getLocation().getFileName() );
594 if ( !antFile.exists() )
595 {
596 return null;
597 }
598
599 try ( LineNumberReader reader = new LineNumberReader( ReaderFactory.newXmlReader( antFile ) ) )
600 {
601 for ( String line = reader.readLine(); line != null; line = reader.readLine() )
602 {
603 if ( reader.getLineNumber() == buildException.getLocation().getLineNumber() )
604 {
605 return "around Ant part ..." + line.trim() + "... @ " + buildException.getLocation().getLineNumber()
606 + ":" + buildException.getLocation().getColumnNumber() + " in " + antFile.getAbsolutePath();
607
608 }
609 }
610 }
611 catch ( Exception e )
612 {
613 getLog().debug( e.getMessage(), e );
614 }
615
616 return null;
617 }
618 }