001/* 002 * Copyright 2007 The Kuali Foundation 003 * 004 * Licensed under the Educational Community License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.opensource.org/licenses/ecl2.php 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.kualigan.maven.plugins.api; 017 018import org.apache.commons.cli.CommandLine; 019import org.apache.commons.cli.OptionBuilder; 020import org.apache.commons.cli.Options; 021import org.apache.commons.cli.PosixParser; 022 023import org.apache.maven.archetype.Archetype; 024import org.apache.maven.artifact.repository.ArtifactRepository; 025import org.apache.maven.artifact.repository.ArtifactRepositoryFactory; 026import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy; 027import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout; 028 029import org.apache.maven.plugin.AbstractMojo; 030import org.apache.maven.plugin.MojoExecutionException; 031 032import org.apache.maven.shared.invoker.DefaultInvocationRequest; 033import org.apache.maven.shared.invoker.DefaultInvoker; 034import org.apache.maven.shared.invoker.InvocationOutputHandler; 035import org.apache.maven.shared.invoker.InvocationRequest; 036import org.apache.maven.shared.invoker.InvocationResult; 037import org.apache.maven.shared.invoker.Invoker; 038import org.apache.maven.shared.invoker.InvokerLogger; 039import org.apache.maven.shared.invoker.MavenInvocationException; 040 041import org.apache.maven.project.MavenProject; 042import org.codehaus.plexus.component.annotations.Component; 043import org.codehaus.plexus.component.annotations.Requirement; 044import org.codehaus.plexus.components.interactivity.Prompter; 045import org.codehaus.plexus.util.FileUtils; 046import org.codehaus.plexus.util.IOUtil; 047import org.codehaus.plexus.util.StringUtils; 048import org.codehaus.plexus.util.cli.CommandLineUtils; 049 050import java.io.File; 051import java.io.FileWriter; 052import java.io.InputStream; 053import java.util.ArrayList; 054import java.util.HashMap; 055import java.util.List; 056import java.util.Map; 057import java.util.Properties; 058import java.util.StringTokenizer; 059 060/** 061 * Creates a maven overlay for the given KFS prototype 062 * 063 * @author Leo Przybylski (przybyls [at] arizona.edu) 064 */ 065@Component(role = org.kualigan.maven.plugins.api.OverlayHelper.class, hint="default") 066public class DefaultOverlayHelper implements OverlayHelper { 067 public static final String ROLE_HINT = "default"; 068 069 private static final Options OPTIONS = new Options(); 070 071 private static final char SET_SYSTEM_PROPERTY = 'D'; 072 073 private static final char OFFLINE = 'o'; 074 075 private static final char REACTOR = 'r'; 076 077 private static final char QUIET = 'q'; 078 079 private static final char DEBUG = 'X'; 080 081 private static final char ERRORS = 'e'; 082 083 private static final char NON_RECURSIVE = 'N'; 084 085 private static final char UPDATE_SNAPSHOTS = 'U'; 086 087 private static final char ACTIVATE_PROFILES = 'P'; 088 089 private static final String FORCE_PLUGIN_UPDATES = "cpu"; 090 091 private static final String FORCE_PLUGIN_UPDATES2 = "up"; 092 093 private static final String SUPPRESS_PLUGIN_UPDATES = "npu"; 094 095 private static final String SUPPRESS_PLUGIN_REGISTRY = "npr"; 096 097 private static final char CHECKSUM_FAILURE_POLICY = 'C'; 098 099 private static final char CHECKSUM_WARNING_POLICY = 'c'; 100 101 private static final char ALTERNATE_USER_SETTINGS = 's'; 102 103 private static final String FAIL_FAST = "ff"; 104 105 private static final String FAIL_AT_END = "fae"; 106 107 private static final String FAIL_NEVER = "fn"; 108 109 private static final String ALTERNATE_POM_FILE = "f"; 110 111 /** 112 */ 113 @Requirement 114 private Archetype archetype; 115 116 /** 117 */ 118 @Requirement 119 private Prompter prompter; 120 121 /** 122 */ 123 @Requirement 124 private ArtifactRepositoryFactory artifactRepositoryFactory; 125 126 /** 127 */ 128 @Requirement(role = org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout.class, 129 hint="default") 130 private ArtifactRepositoryLayout defaultArtifactRepositoryLayout; 131 132 private AbstractMojo caller; 133 134 /** 135 * Invokes the maven goal {@code archetype:generate} with the appropriate properties. 136 * 137 */ 138 public void generateArchetype(final File mavenHome, 139 final String archetypeGroupId, 140 final String archetypeArtifactId, 141 final String archetypeVersion, 142 final String groupId, 143 final String artifactId, 144 final String version, 145 final String prototypeGroupId, 146 final String prototypeArtifactId, 147 final String prototypeVersion) throws MojoExecutionException { 148 final Invoker invoker = new DefaultInvoker().setMavenHome(mavenHome); 149 150 final String additionalArguments = ""; 151 152 final InvocationRequest req = new DefaultInvocationRequest() 153 .setInteractive(false) 154 .setProperties(new Properties() {{ 155 setProperty("archetypeGroupId", archetypeGroupId); 156 setProperty("archetypeArtifactId", archetypeArtifactId); 157 setProperty("archetypeVersion", archetypeVersion); 158 setProperty("groupId", groupId); 159 setProperty("artifactId", artifactId); 160 setProperty("version", version); 161 setProperty("kfsPrototypeGroupId", prototypeGroupId); 162 setProperty("kfsPrototypeArtifactId", prototypeArtifactId); 163 setProperty("kfsPrototypeVersion", prototypeVersion); 164 }}); 165 166 try { 167 setupRequest(req, additionalArguments); 168 169 req.setGoals(new ArrayList<String>() {{ add("archetype:generate"); }}); 170 171 try { 172 final InvocationResult invocationResult = invoker.execute(req); 173 174 if ( invocationResult.getExecutionException() != null ) { 175 throw new MojoExecutionException("Error executing Maven.", 176 invocationResult.getExecutionException()); 177 } 178 179 if (invocationResult.getExitCode() != 0) { 180 throw new MojoExecutionException( 181 "Maven execution failed, exit code: \'" + invocationResult.getExitCode() + "\'"); 182 } 183 } 184 catch (MavenInvocationException e) { 185 throw new MojoExecutionException( "Failed to invoke Maven build.", e ); 186 } 187 } 188 finally { 189 /* 190 if ( settingsFile != null && settingsFile.exists() && !settingsFile.delete() ) 191 { 192 settingsFile.deleteOnExit(); 193 } 194 */ 195 } 196 } 197 198 /** 199 * 200 */ 201 private void setupRequest(final InvocationRequest req, 202 final String additionalArguments) throws MojoExecutionException { 203 try { 204 final String[] args = CommandLineUtils.translateCommandline(additionalArguments); 205 CommandLine cli = new PosixParser().parse(OPTIONS, args); 206 207 if (cli.hasOption( SET_SYSTEM_PROPERTY)) 208 { 209 String[] properties = cli.getOptionValues( SET_SYSTEM_PROPERTY ); 210 Properties props = new Properties(); 211 for ( int i = 0; i < properties.length; i++ ) 212 { 213 String property = properties[i]; 214 String name, value; 215 int sep = property.indexOf( "=" ); 216 if ( sep <= 0 ) 217 { 218 name = property.trim(); 219 value = "true"; 220 } 221 else 222 { 223 name = property.substring( 0, sep ).trim(); 224 value = property.substring( sep + 1 ).trim(); 225 } 226 props.setProperty( name, value ); 227 } 228 229 req.setProperties( props ); 230 } 231 232 if ( cli.hasOption( OFFLINE ) ) 233 { 234 req.setOffline( true ); 235 } 236 237 if ( cli.hasOption( QUIET ) ) 238 { 239 // TODO: setQuiet() currently not supported by InvocationRequest 240 req.setDebug( false ); 241 } 242 else if ( cli.hasOption( DEBUG ) ) 243 { 244 req.setDebug( true ); 245 } 246 else if ( cli.hasOption( ERRORS ) ) 247 { 248 req.setShowErrors( true ); 249 } 250 251 if ( cli.hasOption( REACTOR ) ) 252 { 253 req.setRecursive( true ); 254 } 255 else if ( cli.hasOption( NON_RECURSIVE ) ) 256 { 257 req.setRecursive( false ); 258 } 259 260 if ( cli.hasOption( UPDATE_SNAPSHOTS ) ) 261 { 262 req.setUpdateSnapshots( true ); 263 } 264 265 if ( cli.hasOption( ACTIVATE_PROFILES ) ) 266 { 267 String[] profiles = cli.getOptionValues( ACTIVATE_PROFILES ); 268 List<String> activatedProfiles = new ArrayList<String>(); 269 List<String> deactivatedProfiles = new ArrayList<String>(); 270 271 if ( profiles != null ) 272 { 273 for ( int i = 0; i < profiles.length; ++i ) 274 { 275 StringTokenizer profileTokens = new StringTokenizer( profiles[i], "," ); 276 277 while ( profileTokens.hasMoreTokens() ) 278 { 279 String profileAction = profileTokens.nextToken().trim(); 280 281 if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) ) 282 { 283 deactivatedProfiles.add( profileAction.substring( 1 ) ); 284 } 285 else if ( profileAction.startsWith( "+" ) ) 286 { 287 activatedProfiles.add( profileAction.substring( 1 ) ); 288 } 289 else 290 { 291 activatedProfiles.add( profileAction ); 292 } 293 } 294 } 295 } 296 297 if ( !deactivatedProfiles.isEmpty() ) 298 { 299 getCaller().getLog().warn( "Explicit profile deactivation is not yet supported. " 300 + "The following profiles will NOT be deactivated: " + StringUtils.join( 301 deactivatedProfiles.iterator(), ", " ) ); 302 } 303 304 if ( !activatedProfiles.isEmpty() ) 305 { 306 req.setProfiles( activatedProfiles ); 307 } 308 } 309 310 if ( cli.hasOption( FORCE_PLUGIN_UPDATES ) || cli.hasOption( FORCE_PLUGIN_UPDATES2 ) ) 311 { 312 getCaller().getLog().warn( "Forcing plugin updates is not supported currently." ); 313 } 314 else if ( cli.hasOption( SUPPRESS_PLUGIN_UPDATES ) ) 315 { 316 req.setNonPluginUpdates( true ); 317 } 318 319 if ( cli.hasOption( SUPPRESS_PLUGIN_REGISTRY ) ) 320 { 321 getCaller().getLog().warn( "Explicit suppression of the plugin registry is not supported currently." ); 322 } 323 324 if ( cli.hasOption( CHECKSUM_FAILURE_POLICY ) ) 325 { 326 req.setGlobalChecksumPolicy( InvocationRequest.CHECKSUM_POLICY_FAIL ); 327 } 328 else if ( cli.hasOption( CHECKSUM_WARNING_POLICY ) ) 329 { 330 req.setGlobalChecksumPolicy( InvocationRequest.CHECKSUM_POLICY_WARN ); 331 } 332 333 if ( cli.hasOption( ALTERNATE_USER_SETTINGS ) ) 334 { 335 req.setUserSettingsFile( new File( cli.getOptionValue( ALTERNATE_USER_SETTINGS ) ) ); 336 } 337 338 if ( cli.hasOption( FAIL_AT_END ) ) 339 { 340 req.setFailureBehavior( InvocationRequest.REACTOR_FAIL_AT_END ); 341 } 342 else if ( cli.hasOption( FAIL_FAST ) ) 343 { 344 req.setFailureBehavior( InvocationRequest.REACTOR_FAIL_FAST ); 345 } 346 if ( cli.hasOption( FAIL_NEVER ) ) 347 { 348 req.setFailureBehavior( InvocationRequest.REACTOR_FAIL_NEVER ); 349 } 350 if ( cli.hasOption( ALTERNATE_POM_FILE ) ) 351 { 352 if ( req.getPomFileName() != null ) 353 { 354 getCaller().getLog().info( "pomFileName is already set, ignoring the -f argument" ); 355 } 356 else 357 { 358 req.setPomFileName( cli.getOptionValue( ALTERNATE_POM_FILE ) ); 359 } 360 } 361 } 362 catch ( Exception e ) 363 { 364 throw new MojoExecutionException("Failed to re-parse additional arguments for Maven invocation.", e ); 365 } 366 } 367 368 public void setCaller(final AbstractMojo caller) { 369 this.caller = caller; 370 } 371 372 public AbstractMojo getCaller() { 373 return this.caller; 374 } 375}