1 /*
2 * Copyright (c) 2007, Ounce Labs, Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the <organization> nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY OUNCE LABS, INC. ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL OUNCE LABS, INC. BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 package org.codehaus.mojo.ounce;
29
30 import java.io.File;
31 import java.io.IOException;
32 import java.util.ArrayList;
33 import java.util.Iterator;
34 import java.util.List;
35 import java.util.Map;
36
37 import org.apache.maven.plugin.MojoExecutionException;
38 import org.apache.maven.plugin.MojoFailureException;
39 import org.apache.maven.project.MavenProject;
40 import org.codehaus.mojo.ounce.core.OunceCore;
41 import org.codehaus.mojo.ounce.core.OunceCoreApplication;
42 import org.codehaus.mojo.ounce.core.OunceCoreException;
43 import org.codehaus.mojo.ounce.core.OunceProjectBean;
44 import org.codehaus.mojo.ounce.utils.ExternalApplication;
45 import org.codehaus.mojo.ounce.utils.ProjectFileInfo;
46 import org.codehaus.mojo.ounce.utils.Utils;
47 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
48 import org.codehaus.plexus.components.io.fileselectors.IncludeExcludeFileSelector;
49 import org.codehaus.plexus.util.StringUtils;
50
51 /**
52 * This mojo generates an Ounce application file. It will automatically include all child modules as projects. This list
53 * make be modified using the includes and excludes patterns. Projects that are external to this build may be included
54 * directly using the externalProjects list. External Applications may also be included. All of their modules will be
55 * inherted as part of this application file. Those projects may also be filtered upon import.
56 *
57 * @author <a href="mailto:brianf@apache.org">Brian Fox</a>
58 * @aggregator
59 * @phase package
60 * @goal application
61 */
62 public class ApplicationMojo
63 extends AbstractOunceMojo
64 {
65
66 /**
67 * The projects in the current build.
68 *
69 * @parameter expression="${reactorProjects}"
70 * @required
71 * @readonly
72 */
73 private List projects;
74
75 /**
76 * An array of directories containing the pom file of any projects to include. If an include pattern is specified,
77 * projects not specifed by include patterns are excluded. <br/> Include only applies to inherited modules, not
78 * external projects. The current project is not filtered. <br/> The include pattern may contain the following
79 * wildcard characters:<br/> *: Zero or more characters<br/> **: Any folders<br/> ?: One and only one character<br/>
80 *
81 * @parameter
82 */
83 protected String[] includes;
84
85 /**
86 * An array of directories containing the pom file of any projects to exclude. Excludes can contain standard
87 * Ant-style wildcards. <br/> Excludes only apply to inherited modules, not external projects. The current project
88 * is not filtered.
89 *
90 * @parameter
91 */
92 protected String[] excludes;
93
94 /**
95 * List of external projects to include. These projects are included after any other projects have been included or
96 * excluded. <br/> The format is: name,path<br/> Where:<br/>
97 * <li>name is the artifact ID of the project to include.</li>
98 * <li>path is the pathname to the project.</li>
99 *
100 * @parameter
101 */
102 protected List externalProjects;
103
104 /**
105 * Allows you to include projects from multiple applications. The external application properties are not inherited,
106 * and the external application must already exist. <br/> externalApplications is a list of directories containing
107 * top-level pom files. <br/> The format for externalApplications is:
108 * pathname,[includes|includes],[excludes|excludes] <br/> Where:<br/>
109 * <li>pathname, includes, and excludes are comma delimited; if you have excludes, but no includes, use two commas.</li>
110 * <li>Multiple includes or excludes are separated by pipes (\x7c).</li>
111 * <li>Excludes can contain standard Ant style wildcards.</li>
112 *
113 * @parameter
114 */
115 protected List externalApplications;
116
117 /*
118 * (non-Javadoc)
119 *
120 * @see org.apache.maven.plugin.Mojo#execute()
121 */
122 public void execute()
123 throws MojoExecutionException, MojoFailureException
124 {
125
126 try
127 {
128 OunceCore core = getCore();
129
130 List coreProjects = getIncludedModules();
131 List externs = getExternalProjects();
132
133 if ( externs != null )
134 {
135 if ( coreProjects != null )
136 {
137 coreProjects.addAll( externs );
138 }
139 else
140 {
141 coreProjects = externs;
142 }
143 }
144
145 externs = getIncludedExternalApplicationProjects( core );
146 if ( externs != null )
147 {
148 coreProjects.addAll( externs );
149 }
150
151 // perform variable substitution
152 Iterator it = coreProjects.iterator();
153 while ( it.hasNext() )
154 {
155 OunceProjectBean projectBean = (OunceProjectBean) it.next();
156 projectBean.setPath( Utils.convertToVariablePath( projectBean.getPath(), pathVariableMap ) );
157 }
158
159 core.createApplication( getProjectRoot(), name, ".", coreProjects, options, getLog() );
160 }
161 catch ( ComponentLookupException e )
162 {
163 throw new MojoExecutionException( "Unable to lookup the core interface for hint: " + coreHint, e );
164 }
165 catch ( OunceCoreException e )
166 {
167 throw new MojoExecutionException( "Nested Ouncecore exception: " + e.getLocalizedMessage(), e );
168 }
169 catch ( IOException e )
170 {
171 throw new MojoExecutionException( "Nested IOexception: " + e.getLocalizedMessage(), e );
172 }
173
174 }
175
176 /**
177 * This method filters the projects.
178 *
179 * @param theProjects
180 * @param includes
181 * @param excludes
182 * @return
183 * @throws IOException
184 */
185 private List getSelectedModules( List theProjects, String[] includes, String[] excludes )
186 throws IOException
187 {
188 IncludeExcludeFileSelector selector = new IncludeExcludeFileSelector();
189
190 if ( excludes != null && excludes.length > 0 )
191 {
192 selector.setExcludes( excludes );
193 }
194
195 if ( includes != null && includes.length > 0 )
196 {
197 selector.setIncludes( includes );
198 }
199
200 List coreProjects = new ArrayList( theProjects.size() );
201
202 Iterator iter = theProjects.iterator();
203 while ( iter.hasNext() )
204 {
205 MavenProject prj = (MavenProject) iter.next();
206
207 if ( selector.isSelected( new ProjectFileInfo( prj.getBasedir() ) ) || prj == project )
208 {
209 coreProjects.add( prj );
210 }
211 }
212 return coreProjects;
213 }
214
215 /**
216 * Build a list of modules to be included as projects. These will be projects that are children of the current
217 * project.
218 *
219 * @return List of OunceProjectBeans representing each module
220 * @throws IOException
221 */
222 protected List getIncludedModules()
223 throws IOException
224 {
225
226 /*
227 * first we need to prefilter the reactor projects list. instead of including only the current project's
228 * children, it includes everything we need to build a prefilter based on the current project's path and only
229 * include projects with a matching path.
230 */
231 File baseDir = project.getBasedir();
232 String[] preFilterIncludes = new String[1];
233 preFilterIncludes[0] = "**/" + baseDir.getName() + "/**";
234 List preFilteredProjects = getSelectedModules( projects, preFilterIncludes, null );
235
236 // now do the normal filtering
237 List includedProjects = getSelectedModules( preFilteredProjects, includes, excludes );
238
239 // now make them beans
240 return convertToBeans( includedProjects );
241
242 }
243
244 /**
245 * Converts a list of Maven Projects to OunceProjectBeans
246 *
247 * @param theProjects
248 * @return
249 */
250 private List convertToBeans( List theProjects )
251 {
252 List beanProjects = new ArrayList( theProjects.size() );
253
254 Iterator iter = theProjects.iterator();
255 while ( iter.hasNext() )
256 {
257 MavenProject prj = (MavenProject) iter.next();
258
259 if ( !skipPoms || !prj.getPackaging().equalsIgnoreCase( "pom" ) )
260 {
261 String path = prj.getBasedir().getAbsolutePath();
262
263 path = Utils.convertToRelativePath( path, getProjectRoot(), "" );
264
265 beanProjects.add( new OunceProjectBean( path, prj.getArtifactId() ) );
266 }
267
268 else
269 {
270 this.getLog().debug( "Skipping Pom: " + prj.getArtifactId() );
271 }
272 }
273
274 return beanProjects;
275 }
276
277 /**
278 * Get the list of user defined external projects
279 *
280 * @return List of external Projects
281 * @throws MojoExecutionException if the format is invalid
282 */
283 protected List getExternalProjects()
284 throws MojoExecutionException
285 {
286 List externals = null;
287
288 if ( externalProjects != null && externalProjects.size() > 0 )
289 {
290
291 // init the array
292 externals = new ArrayList( externalProjects.size() );
293
294 // add each one
295 Iterator iter = externalProjects.iterator();
296 while ( iter.hasNext() )
297 {
298 // break the project into name:path
299 String extern = (String) iter.next();
300 String[] prj = extern.split( "," );
301 if ( prj.length == 2 )
302 {
303 externals.add( new OunceProjectBean( Utils.convertToUnixStylePath( prj[1] ), prj[0] ) );
304 }
305 else
306 {
307 // they didn't follow the format
308 throw new MojoExecutionException( "Invalid External Project String: " + extern );
309 }
310 }
311 }
312 return externals;
313 }
314
315 /**
316 * Get the list of user defined external application files to process
317 *
318 * @return List of external Applications
319 * @throws MojoExecutionException if the format is invalid
320 */
321 protected List getExternalApplications()
322 throws MojoExecutionException
323 {
324 List externals = null;
325
326 if ( externalApplications != null && externalApplications.size() > 0 )
327 {
328
329 // init the array
330 externals = new ArrayList( externalApplications.size() );
331
332 // add each one
333 Iterator iter = externalApplications.iterator();
334 while ( iter.hasNext() )
335 {
336 // break the project into
337 // path,includes,excludes
338 String extern = (String) iter.next();
339 String[] prj = extern.split( "," );
340
341 prj[0] = Utils.convertToUnixStylePath( prj[0] );
342
343 if ( prj.length == 3 )
344 {
345 externals.add( new ExternalApplication( prj[0], prj[1], prj[2] ) );
346 }
347 else if ( prj.length == 2 )
348 {
349 externals.add( new ExternalApplication( prj[0], prj[1], null ) );
350 }
351 else if ( prj.length == 1 )
352 {
353 externals.add( new ExternalApplication( prj[0], null, null ) );
354 }
355 else
356 {
357 // they didn't follow the format
358 throw new MojoExecutionException( "Invalid External Application String: " + extern );
359 }
360 }
361 }
362 else
363 {
364 externals = new ArrayList();
365 }
366 return externals;
367 }
368
369 /**
370 * This method processes the external Applications and filters them according to the include/exclude patterns
371 *
372 * @return List of OunceCoreProject objects
373 * @throws MojoExecutionException
374 * @throws OunceCoreException
375 * @throws IOException
376 */
377 public List getIncludedExternalApplicationProjects( OunceCore core )
378 throws MojoExecutionException, OunceCoreException, IOException
379 {
380
381 List externalApps = getExternalApplications();
382
383 // init results
384 ArrayList results = new ArrayList( externalApps.size() );
385
386 Iterator iter = externalApps.iterator();
387
388 while ( iter.hasNext() )
389 {
390 ExternalApplication extern = (ExternalApplication) iter.next();
391
392 // read the projects from the application ->
393 getLog().debug( "Reading External Application: " + extern.getPath() );
394 OunceCoreApplication app = core.readApplication( extern.getPath(), getLog() );
395
396 results.addAll( filterExternalApplicationProjects( app, extern ) );
397 }
398
399 return results;
400 }
401
402 /**
403 * This method filters the projects retrieved from the external application
404 *
405 * @param app
406 * @param extern
407 * @return
408 * @throws IOException
409 */
410 public List filterExternalApplicationProjects( OunceCoreApplication app, ExternalApplication extern )
411 throws IOException
412 {
413 List results = new ArrayList();
414 if ( app != null && app.getProjects() != null )
415 {
416 IncludeExcludeFileSelector fileSelector = new IncludeExcludeFileSelector();
417
418 String excludeString = extern.getExcludes();
419 String includeString = extern.getIncludes();
420
421 // init scanner with inc/exc
422 if ( StringUtils.isNotEmpty( excludeString ) )
423 {
424 // split on |
425 fileSelector.setExcludes( excludeString.split( "\\x7C" ) );
426 }
427
428 if ( StringUtils.isNotEmpty( includeString ) )
429 {
430 // split on |
431 fileSelector.setIncludes( includeString.split( "\\x7C" ) );
432 }
433
434 for ( Iterator pIter = app.getProjects().iterator(); pIter.hasNext(); )
435 {
436 OunceProjectBean prj = (OunceProjectBean) pIter.next();
437 getLog().debug( "Filtering External App Project: " + prj );
438 if ( fileSelector.isSelected( new ProjectFileInfo( new File( prj.getPath() ) ) ) )
439 {
440 String path = Utils.convertToUnixStylePath( extern.getPath() + "/" + prj.getPath() );
441 path = Utils.convertToVariablePath( path, pathVariableMap );
442 prj.setPath( path );
443
444 getLog().debug( "Adding External App Project: " + prj );
445 results.add( prj );
446 }
447 }
448 }
449 return results;
450 }
451
452 /**
453 * @return the projects
454 */
455 public List getProjects()
456 {
457 return this.projects;
458 }
459
460 /**
461 * @param theProjects the projects to set
462 */
463 public void setProjects( List theProjects )
464 {
465 this.projects = theProjects;
466 }
467
468 /**
469 * @return the includes
470 */
471 public String[] getIncludes()
472 {
473 return this.includes;
474 }
475
476 /**
477 * @param theIncludes the includes to set
478 */
479 public void setIncludes( String[] theIncludes )
480 {
481 this.includes = theIncludes;
482 }
483
484 /**
485 * @return the excludes
486 */
487 public String[] getExcludes()
488 {
489 return this.excludes;
490 }
491
492 /**
493 * @param theExcludes the excludes to set
494 */
495 public void setExcludes( String[] theExcludes )
496 {
497 this.excludes = theExcludes;
498 }
499
500 /**
501 * @param theExternalProjects the externalProjects to set
502 */
503 public void setExternalProjects( List theExternalProjects )
504 {
505 this.externalProjects = theExternalProjects;
506 }
507
508 /**
509 * @param theExternalApplications the externalApplications to set
510 */
511 public void setExternalApplications( List theExternalApplications )
512 {
513 this.externalApplications = theExternalApplications;
514 }
515
516 /**
517 * @param thePathProperties the pathVariableMap to set
518 */
519 public void setPathProperties( Map thePathProperties )
520 {
521 this.pathVariableMap = thePathProperties;
522 }
523
524 }