001package org.apache.maven.lifecycle.internal; 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 org.apache.maven.lifecycle.DefaultLifecycles; 023import org.apache.maven.lifecycle.LifeCyclePluginAnalyzer; 024import org.apache.maven.lifecycle.Lifecycle; 025import org.apache.maven.lifecycle.mapping.LifecycleMapping; 026import org.apache.maven.lifecycle.mapping.LifecycleMojo; 027import org.apache.maven.lifecycle.mapping.LifecyclePhase; 028import org.apache.maven.model.Plugin; 029import org.apache.maven.model.PluginExecution; 030import org.codehaus.plexus.component.annotations.Component; 031import org.codehaus.plexus.component.annotations.Requirement; 032import org.codehaus.plexus.logging.Logger; 033import org.codehaus.plexus.util.StringUtils; 034 035import java.util.ArrayList; 036import java.util.Collections; 037import java.util.Comparator; 038import java.util.HashSet; 039import java.util.LinkedHashMap; 040import java.util.List; 041import java.util.Map; 042import java.util.Set; 043 044/** 045 * @since 3.0 046 * @author Benjamin Bentmann 047 * @author Jason van Zyl 048 * @author jdcasey 049 * @author Kristian Rosenvold (extracted class only) 050 * <p/> 051 * NOTE: This class is not part of any public api and can be changed or deleted without prior notice. 052 */ 053@Component( role = LifeCyclePluginAnalyzer.class ) 054public class DefaultLifecyclePluginAnalyzer 055 implements LifeCyclePluginAnalyzer 056{ 057 058 @Requirement( role = LifecycleMapping.class ) 059 private Map<String, LifecycleMapping> lifecycleMappings; 060 061 @Requirement 062 private DefaultLifecycles defaultLifeCycles; 063 064 @Requirement 065 private Logger logger; 066 067 public DefaultLifecyclePluginAnalyzer() 068 { 069 } 070 071 // These methods deal with construction intact Plugin object that look like they come from a standard 072 // <plugin/> block in a Maven POM. We have to do some wiggling to pull the sources of information 073 // together and this really shows the problem of constructing a sensible default configuration but 074 // it's all encapsulated here so it appears normalized to the POM builder. 075 076 // We are going to take the project packaging and find all plugin in the default lifecycle and create 077 // fully populated Plugin objects, including executions with goals and default configuration taken 078 // from the plugin.xml inside a plugin. 079 // 080 081 public Set<Plugin> getPluginsBoundByDefaultToAllLifecycles( String packaging ) 082 { 083 if ( logger.isDebugEnabled() ) 084 { 085 logger.debug( "Looking up lifecyle mappings for packaging " + packaging + " from " 086 + Thread.currentThread().getContextClassLoader() ); 087 } 088 089 LifecycleMapping lifecycleMappingForPackaging = lifecycleMappings.get( packaging ); 090 091 if ( lifecycleMappingForPackaging == null ) 092 { 093 return null; 094 } 095 096 Map<Plugin, Plugin> plugins = new LinkedHashMap<>(); 097 098 for ( Lifecycle lifecycle : getOrderedLifecycles() ) 099 { 100 org.apache.maven.lifecycle.mapping.Lifecycle lifecycleConfiguration = 101 lifecycleMappingForPackaging.getLifecycles().get( lifecycle.getId() ); 102 103 Map<String, LifecyclePhase> phaseToGoalMapping = null; 104 105 if ( lifecycleConfiguration != null ) 106 { 107 phaseToGoalMapping = lifecycleConfiguration.getLifecyclePhases(); 108 } 109 else if ( lifecycle.getDefaultLifecyclePhases() != null ) 110 { 111 phaseToGoalMapping = lifecycle.getDefaultLifecyclePhases(); 112 } 113 114 if ( phaseToGoalMapping != null ) 115 { 116 for ( Map.Entry<String, LifecyclePhase> goalsForLifecyclePhase : phaseToGoalMapping.entrySet() ) 117 { 118 String phase = goalsForLifecyclePhase.getKey(); 119 LifecyclePhase goals = goalsForLifecyclePhase.getValue(); 120 if ( goals != null ) 121 { 122 parseLifecyclePhaseDefinitions( plugins, phase, goals ); 123 } 124 } 125 } 126 } 127 128 return plugins.keySet(); 129 } 130 131 private List<Lifecycle> getOrderedLifecycles() 132 { 133 // NOTE: The lifecycle order can affect implied execution ids so we better be deterministic. 134 135 List<Lifecycle> lifecycles = new ArrayList<>( defaultLifeCycles.getLifeCycles() ); 136 137 Collections.sort( lifecycles, new Comparator<Lifecycle>() 138 { 139 140 public int compare( Lifecycle l1, Lifecycle l2 ) 141 { 142 return l1.getId().compareTo( l2.getId() ); 143 } 144 145 } ); 146 147 return lifecycles; 148 } 149 150 private void parseLifecyclePhaseDefinitions( Map<Plugin, Plugin> plugins, String phase, LifecyclePhase goals ) 151 { 152 List<LifecycleMojo> mojos = goals.getMojos(); 153 if ( mojos != null ) 154 { 155 156 for ( int i = 0; i < mojos.size(); i++ ) 157 { 158 LifecycleMojo mojo = mojos.get( i ); 159 160 GoalSpec gs = parseGoalSpec( mojo.getGoal() ); 161 162 if ( gs == null ) 163 { 164 logger.warn( "Ignored invalid goal specification '" + mojo.getGoal() 165 + "' from lifecycle mapping for phase " + phase ); 166 continue; 167 } 168 169 Plugin plugin = new Plugin(); 170 plugin.setGroupId( gs.groupId ); 171 plugin.setArtifactId( gs.artifactId ); 172 plugin.setVersion( gs.version ); 173 174 Plugin existing = plugins.get( plugin ); 175 if ( existing != null ) 176 { 177 if ( existing.getVersion() == null ) 178 { 179 existing.setVersion( plugin.getVersion() ); 180 } 181 plugin = existing; 182 } 183 else 184 { 185 plugins.put( plugin, plugin ); 186 } 187 188 PluginExecution execution = new PluginExecution(); 189 execution.setId( getExecutionId( plugin, gs.goal ) ); 190 execution.setPhase( phase ); 191 execution.setPriority( i - mojos.size() ); 192 execution.getGoals().add( gs.goal ); 193 execution.setConfiguration( mojo.getConfiguration() ); 194 195 plugin.setDependencies( mojo.getDependencies() ); 196 plugin.getExecutions().add( execution ); 197 } 198 } 199 } 200 201 private GoalSpec parseGoalSpec( String goalSpec ) 202 { 203 GoalSpec gs = new GoalSpec(); 204 205 String[] p = StringUtils.split( goalSpec.trim(), ":" ); 206 207 if ( p.length == 3 ) 208 { 209 // <groupId>:<artifactId>:<goal> 210 gs.groupId = p[0]; 211 gs.artifactId = p[1]; 212 gs.goal = p[2]; 213 } 214 else if ( p.length == 4 ) 215 { 216 // <groupId>:<artifactId>:<version>:<goal> 217 gs.groupId = p[0]; 218 gs.artifactId = p[1]; 219 gs.version = p[2]; 220 gs.goal = p[3]; 221 } 222 else 223 { 224 // invalid 225 gs = null; 226 } 227 228 return gs; 229 } 230 231 private String getExecutionId( Plugin plugin, String goal ) 232 { 233 Set<String> existingIds = new HashSet<>(); 234 for ( PluginExecution execution : plugin.getExecutions() ) 235 { 236 existingIds.add( execution.getId() ); 237 } 238 239 String base = "default-" + goal; 240 String id = base; 241 242 for ( int index = 1; existingIds.contains( id ); index++ ) 243 { 244 id = base + '-' + index; 245 } 246 247 return id; 248 } 249 250 static class GoalSpec 251 { 252 253 String groupId; 254 255 String artifactId; 256 257 String version; 258 259 String goal; 260 261 } 262 263}