1 package org.apache.maven.archetype.mojos;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.maven.archetype.ArchetypeManager;
24 import org.apache.maven.archetype.ArchetypeGenerationRequest;
25 import org.apache.maven.archetype.ArchetypeGenerationResult;
26 import org.apache.maven.archetype.ui.generation.ArchetypeGenerationConfigurator;
27 import org.apache.maven.archetype.ui.generation.ArchetypeSelector;
28 import org.apache.maven.artifact.repository.ArtifactRepository;
29 import org.apache.maven.execution.MavenSession;
30 import org.apache.maven.plugin.AbstractMojo;
31 import org.apache.maven.plugin.ContextEnabled;
32 import org.apache.maven.plugin.MojoExecutionException;
33 import org.apache.maven.plugin.MojoFailureException;
34 import org.apache.maven.shared.invoker.DefaultInvocationRequest;
35 import org.apache.maven.shared.invoker.InvocationRequest;
36 import org.apache.maven.shared.invoker.Invoker;
37 import org.apache.maven.shared.invoker.MavenInvocationException;
38
39 import java.io.File;
40 import java.util.Arrays;
41 import java.util.List;
42 import java.util.Properties;
43
44 /**
45 * Generates a new project from an archetype, or updated the actual project if using a partial archetype.
46 * If the project is fully generated, it is generated in a directory corresponding to its artifactId.
47 * If the project is updated with a partial archetype, it is done in the current directory.
48 *
49 * @author rafale
50 * @requiresProject false
51 * @goal generate
52 * @execute phase="generate-sources"
53 */
54 public class CreateProjectFromArchetypeMojo
55 extends AbstractMojo
56 implements ContextEnabled
57 {
58 /** @component */
59 private ArchetypeManager manager;
60
61 /** @component */
62 private ArchetypeSelector selector;
63
64 /** @component */
65 private ArchetypeGenerationConfigurator configurator;
66
67 /** @component */
68 private Invoker invoker;
69
70 /**
71 * The archetype's artifactId.
72 *
73 * @parameter expression="${archetypeArtifactId}"
74 */
75 private String archetypeArtifactId;
76
77 /**
78 * The archetype's groupId.
79 *
80 * @parameter expression="${archetypeGroupId}"
81 */
82 private String archetypeGroupId;
83
84 /**
85 * The archetype's version.
86 *
87 * @parameter expression="${archetypeVersion}"
88 */
89 private String archetypeVersion;
90
91 /**
92 * The archetype's repository.
93 *
94 * @parameter expression="${archetypeRepository}"
95 */
96 private String archetypeRepository;
97
98 /**
99 * The archetype catalogs to use to build a list and let the user choose from.
100 * It is a comma separated list of catalogs.
101 * Catalogs use following schemes:
102 * <ul>
103 * <li>'<code>file://...</code>' with <code>archetype-catalog.xml</code> automatically appended when pointing to a directory</li>
104 * <li>'<code>http://...</code>' or '<code>https://...</code>' with <code>archetype-catalog.xml</code> always appended</li>
105 * <li>'<code>local</code>' which is the shortcut for '<code>file://~/.m2/archetype-catalog.xml</code>'</li>
106 * <li>'<code>remote</code>' which is the shortcut for Maven Central repository, ie '<code>http://repo1.maven.org/maven2</code>'</li>
107 * <li>'<code>internal</code>' which is an internal catalog</li>
108 * </ul>
109 *
110 * Since 2.0-alpha-5, default value is no longer <code>internal,local</code> but <code>remote,local</code>.
111 * If Maven Central repository catalog file is empty, <code>internal</code> catalog is used instead.
112 *
113 * @parameter expression="${archetypeCatalog}" default-value="remote,local"
114 */
115 private String archetypeCatalog;
116
117 /**
118 * Local Maven repository.
119 *
120 * @parameter expression="${localRepository}"
121 * @required
122 * @readonly
123 */
124 private ArtifactRepository localRepository;
125
126 /**
127 * List of remote repositories used by the resolver.
128 *
129 * @parameter expression="${project.remoteArtifactRepositories}"
130 * @readonly
131 * @required
132 */
133 private List<ArtifactRepository> remoteArtifactRepositories;
134
135 /**
136 * User settings use to check the interactiveMode.
137 *
138 * @parameter expression="${interactiveMode}" default-value="${settings.interactiveMode}"
139 * @required
140 */
141 private Boolean interactiveMode;
142
143 /** @parameter expression="${basedir}" */
144 private File basedir;
145
146 /**
147 * @parameter expression="${session}"
148 * @readonly
149 */
150 private MavenSession session;
151
152 /**
153 * Additional goals to immediately run on the project created from the archetype.
154 *
155 * @parameter expression="${goals}"
156 */
157 private String goals;
158
159 /**
160 * Applying some filter on displayed archetypes list: format is <code>artifactId</code> or <code>groupId:artifactId</code>.
161 * <ul>
162 * <li><code>org.apache:</code> -> displays all archetypes which contain org.apache in groupId</li>
163 * <li><code>:jee</code> or <code>jee</code> -> displays all archetypes which contain jee in artifactId</li>
164 * <li><code>org.apache:jee</code> -> displays all archetypes which contain org.apache in groupId AND jee in artifactId</li>
165 * </ul>
166 * @parameter expression="${filter}"
167 * @since 2.1
168 */
169 private String filter;
170
171 public void execute()
172 throws MojoExecutionException, MojoFailureException
173 {
174 Properties executionProperties = session.getExecutionProperties();
175
176 ArchetypeGenerationRequest request = new ArchetypeGenerationRequest()
177 .setArchetypeGroupId( archetypeGroupId )
178 .setArchetypeArtifactId( archetypeArtifactId )
179 .setArchetypeVersion( archetypeVersion )
180 .setOutputDirectory( basedir.getAbsolutePath() )
181 .setLocalRepository( localRepository )
182 .setArchetypeRepository( archetypeRepository )
183 .setRemoteArtifactRepositories( remoteArtifactRepositories )
184 .setFilter( filter );
185
186 try
187 {
188 if ( interactiveMode.booleanValue() )
189 {
190 getLog().info( "Generating project in Interactive mode" );
191 }
192 else
193 {
194 getLog().info( "Generating project in Batch mode" );
195 }
196
197 selector.selectArchetype( request, interactiveMode, archetypeCatalog );
198
199 if ( StringUtils.isBlank( request.getArchetypeArtifactId() ) )
200 {
201 // no archetype found: stopping
202 return;
203 }
204
205 configurator.configureArchetype( request, interactiveMode, executionProperties );
206
207 ArchetypeGenerationResult generationResult = manager.generateProjectFromArchetype( request );
208
209 if ( generationResult.getCause() != null )
210 {
211 throw new MojoFailureException( generationResult.getCause(), generationResult.getCause().getMessage(),
212 generationResult.getCause().getMessage() );
213 }
214 }
215 catch ( MojoFailureException ex )
216 {
217 throw ex;
218 }
219 catch ( Exception ex )
220 {
221 throw (MojoFailureException) new MojoFailureException( ex.getMessage() ).initCause( ex );
222 }
223
224 String artifactId = request.getArtifactId();
225
226 String postArchetypeGenerationGoals = request.getArchetypeGoals();
227
228 if ( StringUtils.isEmpty( postArchetypeGenerationGoals ) )
229 {
230 postArchetypeGenerationGoals = goals;
231 }
232
233 if ( StringUtils.isNotEmpty( postArchetypeGenerationGoals ) )
234 {
235 invokePostArchetypeGenerationGoals( postArchetypeGenerationGoals, artifactId );
236 }
237 }
238
239 private void invokePostArchetypeGenerationGoals( String goals, String artifactId )
240 throws MojoExecutionException, MojoFailureException
241 {
242 getLog().info( "Invoking post-archetype-generation goals: " + goals );
243
244 File projectBasedir = new File( basedir, artifactId );
245
246 if ( projectBasedir.exists() )
247 {
248 InvocationRequest request = new DefaultInvocationRequest()
249 .setBaseDirectory( projectBasedir )
250 .setGoals( Arrays.asList( StringUtils.split( goals, "," ) ) );
251
252 try
253 {
254 invoker.execute( request );
255 }
256 catch ( MavenInvocationException e )
257 {
258 throw new MojoExecutionException( "Cannot run additions goals.", e );
259 }
260 }
261 else
262 {
263 getLog().info( "Post-archetype-generation goals aborted: unavailable basedir " + projectBasedir );
264 }
265 }
266 }