001package org.apache.maven.plugins.enforcer; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import java.io.File; 023import java.io.IOException; 024import java.lang.reflect.Field; 025import java.util.ArrayList; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.Collections; 029import java.util.HashMap; 030import java.util.HashSet; 031import java.util.Iterator; 032import java.util.List; 033import java.util.Map; 034import java.util.Set; 035import java.util.Map.Entry; 036 037import org.apache.maven.BuildFailureException; 038import org.apache.maven.artifact.Artifact; 039import org.apache.maven.artifact.factory.ArtifactFactory; 040import org.apache.maven.artifact.repository.ArtifactRepository; 041import org.apache.maven.artifact.resolver.ArtifactNotFoundException; 042import org.apache.maven.artifact.resolver.ArtifactResolutionException; 043import org.apache.maven.artifact.resolver.ArtifactResolver; 044import org.apache.maven.artifact.versioning.InvalidVersionSpecificationException; 045import org.apache.maven.artifact.versioning.VersionRange; 046import org.apache.maven.enforcer.rule.api.EnforcerRuleException; 047import org.apache.maven.enforcer.rule.api.EnforcerRuleHelper; 048import org.apache.maven.execution.MavenSession; 049import org.apache.maven.lifecycle.Lifecycle; 050import org.apache.maven.lifecycle.LifecycleExecutionException; 051import org.apache.maven.lifecycle.LifecycleExecutor; 052import org.apache.maven.lifecycle.mapping.LifecycleMapping; 053import org.apache.maven.model.BuildBase; 054import org.apache.maven.model.Model; 055import org.apache.maven.model.Plugin; 056import org.apache.maven.model.Profile; 057import org.apache.maven.model.ReportPlugin; 058import org.apache.maven.plugin.InvalidPluginException; 059import org.apache.maven.plugin.MojoExecutionException; 060import org.apache.maven.plugin.PluginManager; 061import org.apache.maven.plugin.PluginManagerException; 062import org.apache.maven.plugin.PluginNotFoundException; 063import org.apache.maven.plugin.descriptor.PluginDescriptor; 064import org.apache.maven.plugin.logging.Log; 065import org.apache.maven.plugin.version.PluginVersionNotFoundException; 066import org.apache.maven.plugin.version.PluginVersionResolutionException; 067import org.apache.maven.plugins.enforcer.utils.EnforcerRuleUtils; 068import org.apache.maven.plugins.enforcer.utils.PluginWrapper; 069import org.apache.maven.project.MavenProject; 070import org.apache.maven.settings.Settings; 071import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluationException; 072import org.codehaus.plexus.component.repository.exception.ComponentLookupException; 073import org.codehaus.plexus.util.ReflectionUtils; 074import org.codehaus.plexus.util.StringUtils; 075import org.codehaus.plexus.util.xml.pull.XmlPullParserException; 076 077/** 078 * This rule will enforce that all plugins specified in the poms have a version declared. 079 * 080 * @author <a href="mailto:brianf@apache.org">Brian Fox</a> 081 * @version $Id: RequirePluginVersions.java 1496229 2013-06-24 21:43:56Z rfscholte $ 082 */ 083public class RequirePluginVersions 084 extends AbstractNonCacheableEnforcerRule 085{ 086 087 /** Don't allow the LATEST identifier. 088 * 089 * @deprecated the visibility will be reduced to private with the next major version 090 * @see {@link #setBanLatest(boolean)} 091 * @see {@link #isBanLatest()} 092 */ 093 public boolean banLatest = true; 094 095 /** Don't allow the RELEASE identifier. 096 * 097 * @deprecated the visibility will be reduced to private with the next major version 098 * @see {@link #setBanRelease(boolean)} 099 * @see {@link #isBanRelease()} 100 */ 101 public boolean banRelease = true; 102 103 /** Don't allow snapshot plugins. 104 * 105 * @deprecated the visibility will be reduced to private with the next major version 106 * @see {@link #setBanSnapshots(boolean)} 107 * @see {@link #isBanSnapshots()} 108 */ 109 public boolean banSnapshots = true; 110 111 /** Don't allow timestamp snapshot plugins. 112 * 113 * @deprecated the visibility will be reduced to private with the next major version 114 * @see {@link #setBanTimestamps(boolean)} 115 * @see {@link #isBanTimestamps()} 116 */ 117 public boolean banTimestamps = true; 118 119 /** 120 * The comma separated list of phases that should be used to find lifecycle plugin bindings. The default value is 121 * "clean,deploy,site". 122 * 123 * @deprecated the visibility will be reduced to private with the next major version 124 * @see {@link #setPhases(String)} 125 * @see {@link #getPhases()} 126 */ 127 public String phases = "clean,deploy,site"; 128 129 /** 130 * Additional plugins to enforce have versions. These are plugins that may not be in the poms but are used anyway, 131 * like help, eclipse etc. <br> 132 * The plugins should be specified in the form: <code>group:artifactId</code>. 133 * 134 * @deprecated the visibility will be reduced to private with the next major version 135 * @see {@link #setAdditionalPlugins(List)} 136 * @see {@link #getAdditionalPlugins()} 137 */ 138 public List<String> additionalPlugins; 139 140 /** 141 * Plugins to skip for version enforcement. The plugins should be specified in the form: 142 * <code>group:artifactId</code>. NOTE: This is deprecated, use unCheckedPluginList instead. 143 * 144 * @deprecated the visibility will be reduced to private with the next major version 145 * @see {@link #setUnCheckedPlugins(List)} 146 * @see {@link #getUnCheckedPlugins()} 147 */ 148 public List unCheckedPlugins; 149 150 /** 151 * Same as unCheckedPlugins but as a comma list to better support properties. Sample form: 152 * <code>group:artifactId,group2:artifactId2</code> 153 * @since 1.0-beta-1 154 * 155 * @deprecated the visibility will be reduced to private with the next major version 156 * @see {@link #setUnCheckedPlugins(List)} 157 * @see {@link #getUnCheckedPlugins()} 158 */ 159 public String unCheckedPluginList; 160 161 /** The plugin manager. */ 162 private PluginManager pluginManager; 163 164 /** The phase to lifecycle map. */ 165 private Map<String, Lifecycle> phaseToLifecycleMap; 166 167 /** The lifecycles. */ 168 private Collection<Lifecycle> lifecycles; 169 170 /** The factory. */ 171 ArtifactFactory factory; 172 173 /** The resolver. */ 174 ArtifactResolver resolver; 175 176 /** The local. */ 177 ArtifactRepository local; 178 179 /** The remote repositories. */ 180 List<ArtifactRepository> remoteRepositories; 181 182 /** The log. */ 183 Log log; 184 185 /** The session. */ 186 MavenSession session; 187 188 /** The utils. */ 189 EnforcerRuleUtils utils; 190 191 /* 192 * (non-Javadoc) 193 * 194 * @see org.apache.maven.enforcer.rule.api.EnforcerRule#execute(org.apache.maven.enforcer.rule.api.EnforcerRuleHelper) 195 */ 196 public void execute( EnforcerRuleHelper helper ) 197 throws EnforcerRuleException 198 { 199 log = helper.getLog(); 200 201 MavenProject project; 202 try 203 { 204 // get the various expressions out of the helper. 205 206 project = (MavenProject) helper.evaluate( "${project}" ); 207 LifecycleExecutor life; 208 life = (LifecycleExecutor) helper.getComponent( LifecycleExecutor.class ); 209 210 // The lifecycle API changed from Maven 2 to 3 so we have to do a hack to figure 211 // out which one we're using. 212 Field field = ReflectionUtils.getFieldByNameIncludingSuperclasses( "defaultLifeCycles", life.getClass() ); 213 if ( field != null ) // Using Maven 3 214 { 215 Object defaultLifeCycles = ReflectionUtils.getValueIncludingSuperclasses( "defaultLifeCycles", life ); 216 Map lifecyclesMap = 217 (Map) ReflectionUtils.getValueIncludingSuperclasses( "lifecycles", defaultLifeCycles ); 218 lifecycles = lifecyclesMap.values(); 219 } 220 else // Using Maven 2 221 { 222 lifecycles = (Collection) ReflectionUtils.getValueIncludingSuperclasses( "lifecycles", life ); 223 } 224 225 session = (MavenSession) helper.evaluate( "${session}" ); 226 pluginManager = (PluginManager) helper.getComponent( PluginManager.class ); 227 factory = (ArtifactFactory) helper.getComponent( ArtifactFactory.class ); 228 resolver = (ArtifactResolver) helper.getComponent( ArtifactResolver.class ); 229 local = (ArtifactRepository) helper.evaluate( "${localRepository}" ); 230 remoteRepositories = project.getRemoteArtifactRepositories(); 231 232 utils = new EnforcerRuleUtils( helper ); 233 234 // get all the plugins that are bound to the specified lifecycles 235 Set<Plugin> allPlugins = getBoundPlugins( life, project, phases ); 236 237 // insert any additional plugins specified by the user. 238 allPlugins = addAdditionalPlugins( allPlugins, additionalPlugins ); 239 allPlugins.addAll( getProfilePlugins( project ) ); 240 241 242 // pull out any we should skip 243 allPlugins = 244 (Set) removeUncheckedPlugins( combineUncheckedPlugins( unCheckedPlugins, unCheckedPluginList ), 245 allPlugins ); 246 247 // there's nothing to do here 248 if ( allPlugins.isEmpty() ) 249 { 250 log.info( "No plugin bindings found." ); 251 return; 252 } 253 else 254 { 255 log.debug( "All Plugins in use: " + allPlugins ); 256 } 257 258 // get all the plugins that are mentioned in the pom (and parents) 259 List<PluginWrapper> pluginWrappers = getAllPluginEntries( project ); 260 261 // now look for the versions that aren't valid and add to a list. 262 List<Plugin> failures = new ArrayList<Plugin>(); 263 for ( Plugin plugin : allPlugins ) 264 { 265 if ( !hasValidVersionSpecified( helper, plugin, pluginWrappers ) ) 266 { 267 failures.add( plugin ); 268 } 269 } 270 271 // if anything was found, log it then append the optional message. 272 if ( !failures.isEmpty() ) 273 { 274 StringBuilder newMsg = new StringBuilder(); 275 newMsg.append( "Some plugins are missing valid versions:" ); 276 if ( banLatest || banRelease || banSnapshots || banTimestamps ) 277 { 278 newMsg.append( "(" ); 279 if ( banLatest ) 280 { 281 newMsg.append( "LATEST " ); 282 } 283 if ( banRelease ) 284 { 285 newMsg.append( "RELEASE " ); 286 } 287 if ( banSnapshots || banTimestamps ) 288 { 289 newMsg.append( "SNAPSHOT " ); 290 } 291 newMsg.append( "are not allowed )\n" ); 292 } 293 for ( Plugin plugin : failures ) 294 { 295 newMsg.append( plugin.getGroupId() ); 296 newMsg.append( ":" ); 297 newMsg.append( plugin.getArtifactId() ); 298 299 try 300 { 301 newMsg.append( ". \tThe version currently in use is " ); 302 303 Plugin currentPlugin = findCurrentPlugin( plugin, project ); 304 305 if ( currentPlugin != null ) 306 { 307 newMsg.append( currentPlugin.getVersion() ); 308 } 309 else 310 { 311 newMsg.append( "unknown" ); 312 } 313 } 314 catch ( Exception e ) 315 { 316 // lots can go wrong here. Don't allow any issues trying to 317 // determine the issue stop me 318 log.debug( "Exception while determining plugin Version.", e ); 319 newMsg.append( ". Unable to determine the plugin version." ); 320 } 321 newMsg.append( "\n" ); 322 } 323 String message = getMessage(); 324 if ( StringUtils.isNotEmpty( message ) ) 325 { 326 newMsg.append( message ); 327 } 328 329 throw new EnforcerRuleException( newMsg.toString() ); 330 } 331 } 332 catch ( ExpressionEvaluationException e ) 333 { 334 throw new EnforcerRuleException( "Unable to Evaluate an Expression:" + e.getLocalizedMessage() ); 335 } 336 catch ( ComponentLookupException e ) 337 { 338 throw new EnforcerRuleException( "Unable to lookup a component:" + e.getLocalizedMessage() ); 339 } 340 catch ( IllegalAccessException e ) 341 { 342 throw new EnforcerRuleException( e.getLocalizedMessage() ); 343 } 344 catch ( LifecycleExecutionException e ) 345 { 346 throw new EnforcerRuleException( e.getLocalizedMessage() ); 347 } 348 catch ( PluginNotFoundException e ) 349 { 350 throw new EnforcerRuleException( e.getLocalizedMessage() ); 351 } 352 catch ( ArtifactResolutionException e ) 353 { 354 throw new EnforcerRuleException( e.getLocalizedMessage() ); 355 } 356 catch ( ArtifactNotFoundException e ) 357 { 358 throw new EnforcerRuleException( e.getLocalizedMessage() ); 359 } 360 catch ( IOException e ) 361 { 362 throw new EnforcerRuleException( e.getLocalizedMessage() ); 363 } 364 catch ( XmlPullParserException e ) 365 { 366 throw new EnforcerRuleException( e.getLocalizedMessage() ); 367 } 368 catch ( MojoExecutionException e ) 369 { 370 throw new EnforcerRuleException( e.getLocalizedMessage() ); 371 } 372 } 373 374 /** 375 * Remove the plugins that the user doesn't want to check. 376 * 377 * @param uncheckedPlugins 378 * @param plugins 379 * @throws MojoExecutionException 380 * @return 381 */ 382 public Collection<Plugin> removeUncheckedPlugins( Collection<String> uncheckedPlugins, Collection<Plugin> plugins ) 383 throws MojoExecutionException 384 { 385 if ( uncheckedPlugins != null && !uncheckedPlugins.isEmpty() ) 386 { 387 for ( String pluginKey : uncheckedPlugins ) 388 { 389 Plugin plugin = parsePluginString( pluginKey, "UncheckedPlugins" ); 390 plugins.remove( plugin ); 391 } 392 } 393 return plugins; 394 } 395 396 /** 397 * Combines the old Collection with the new comma separated list. 398 * @param uncheckedPlugins 399 * @param uncheckedPluginsList 400 * @return 401 */ 402 public Collection<String> combineUncheckedPlugins( Collection<String> uncheckedPlugins, String uncheckedPluginsList ) 403 { 404 //if the comma list is empty, then there's nothing to do here. 405 if ( StringUtils.isNotEmpty( uncheckedPluginsList ) ) 406 { 407 //make sure there is a collection to add to. 408 if ( uncheckedPlugins == null ) 409 { 410 uncheckedPlugins = new HashSet<String>(); 411 } 412 else if ( !uncheckedPlugins.isEmpty() && log != null ) 413 { 414 log.warn( "The parameter 'unCheckedPlugins' is deprecated. Use 'unCheckedPluginList' instead" ); 415 } 416 417 uncheckedPlugins.addAll( Arrays.asList( uncheckedPluginsList.split( "," ) ) ); 418 } 419 return uncheckedPlugins; 420 } 421 422 /** 423 * Add the additional plugins if they don't exist yet. 424 * 425 * @param existing the existing 426 * @param additional the additional 427 * @return the sets the 428 * @throws MojoExecutionException the mojo execution exception 429 */ 430 public Set<Plugin> addAdditionalPlugins( Set<Plugin> existing, List<String> additional ) 431 throws MojoExecutionException 432 { 433 if ( additional != null ) 434 { 435 for ( String pluginString : additional ) 436 { 437 Plugin plugin = parsePluginString( pluginString, "AdditionalPlugins" ); 438 439 if ( existing == null ) 440 { 441 existing = new HashSet<Plugin>(); 442 existing.add( plugin ); 443 } 444 else if ( !existing.contains( plugin ) ) 445 { 446 existing.add( plugin ); 447 } 448 } 449 } 450 return existing; 451 } 452 453 /** 454 * Helper method to parse and inject a Plugin. 455 * 456 * @param pluginString 457 * @param field 458 * @throws MojoExecutionException 459 * @return the plugin 460 */ 461 protected Plugin parsePluginString( String pluginString, String field ) 462 throws MojoExecutionException 463 { 464 if ( pluginString != null ) 465 { 466 String[] pluginStrings = pluginString.split( ":" ); 467 if ( pluginStrings.length == 2 ) 468 { 469 Plugin plugin = new Plugin(); 470 plugin.setGroupId( StringUtils.strip( pluginStrings[0] ) ); 471 plugin.setArtifactId( StringUtils.strip( pluginStrings[1] ) ); 472 473 return plugin; 474 } 475 else 476 { 477 throw new MojoExecutionException( "Invalid " + field + " string: " + pluginString ); 478 } 479 } 480 else 481 { 482 throw new MojoExecutionException( "Invalid " + field + " string: " + pluginString ); 483 } 484 485 } 486 487 /** 488 * Finds the plugins that are listed in active profiles. 489 * 490 * @param project the project 491 * @return the profile plugins 492 */ 493 public Set<Plugin> getProfilePlugins( MavenProject project ) 494 { 495 Set<Plugin> result = new HashSet<Plugin>(); 496 @SuppressWarnings( "unchecked" ) 497 List<Profile> profiles = project.getActiveProfiles(); 498 if ( profiles != null && !profiles.isEmpty() ) 499 { 500 for ( Profile p : profiles ) 501 { 502 BuildBase b = p.getBuild(); 503 if ( b != null ) 504 { 505 @SuppressWarnings( "unchecked" ) 506 List<Plugin> plugins = b.getPlugins(); 507 if ( plugins != null ) 508 { 509 result.addAll( plugins ); 510 } 511 } 512 } 513 } 514 return result; 515 } 516 517 /** 518 * Given a plugin, this will retrieve the matching plugin artifact from the model. 519 * 520 * @param plugin plugin to lookup 521 * @param project project to search 522 * @return matching plugin, <code>null</code> if not found. 523 */ 524 protected Plugin findCurrentPlugin( Plugin plugin, MavenProject project ) 525 { 526 Plugin found = null; 527 try 528 { 529 Model model = project.getModel(); 530 @SuppressWarnings( "unchecked" ) 531 Map<String, Plugin> plugins = model.getBuild().getPluginsAsMap(); 532 found = plugins.get( plugin.getKey() ); 533 } 534 catch ( NullPointerException e ) 535 { 536 // nothing to do here 537 } 538 539 if ( found == null ) 540 { 541 found = resolvePlugin( plugin, project ); 542 } 543 544 return found; 545 } 546 547 /** 548 * Resolve plugin. 549 * 550 * @param plugin the plugin 551 * @param project the project 552 * @return the plugin 553 */ 554 protected Plugin resolvePlugin( Plugin plugin, MavenProject project ) 555 { 556 557 @SuppressWarnings( "unchecked" ) 558 List<ArtifactRepository> pluginRepositories = project.getPluginArtifactRepositories(); 559 Artifact artifact = 560 factory.createPluginArtifact( plugin.getGroupId(), plugin.getArtifactId(), 561 VersionRange.createFromVersion( "LATEST" ) ); 562 563 try 564 { 565 this.resolver.resolve( artifact, pluginRepositories, this.local ); 566 plugin.setVersion( artifact.getVersion() ); 567 } 568 catch ( ArtifactResolutionException e ) 569 { 570 } 571 catch ( ArtifactNotFoundException e ) 572 { 573 } 574 575 return plugin; 576 } 577 578 /** 579 * Gets the plugins that are bound to the defined phases. This does not find plugins bound in the pom to a phase 580 * later than the plugin is executing. 581 * 582 * @param life the life 583 * @param project the project 584 * @param thePhases the the phases 585 * @return the bound plugins 586 * @throws PluginNotFoundException the plugin not found exception 587 * @throws LifecycleExecutionException the lifecycle execution exception 588 * @throws IllegalAccessException the illegal access exception 589 */ 590 protected Set<Plugin> getBoundPlugins( LifecycleExecutor life, MavenProject project, String thePhases ) 591 throws PluginNotFoundException, LifecycleExecutionException, IllegalAccessException 592 { 593 594 Set<Plugin> allPlugins = new HashSet<Plugin>(); 595 596 // lookup the bindings for all the passed in phases 597 String[] lifecyclePhases = thePhases.split( "," ); 598 for ( int i = 0; i < lifecyclePhases.length; i++ ) 599 { 600 String lifecyclePhase = lifecyclePhases[i]; 601 if ( StringUtils.isNotEmpty( lifecyclePhase ) ) 602 { 603 try 604 { 605 Lifecycle lifecycle = getLifecycleForPhase( lifecyclePhase ); 606 allPlugins.addAll( getAllPlugins( project, lifecycle ) ); 607 } 608 catch ( BuildFailureException e ) 609 { 610 // i'm going to swallow this because the 611 // user may have declared a phase that 612 // doesn't exist for every module. 613 } 614 } 615 } 616 return allPlugins; 617 } 618 619 /* 620 * Checks to see if the version is specified for the plugin. Can optionally ban "RELEASE" or "LATEST" even if 621 * specified. 622 */ 623 /** 624 * Checks for valid version specified. 625 * 626 * @param helper the helper 627 * @param source the source 628 * @param pluginWrappers the plugins 629 * @return true, if successful 630 */ 631 protected boolean hasValidVersionSpecified( EnforcerRuleHelper helper, Plugin source, List<PluginWrapper> pluginWrappers ) 632 { 633 boolean found = false; 634 boolean status = false; 635 for ( PluginWrapper plugin : pluginWrappers ) 636 { 637 // find the matching plugin entry 638 if ( source.getArtifactId().equals( plugin.getArtifactId() ) 639 && source.getGroupId().equals( plugin.getGroupId() ) ) 640 { 641 found = true; 642 // found the entry. now see if the version is specified 643 String version = plugin.getVersion(); 644 try 645 { 646 version = (String) helper.evaluate( version ); 647 } 648 catch ( ExpressionEvaluationException e ) 649 { 650 return false; 651 } 652 653 if ( StringUtils.isNotEmpty( version ) && !StringUtils.isWhitespace( version ) ) 654 { 655 656 if ( banRelease && version.equals( "RELEASE" ) ) 657 { 658 return false; 659 } 660 661 if ( banLatest && version.equals( "LATEST" ) ) 662 { 663 return false; 664 } 665 666 if ( banSnapshots && isSnapshot( version ) ) 667 { 668 return false; 669 } 670 // the version was specified and not 671 // banned. It's ok. Keep looking through the list to make 672 // sure it's not using a banned version somewhere else. 673 674 status = true; 675 676 if ( !banRelease && !banLatest && !banSnapshots ) 677 { 678 // no need to keep looking 679 break; 680 } 681 } 682 } 683 } 684 if ( !found ) 685 { 686 log.debug( "plugin " + source.getGroupId() + ":" + source.getArtifactId() + " not found" ); 687 } 688 return status; 689 } 690 691 /** 692 * Checks if is snapshot. 693 * 694 * @param baseVersion the base version 695 * @return true, if is snapshot 696 */ 697 protected boolean isSnapshot( String baseVersion ) 698 { 699 if ( banTimestamps ) 700 { 701 return Artifact.VERSION_FILE_PATTERN.matcher( baseVersion ).matches() 702 || baseVersion.endsWith( Artifact.SNAPSHOT_VERSION ); 703 } 704 else 705 { 706 return baseVersion.endsWith( Artifact.SNAPSHOT_VERSION ); 707 } 708 } 709 710 /* 711 * Uses borrowed lifecycle code to get a list of all plugins bound to the lifecycle. 712 */ 713 /** 714 * Gets the all plugins. 715 * 716 * @param project the project 717 * @param lifecycle the lifecycle 718 * @return the all plugins 719 * @throws PluginNotFoundException the plugin not found exception 720 * @throws LifecycleExecutionException the lifecycle execution exception 721 */ 722 @SuppressWarnings( "unchecked" ) 723 private Set<Plugin> getAllPlugins( MavenProject project, Lifecycle lifecycle ) 724 throws PluginNotFoundException, LifecycleExecutionException 725 726 { 727 log.debug( "RequirePluginVersions.getAllPlugins:" ); 728 729 Set<Plugin> plugins = new HashSet<Plugin>(); 730 // first, bind those associated with the packaging 731 Map mappings = findMappingsForLifecycle( project, lifecycle ); 732 733 Iterator iter = mappings.entrySet().iterator(); 734 while ( iter.hasNext() ) 735 { 736 Entry entry = (Entry) iter.next(); 737 log.debug( " lifecycleMapping = " + entry.getKey() ); 738 String pluginsForLifecycle = (String) entry.getValue(); 739 log.debug( " plugins = " + pluginsForLifecycle ); 740 if ( StringUtils.isNotEmpty( pluginsForLifecycle ) ) 741 { 742 String pluginList[] = pluginsForLifecycle.split( "," ); 743 for ( String plugin : pluginList ) 744 { 745 plugin = StringUtils.strip( plugin ); 746 log.debug( " plugin = " + plugin ); 747 String tokens[] = plugin.split( ":" ); 748 log.debug( " GAV = " + Arrays.asList( tokens ) ); 749 750 Plugin p = new Plugin(); 751 p.setGroupId( tokens[0] ); 752 p.setArtifactId( tokens[1] ); 753 plugins.add( p ); 754 } 755 } 756 } 757 758 List<String> mojos = findOptionalMojosForLifecycle( project, lifecycle ); 759 for ( String value : mojos ) 760 { 761 String tokens[] = value.split( ":" ); 762 763 Plugin plugin = new Plugin(); 764 plugin.setGroupId( tokens[0] ); 765 plugin.setArtifactId( tokens[1] ); 766 plugins.add( plugin ); 767 } 768 769 plugins.addAll( project.getBuildPlugins() ); 770 771 return plugins; 772 } 773 774 /* 775 * NOTE: All the code following this point was scooped from the DefaultLifecycleExecutor. There must be a better way 776 * but for now it should work. 777 */ 778 /** 779 * Gets the phase to lifecycle map. 780 * 781 * @return the phase to lifecycle map 782 * @throws LifecycleExecutionException the lifecycle execution exception 783 */ 784 public Map<String, Lifecycle> getPhaseToLifecycleMap() 785 throws LifecycleExecutionException 786 { 787 if ( phaseToLifecycleMap == null ) 788 { 789 phaseToLifecycleMap = new HashMap<String, Lifecycle>(); 790 791 for ( Lifecycle lifecycle : lifecycles ) 792 { 793 @SuppressWarnings( "unchecked" ) 794 List<String> phases = lifecycle.getPhases(); 795 for ( String phase : phases ) 796 { 797 if ( phaseToLifecycleMap.containsKey( phase ) ) 798 { 799 Lifecycle prevLifecycle = (Lifecycle) phaseToLifecycleMap.get( phase ); 800 throw new LifecycleExecutionException( "Phase '" + phase 801 + "' is defined in more than one lifecycle: '" + lifecycle.getId() + "' and '" 802 + prevLifecycle.getId() + "'" ); 803 } 804 else 805 { 806 phaseToLifecycleMap.put( phase, lifecycle ); 807 } 808 } 809 } 810 } 811 return phaseToLifecycleMap; 812 } 813 814 /** 815 * Gets the lifecycle for phase. 816 * 817 * @param phase the phase 818 * @return the lifecycle for phase 819 * @throws BuildFailureException the build failure exception 820 * @throws LifecycleExecutionException the lifecycle execution exception 821 */ 822 private Lifecycle getLifecycleForPhase( String phase ) 823 throws BuildFailureException, LifecycleExecutionException 824 { 825 Lifecycle lifecycle = (Lifecycle) getPhaseToLifecycleMap().get( phase ); 826 827 if ( lifecycle == null ) 828 { 829 throw new BuildFailureException( "Unable to find lifecycle for phase '" + phase + "'" ); 830 } 831 return lifecycle; 832 } 833 834 /** 835 * Find mappings for lifecycle. 836 * 837 * @param project the project 838 * @param lifecycle the lifecycle 839 * @return the map 840 * @throws LifecycleExecutionException the lifecycle execution exception 841 * @throws PluginNotFoundException the plugin not found exception 842 */ 843 private Map findMappingsForLifecycle( MavenProject project, Lifecycle lifecycle ) 844 throws LifecycleExecutionException, PluginNotFoundException 845 { 846 String packaging = project.getPackaging(); 847 Map mappings = null; 848 849 LifecycleMapping m = 850 (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session.getSettings(), 851 session.getLocalRepository() ); 852 if ( m != null ) 853 { 854 mappings = m.getPhases( lifecycle.getId() ); 855 } 856 857 Map defaultMappings = lifecycle.getDefaultPhases(); 858 859 if ( mappings == null ) 860 { 861 try 862 { 863 m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging ); 864 mappings = m.getPhases( lifecycle.getId() ); 865 } 866 catch ( ComponentLookupException e ) 867 { 868 if ( defaultMappings == null ) 869 { 870 throw new LifecycleExecutionException( "Cannot find lifecycle mapping for packaging: \'" 871 + packaging + "\'.", e ); 872 } 873 } 874 } 875 876 if ( mappings == null ) 877 { 878 if ( defaultMappings == null ) 879 { 880 throw new LifecycleExecutionException( "Cannot find lifecycle mapping for packaging: \'" + packaging 881 + "\', and there is no default" ); 882 } 883 else 884 { 885 mappings = defaultMappings; 886 } 887 } 888 889 return mappings; 890 } 891 892 /** 893 * Find optional mojos for lifecycle. 894 * 895 * @param project the project 896 * @param lifecycle the lifecycle 897 * @return the list 898 * @throws LifecycleExecutionException the lifecycle execution exception 899 * @throws PluginNotFoundException the plugin not found exception 900 */ 901 @SuppressWarnings( "unchecked" ) 902 private List<String> findOptionalMojosForLifecycle( MavenProject project, Lifecycle lifecycle ) 903 throws LifecycleExecutionException, PluginNotFoundException 904 { 905 String packaging = project.getPackaging(); 906 List<String> optionalMojos = null; 907 908 LifecycleMapping m = 909 (LifecycleMapping) findExtension( project, LifecycleMapping.ROLE, packaging, session.getSettings(), 910 session.getLocalRepository() ); 911 912 if ( m != null ) 913 { 914 optionalMojos = m.getOptionalMojos( lifecycle.getId() ); 915 } 916 917 if ( optionalMojos == null ) 918 { 919 try 920 { 921 m = (LifecycleMapping) session.lookup( LifecycleMapping.ROLE, packaging ); 922 optionalMojos = m.getOptionalMojos( lifecycle.getId() ); 923 } 924 catch ( ComponentLookupException e ) 925 { 926 log.debug( "Error looking up lifecycle mapping to retrieve optional mojos. Lifecycle ID: " 927 + lifecycle.getId() + ". Error: " + e.getMessage(), e ); 928 } 929 } 930 931 if ( optionalMojos == null ) 932 { 933 optionalMojos = Collections.emptyList(); 934 } 935 936 return optionalMojos; 937 } 938 939 /** 940 * Find extension. 941 * 942 * @param project the project 943 * @param role the role 944 * @param roleHint the role hint 945 * @param settings the settings 946 * @param localRepository the local repository 947 * @return the object 948 * @throws LifecycleExecutionException the lifecycle execution exception 949 * @throws PluginNotFoundException the plugin not found exception 950 */ 951 private Object findExtension( MavenProject project, String role, String roleHint, Settings settings, 952 ArtifactRepository localRepository ) 953 throws LifecycleExecutionException, PluginNotFoundException 954 { 955 Object pluginComponent = null; 956 957 @SuppressWarnings( "unchecked" ) 958 List<Plugin> buildPlugins = project.getBuildPlugins(); 959 for ( Plugin plugin : buildPlugins ) 960 { 961 if ( plugin.isExtensions() ) 962 { 963 verifyPlugin( plugin, project, settings, localRepository ); 964 965 // TODO: if moved to the plugin manager we 966 // already have the descriptor from above 967 // and so do can lookup the container 968 // directly 969 try 970 { 971 pluginComponent = pluginManager.getPluginComponent( plugin, role, roleHint ); 972 973 if ( pluginComponent != null ) 974 { 975 break; 976 } 977 } 978 catch ( ComponentLookupException e ) 979 { 980 log.debug( "Unable to find the lifecycle component in the extension", e ); 981 } 982 catch ( PluginManagerException e ) 983 { 984 throw new LifecycleExecutionException( "Error getting extensions from the plugin '" 985 + plugin.getKey() + "': " + e.getMessage(), e ); 986 } 987 } 988 } 989 return pluginComponent; 990 } 991 992 /** 993 * Verify plugin. 994 * 995 * @param plugin the plugin 996 * @param project the project 997 * @param settings the settings 998 * @param localRepository the local repository 999 * @return the plugin descriptor 1000 * @throws LifecycleExecutionException the lifecycle execution exception 1001 * @throws PluginNotFoundException the plugin not found exception 1002 */ 1003 private PluginDescriptor verifyPlugin( Plugin plugin, MavenProject project, Settings settings, 1004 ArtifactRepository localRepository ) 1005 throws LifecycleExecutionException, PluginNotFoundException 1006 { 1007 PluginDescriptor pluginDescriptor; 1008 try 1009 { 1010 pluginDescriptor = pluginManager.verifyPlugin( plugin, project, settings, localRepository ); 1011 } 1012 catch ( PluginManagerException e ) 1013 { 1014 throw new LifecycleExecutionException( "Internal error in the plugin manager getting plugin '" 1015 + plugin.getKey() + "': " + e.getMessage(), e ); 1016 } 1017 catch ( PluginVersionResolutionException e ) 1018 { 1019 throw new LifecycleExecutionException( e.getMessage(), e ); 1020 } 1021 catch ( InvalidVersionSpecificationException e ) 1022 { 1023 throw new LifecycleExecutionException( e.getMessage(), e ); 1024 } 1025 catch ( InvalidPluginException e ) 1026 { 1027 throw new LifecycleExecutionException( e.getMessage(), e ); 1028 } 1029 catch ( ArtifactNotFoundException e ) 1030 { 1031 throw new LifecycleExecutionException( e.getMessage(), e ); 1032 } 1033 catch ( ArtifactResolutionException e ) 1034 { 1035 throw new LifecycleExecutionException( e.getMessage(), e ); 1036 } 1037 catch ( PluginVersionNotFoundException e ) 1038 { 1039 throw new LifecycleExecutionException( e.getMessage(), e ); 1040 } 1041 return pluginDescriptor; 1042 } 1043 1044 /** 1045 * Gets all plugin entries in build.plugins, build.pluginManagement.plugins, profile.build.plugins, reporting and 1046 * profile.reporting in this project and all parents 1047 * 1048 * @param project the project 1049 * @return the all plugin entries wrapped in a PluginWrapper Object 1050 * @throws ArtifactResolutionException the artifact resolution exception 1051 * @throws ArtifactNotFoundException the artifact not found exception 1052 * @throws IOException Signals that an I/O exception has occurred. 1053 * @throws XmlPullParserException the xml pull parser exception 1054 */ 1055 protected List<PluginWrapper> getAllPluginEntries( MavenProject project ) 1056 throws ArtifactResolutionException, ArtifactNotFoundException, IOException, XmlPullParserException 1057 { 1058 List<PluginWrapper> plugins = new ArrayList<PluginWrapper>(); 1059 // get all the pom models 1060 1061 String pomName = null; 1062 try 1063 { 1064 pomName = project.getFile().getName(); 1065 } 1066 catch ( Exception e ) 1067 { 1068 pomName = "pom.xml"; 1069 } 1070 List<Model> models = 1071 utils.getModelsRecursively( project.getGroupId(), project.getArtifactId(), project.getVersion(), 1072 new File( project.getBasedir(), pomName ) ); 1073 1074 // now find all the plugin entries, either in 1075 // build.plugins or build.pluginManagement.plugins, profiles.plugins and reporting 1076 for ( Model model : models ) 1077 { 1078 try 1079 { 1080 List<Plugin> modelPlugins = model.getBuild().getPlugins(); 1081 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), model.getId() + ".build.plugins" ) ); 1082 } 1083 catch ( NullPointerException e ) 1084 { 1085 // guess there are no plugins here. 1086 } 1087 1088 try 1089 { 1090 List<ReportPlugin> modelReportPlugins = model.getReporting().getPlugins(); 1091 // add the reporting plugins 1092 plugins.addAll( PluginWrapper.addAll( utils.resolveReportPlugins( modelReportPlugins ), model.getId() + ".reporting" ) ); 1093 } 1094 catch ( NullPointerException e ) 1095 { 1096 // guess there are no plugins here. 1097 } 1098 1099 try 1100 { 1101 List<Plugin> modelPlugins = model.getBuild().getPluginManagement().getPlugins(); 1102 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), 1103 model.getId() + ".build.pluginManagement.plugins" ) ); 1104 } 1105 catch ( NullPointerException e ) 1106 { 1107 // guess there are no plugins here. 1108 } 1109 1110 // Add plugins in profiles 1111 @SuppressWarnings( "unchecked" ) 1112 List<Profile> profiles = model.getProfiles(); 1113 for ( Profile profile : profiles ) 1114 { 1115 try 1116 { 1117 List<Plugin> modelPlugins = profile.getBuild().getPlugins(); 1118 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), model.getId() 1119 + ".profiles.profile[" + profile.getId() + "].build.plugins" ) ); 1120 } 1121 catch ( NullPointerException e ) 1122 { 1123 // guess there are no plugins here. 1124 } 1125 1126 try 1127 { 1128 List<ReportPlugin> modelReportPlugins = profile.getReporting().getPlugins(); 1129 // add the reporting plugins 1130 plugins.addAll( PluginWrapper.addAll( utils.resolveReportPlugins( modelReportPlugins ), model.getId() 1131 + "profile[" + profile.getId() + "].reporting.plugins" ) ); 1132 } 1133 catch ( NullPointerException e ) 1134 { 1135 // guess there are no plugins here. 1136 } 1137 try 1138 { 1139 List<Plugin> modelPlugins = profile.getBuild().getPluginManagement().getPlugins(); 1140 plugins.addAll( PluginWrapper.addAll( utils.resolvePlugins( modelPlugins ), 1141 model.getId() + "profile[" + profile.getId() 1142 + "].build.pluginManagement.plugins" ) ); 1143 } 1144 catch ( NullPointerException e ) 1145 { 1146 // guess there are no plugins here. 1147 } 1148 } 1149 } 1150 1151 return plugins; 1152 } 1153 1154 /** 1155 * Checks if is ban latest. 1156 * 1157 * @return the banLatest 1158 */ 1159 protected boolean isBanLatest() 1160 { 1161 return this.banLatest; 1162 } 1163 1164 /** 1165 * Sets the ban latest. 1166 * 1167 * @param theBanLatest the banLatest to set 1168 */ 1169 protected void setBanLatest( boolean theBanLatest ) 1170 { 1171 this.banLatest = theBanLatest; 1172 } 1173 1174 /** 1175 * Checks if is ban release. 1176 * 1177 * @return the banRelease 1178 */ 1179 protected boolean isBanRelease() 1180 { 1181 return this.banRelease; 1182 } 1183 1184 /** 1185 * Sets the ban release. 1186 * 1187 * @param theBanRelease the banRelease to set 1188 */ 1189 protected void setBanRelease( boolean theBanRelease ) 1190 { 1191 this.banRelease = theBanRelease; 1192 } 1193 1194 /** 1195 * Gets the utils. 1196 * 1197 * @return the utils 1198 */ 1199 protected EnforcerRuleUtils getUtils() 1200 { 1201 return this.utils; 1202 } 1203 1204 /** 1205 * Sets the utils. 1206 * 1207 * @param theUtils the utils to set 1208 */ 1209 protected void setUtils( EnforcerRuleUtils theUtils ) 1210 { 1211 this.utils = theUtils; 1212 } 1213 1214 /** 1215 * Checks if is ban snapshots. 1216 * 1217 * @return the banSnapshots 1218 */ 1219 public boolean isBanSnapshots() 1220 { 1221 return this.banSnapshots; 1222 } 1223 1224 /** 1225 * Sets the ban snapshots. 1226 * 1227 * @param theBanSnapshots the banSnapshots to set 1228 */ 1229 public void setBanSnapshots( boolean theBanSnapshots ) 1230 { 1231 this.banSnapshots = theBanSnapshots; 1232 } 1233 1234 /** 1235 * Checks if is ban timestamps. 1236 * 1237 * @return the banTimestamps 1238 */ 1239 public boolean isBanTimestamps() 1240 { 1241 return this.banTimestamps; 1242 } 1243 1244 /** 1245 * Sets the ban timestamps. 1246 * 1247 * @param theBanTimestamps the banTimestamps to set 1248 */ 1249 public void setBanTimestamps( boolean theBanTimestamps ) 1250 { 1251 this.banTimestamps = theBanTimestamps; 1252 } 1253 1254 public List getUnCheckedPlugins() 1255 { 1256 return unCheckedPlugins; 1257 } 1258 1259 public void setUnCheckedPlugins( List unCheckedPlugins ) 1260 { 1261 this.unCheckedPlugins = unCheckedPlugins; 1262 } 1263 1264 public final void setPhases( String phases ) 1265 { 1266 this.phases = phases; 1267 } 1268 1269 public final String getPhases() 1270 { 1271 return phases; 1272 } 1273 1274 public final void setAdditionalPlugins( List<String> additionalPlugins ) 1275 { 1276 this.additionalPlugins = additionalPlugins; 1277 } 1278 1279 public final List<String> getAdditionalPlugins() 1280 { 1281 return additionalPlugins; 1282 } 1283}