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