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, final Properties archetypeProperties) throws MojoExecutionException { 139 final Invoker invoker = new DefaultInvoker().setMavenHome(mavenHome); 140 141 final String additionalArguments = ""; 142 143 final InvocationRequest req = new DefaultInvocationRequest() 144 .setInteractive(false) 145 .setProperties(archetypeProperties); 146 147 try { 148 setupRequest(req, additionalArguments); 149 150 req.setGoals(new ArrayList<String>() {{ add("archetype:generate"); }}); 151 152 try { 153 final InvocationResult invocationResult = invoker.execute(req); 154 155 if ( invocationResult.getExecutionException() != null ) { 156 throw new MojoExecutionException("Error executing Maven.", 157 invocationResult.getExecutionException()); 158 } 159 160 if (invocationResult.getExitCode() != 0) { 161 throw new MojoExecutionException( 162 "Maven execution failed, exit code: \'" + invocationResult.getExitCode() + "\'"); 163 } 164 } 165 catch (MavenInvocationException e) { 166 throw new MojoExecutionException( "Failed to invoke Maven build.", e ); 167 } 168 } 169 finally { 170 /* 171 if ( settingsFile != null && settingsFile.exists() && !settingsFile.delete() ) 172 { 173 settingsFile.deleteOnExit(); 174 } 175 */ 176 } 177 } 178 179 /** 180 * 181 */ 182 private void setupRequest(final InvocationRequest req, 183 final String additionalArguments) throws MojoExecutionException { 184 try { 185 final String[] args = CommandLineUtils.translateCommandline(additionalArguments); 186 CommandLine cli = new PosixParser().parse(OPTIONS, args); 187 188 if (cli.hasOption( SET_SYSTEM_PROPERTY)) 189 { 190 String[] properties = cli.getOptionValues( SET_SYSTEM_PROPERTY ); 191 Properties props = new Properties(); 192 for ( int i = 0; i < properties.length; i++ ) 193 { 194 String property = properties[i]; 195 String name, value; 196 int sep = property.indexOf( "=" ); 197 if ( sep <= 0 ) 198 { 199 name = property.trim(); 200 value = "true"; 201 } 202 else 203 { 204 name = property.substring( 0, sep ).trim(); 205 value = property.substring( sep + 1 ).trim(); 206 } 207 props.setProperty( name, value ); 208 } 209 210 req.setProperties( props ); 211 } 212 213 if ( cli.hasOption( OFFLINE ) ) 214 { 215 req.setOffline( true ); 216 } 217 218 if ( cli.hasOption( QUIET ) ) 219 { 220 // TODO: setQuiet() currently not supported by InvocationRequest 221 req.setDebug( false ); 222 } 223 else if ( cli.hasOption( DEBUG ) ) 224 { 225 req.setDebug( true ); 226 } 227 else if ( cli.hasOption( ERRORS ) ) 228 { 229 req.setShowErrors( true ); 230 } 231 232 if ( cli.hasOption( REACTOR ) ) 233 { 234 req.setRecursive( true ); 235 } 236 else if ( cli.hasOption( NON_RECURSIVE ) ) 237 { 238 req.setRecursive( false ); 239 } 240 241 if ( cli.hasOption( UPDATE_SNAPSHOTS ) ) 242 { 243 req.setUpdateSnapshots( true ); 244 } 245 246 if ( cli.hasOption( ACTIVATE_PROFILES ) ) 247 { 248 String[] profiles = cli.getOptionValues( ACTIVATE_PROFILES ); 249 List<String> activatedProfiles = new ArrayList<String>(); 250 List<String> deactivatedProfiles = new ArrayList<String>(); 251 252 if ( profiles != null ) 253 { 254 for ( int i = 0; i < profiles.length; ++i ) 255 { 256 StringTokenizer profileTokens = new StringTokenizer( profiles[i], "," ); 257 258 while ( profileTokens.hasMoreTokens() ) 259 { 260 String profileAction = profileTokens.nextToken().trim(); 261 262 if ( profileAction.startsWith( "-" ) || profileAction.startsWith( "!" ) ) 263 { 264 deactivatedProfiles.add( profileAction.substring( 1 ) ); 265 } 266 else if ( profileAction.startsWith( "+" ) ) 267 { 268 activatedProfiles.add( profileAction.substring( 1 ) ); 269 } 270 else 271 { 272 activatedProfiles.add( profileAction ); 273 } 274 } 275 } 276 } 277 278 if ( !deactivatedProfiles.isEmpty() ) 279 { 280 getCaller().getLog().warn( "Explicit profile deactivation is not yet supported. " 281 + "The following profiles will NOT be deactivated: " + StringUtils.join( 282 deactivatedProfiles.iterator(), ", " ) ); 283 } 284 285 if ( !activatedProfiles.isEmpty() ) 286 { 287 req.setProfiles( activatedProfiles ); 288 } 289 } 290 291 if ( cli.hasOption( FORCE_PLUGIN_UPDATES ) || cli.hasOption( FORCE_PLUGIN_UPDATES2 ) ) 292 { 293 getCaller().getLog().warn( "Forcing plugin updates is not supported currently." ); 294 } 295 else if ( cli.hasOption( SUPPRESS_PLUGIN_UPDATES ) ) 296 { 297 req.setNonPluginUpdates( true ); 298 } 299 300 if ( cli.hasOption( SUPPRESS_PLUGIN_REGISTRY ) ) 301 { 302 getCaller().getLog().warn( "Explicit suppression of the plugin registry is not supported currently." ); 303 } 304 305 if ( cli.hasOption( CHECKSUM_FAILURE_POLICY ) ) 306 { 307 req.setGlobalChecksumPolicy( InvocationRequest.CHECKSUM_POLICY_FAIL ); 308 } 309 else if ( cli.hasOption( CHECKSUM_WARNING_POLICY ) ) 310 { 311 req.setGlobalChecksumPolicy( InvocationRequest.CHECKSUM_POLICY_WARN ); 312 } 313 314 if ( cli.hasOption( ALTERNATE_USER_SETTINGS ) ) 315 { 316 req.setUserSettingsFile( new File( cli.getOptionValue( ALTERNATE_USER_SETTINGS ) ) ); 317 } 318 319 if ( cli.hasOption( FAIL_AT_END ) ) 320 { 321 req.setFailureBehavior( InvocationRequest.REACTOR_FAIL_AT_END ); 322 } 323 else if ( cli.hasOption( FAIL_FAST ) ) 324 { 325 req.setFailureBehavior( InvocationRequest.REACTOR_FAIL_FAST ); 326 } 327 if ( cli.hasOption( FAIL_NEVER ) ) 328 { 329 req.setFailureBehavior( InvocationRequest.REACTOR_FAIL_NEVER ); 330 } 331 if ( cli.hasOption( ALTERNATE_POM_FILE ) ) 332 { 333 if ( req.getPomFileName() != null ) 334 { 335 getCaller().getLog().info( "pomFileName is already set, ignoring the -f argument" ); 336 } 337 else 338 { 339 req.setPomFileName( cli.getOptionValue( ALTERNATE_POM_FILE ) ); 340 } 341 } 342 } 343 catch ( Exception e ) 344 { 345 throw new MojoExecutionException("Failed to re-parse additional arguments for Maven invocation.", e ); 346 } 347 } 348 349 public void setCaller(final AbstractMojo caller) { 350 this.caller = caller; 351 } 352 353 public AbstractMojo getCaller() { 354 return this.caller; 355 } 356}