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