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