1 package org.apache.maven.jelly.tags.maven;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 import java.io.File;
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Iterator;
25 import java.util.List;
26
27 import org.apache.commons.jelly.JellyTagException;
28 import org.apache.commons.jelly.MissingAttributeException;
29 import org.apache.commons.jelly.XMLOutput;
30 import org.apache.commons.logging.Log;
31 import org.apache.commons.logging.LogFactory;
32 import org.apache.maven.MavenConstants;
33 import org.apache.maven.MavenException;
34 import org.apache.maven.MavenUtils;
35 import org.apache.maven.project.Project;
36
37 /**
38 * Reactor tag that processes a set of project descriptors taking into
39 * consideration the inter-project dependencies.
40 * <p/>
41 * Used for building a set of projects in the correct order to satisfy any
42 * dependencies among the projects being processed.
43 *
44 * @author <a href="mailto:bob@werken.com">bob mcwhirter</a>
45 * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
46 * @author <a href="mailto:evenisse@ifrance.com">Emmanuel Venisse</a>
47 * @version $Id: ReactorTag.java 517014 2007-03-11 21:15:50Z ltheussl $
48 * @todo We use the basedir for the glob, but we need to set the descriptor.
49 * @todo better use of inheritance from MavenTag
50 */
51 public class ReactorTag
52 extends MavenTag
53 {
54 private static final Log LOGGER = LogFactory.getLog( ReactorTag.class );
55
56 /**
57 * The glob used to select projects within the base directory.
58 */
59 private String glob;
60
61 /**
62 * Projects to include.
63 */
64 private String includes;
65
66 /**
67 * Projects to exclude.
68 */
69 private String excludes;
70
71 /**
72 * Banner to display when each project is processed.
73 */
74 private String banner;
75
76 /**
77 * project base directory
78 */
79 private File basedir;
80
81 /**
82 * The name of the context variable to store the project collection in.
83 */
84 private String collectionVar = "reactorProjects";
85
86 /**
87 * Whether to actually execute the default or specified goals, or
88 * simply collect the projects in order.
89 */
90 private boolean collectOnly = false;
91
92 /**
93 * Whether to sort the projects by dependencies.
94 */
95 private boolean sort = true;
96
97 /**
98 * Post processing flag. If this is set then we will hold on to the
99 * processed projects, otherwise they will be dumped.
100 */
101 private boolean postProcessing = false;
102
103 /**
104 * Storage for projects that failed in the build.
105 */
106 private Collection failedProjects = new ArrayList();
107
108 /**
109 * List of Project objects to use instead of glob or includes.
110 */
111 private List projectList = null;
112
113
114
115
116
117 /**
118 * Set the project list.
119 *
120 * @param projectList the project list
121 */
122 public void setProjectList( List projectList )
123 {
124 this.projectList = projectList;
125 }
126
127 /**
128 * Get the project list.
129 *
130 * @return the project list
131 */
132 public List getProjectList()
133 {
134 return projectList;
135 }
136
137 /**
138 * Setter for the basedir property
139 * XXX if the method it overrides is deprecated, is this also deprecated?
140 *
141 * @param basedir the base directory for execution of the project
142 */
143 public void setBasedir( File basedir )
144 {
145 this.basedir = basedir;
146 }
147
148 /**
149 * Getter for the basedir property
150 *
151 * @return the base directory for execution of the project
152 */
153 public File getBasedir()
154 {
155 return this.basedir;
156 }
157
158 public void setSort( boolean sort )
159 {
160 this.sort = sort;
161 }
162
163 /**
164 * Set the collectOnly attribute. This controls whether reactor
165 * will actually execute any goals on the projects, or simply
166 * collect the sorted set of projects included in this reactor
167 * invocation.
168 *
169 * @param collectOnly if true, don't execute project goals; simply
170 * gather the sorted project collection and store. Otherwise,
171 * operate as before (execute either specified goals or default goal
172 * for each project).
173 */
174 public void setCollectOnly( boolean collectOnly )
175 {
176 this.collectOnly = collectOnly;
177 }
178
179 /**
180 * Set the collectionVar attribute. This controls the context
181 * variable which will contain the sorted set of projects included
182 * in this reactor invocation.
183 *
184 * @param collectionVar The context variable for the project collection
185 * discovered here.
186 */
187 public void setCollectionVar( String collectionVar )
188 {
189 this.collectionVar = collectionVar;
190 }
191
192 /**
193 * Set the postProcessing attribute.
194 *
195 * @param postProcessing
196 */
197 public void setPostProcessing( boolean postProcessing )
198 {
199 this.postProcessing = postProcessing;
200 }
201
202 /**
203 * Get the postProcessing attribute.
204 *
205 * @return The
206 */
207 public boolean getPostProcessing()
208 {
209 return postProcessing;
210 }
211
212 /**
213 * Set the glob used to find projects.
214 *
215 * @param glob The glob used to find projects.
216 * @deprecated Use includes/excludes instead.
217 */
218 public void setGlob( String glob )
219 {
220 LOGGER.warn( "\nDEPRECATION WARNING: use the 'includes' attribute instead of the 'glob' attribute.\n" );
221 this.glob = glob;
222 }
223
224 /**
225 * Get the glob used to find projects.
226 *
227 * @return String The glob.
228 */
229 public String getGlob()
230 {
231 return glob;
232 }
233
234 /**
235 * Set the includes used to find projects.
236 *
237 * @param includes The includes used to find projects.
238 */
239 public void setIncludes( String includes )
240 {
241 this.includes = includes;
242 }
243
244 /**
245 * Get the includes used to find projects.
246 *
247 * @return String The includes.
248 */
249 public String getIncludes()
250 {
251 return includes;
252 }
253
254 /**
255 * Set the excludes used to find projects.
256 *
257 * @param excludes The excludes used to find projects.
258 */
259 public void setExcludes( String excludes )
260 {
261 this.excludes = excludes;
262 }
263
264 /**
265 * Get the excludes used to find projects.
266 *
267 * @return String The excludes.
268 */
269 public String getExcludes()
270 {
271 return excludes;
272 }
273
274 /**
275 * Set the banner to be displayed for each project while
276 * it is being processed.
277 *
278 * @param banner The banner to use for each processed project.
279 */
280 public void setBanner( String banner )
281 {
282 this.banner = banner;
283 }
284
285 /**
286 * Get the banner to be displayed for project while it
287 * is being processed.
288 *
289 * @return String The banner.
290 */
291 public String getBanner()
292 {
293 if ( banner == null )
294 {
295 banner = "Processing";
296 }
297
298 return banner;
299 }
300
301 /**
302 * Execute the body of the reactor tag.
303 *
304 * @param output The output sink.
305 * @throws JellyTagException If an error occurs while processing the tag.
306 */
307 public void doTag( XMLOutput output )
308 throws MissingAttributeException, JellyTagException
309 {
310 checkAttribute( getBasedir(), "basedir" );
311
312 if ( ( getGlob() == null ) && ( getIncludes() == null ) && ( projectList == null ) )
313 {
314 throw new MissingAttributeException( "glob|includes|projectList" );
315 }
316
317 LOGGER.info( "Starting the reactor..." );
318
319 List sortedProjects = null;
320 try
321 {
322 sortedProjects = getSortedProjects();
323 }
324 catch ( Exception e )
325 {
326 throw new JellyTagException( "Error getting projects", e );
327 }
328
329 LOGGER.info( "Our processing order:" );
330
331 for ( Iterator i = sortedProjects.iterator(); i.hasNext(); )
332 {
333 Project p = (Project) i.next();
334 LOGGER.info( p.getName() );
335 }
336
337 ArrayList reactorProjects = new ArrayList();
338
339 Runtime r = Runtime.getRuntime();
340 for ( Iterator i = sortedProjects.iterator(); i.hasNext(); )
341 {
342
343
344
345 Project project = (Project) i.next();
346 beforeProject( project );
347
348 final long mb = 1024 * 1024;
349 LOGGER.info( "+----------------------------------------" );
350 LOGGER.info( "| " + getBanner() + " " + project.getName() );
351 LOGGER.info( "| Memory: " + ( ( r.totalMemory() - r.freeMemory() ) / mb ) + "M/" + ( r.totalMemory() / mb )
352 + "M" );
353 LOGGER.info( "+----------------------------------------" );
354
355
356
357
358 List goalList = null;
359 if ( getGoals() != null )
360 {
361 goalList = MavenUtils.getGoalListFromCsv( getGoals() );
362 }
363
364 beforeLaunchGoals( project );
365
366 try
367 {
368 if ( !collectOnly )
369 {
370 getMavenContext().getMavenSession().attainGoals( project, goalList );
371 }
372 }
373 catch ( Exception e )
374 {
375 onException( project, e );
376
377
378 if ( !isIgnoreFailures() )
379 {
380 throw new JellyTagException( "Reactor subproject failure occurred", e );
381 }
382 }
383
384 afterLaunchGoals( project );
385 afterProject( project );
386
387 if ( getPostProcessing() || collectOnly )
388 {
389 reactorProjects.add( project );
390 }
391 }
392
393 getContext().setVariable( collectionVar, reactorProjects );
394 Collection c = (Collection) getContext().getVariable( MavenConstants.FAILED_PROJECTS );
395 if ( c == null )
396 {
397 c = new ArrayList( failedProjects );
398 }
399 else
400 {
401 c.addAll( failedProjects );
402 }
403 getContext().setVariable( MavenConstants.FAILED_PROJECTS, c );
404 }
405
406 /**
407 * Get a list of projects to process, sorted by dependency processing order.
408 * Maintained as a separate method so that the original projects and dependency resolver memory is freed.
409 *
410 * @return the project list
411 */
412 private List getSortedProjects()
413 throws MavenException
414 {
415 if ( projectList != null )
416 {
417 LOGGER.debug( "using existing list of projects: " + projectList );
418 return projectList;
419 }
420
421 String projectIncludes;
422 if ( getGlob() != null )
423 {
424 projectIncludes = getGlob();
425 }
426 else
427 {
428 projectIncludes = getIncludes();
429 }
430
431 List projects = MavenUtils.getProjects( getBasedir(), projectIncludes, getExcludes(), getMavenContext()
432 .getMavenSession().getRootContext() );
433
434 if ( sort )
435 {
436 DependencyResolver dr = new DependencyResolver();
437 dr.setProjects( projects );
438
439 return dr.getSortedDependencies( false );
440 }
441 else
442 {
443 return projects;
444 }
445 }
446
447 /**
448 * This method is running before launching a project.
449 *
450 * @param project the currentProject
451 */
452 public void beforeProject( Project project )
453 {
454 }
455
456 /**
457 * This method is running before launching project goals.
458 *
459 * @param project the currentProject
460 */
461 public void beforeLaunchGoals( Project project )
462 {
463 }
464
465 /**
466 * This method is running after launching project goals.
467 *
468 * @param project the currentProject
469 */
470 public void afterLaunchGoals( Project project )
471 {
472 }
473
474 /**
475 * This method is running after launching a project.
476 *
477 * @param project the currentProject
478 */
479 public void afterProject( Project project )
480 {
481 }
482
483 /**
484 * This method is running when an exception occurs whatever
485 * the ignoreFailures value.
486 *
487 * @param project the currentProject
488 * @param e the exception
489 */
490 public void onException( Project project, Exception e )
491 {
492 getContext().setVariable( MavenConstants.BUILD_FAILURE, "true" );
493 failedProjects.add( project );
494 }
495
496 /**
497 * This method is running when an exception occurs in
498 * dependency resolution.
499 *
500 * @param e the exception
501 */
502 public void onDependencyResolutionException( Exception e )
503 {
504 }
505 }