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