1 | package org.apache.maven.continuum.project.builder.maven; |
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 java.io.File; |
23 | import java.net.MalformedURLException; |
24 | import java.net.URL; |
25 | import java.util.ArrayList; |
26 | import java.util.List; |
27 | |
28 | import org.apache.continuum.dao.LocalRepositoryDao; |
29 | import org.apache.continuum.dao.ScheduleDao; |
30 | import org.apache.continuum.model.repository.LocalRepository; |
31 | import org.apache.maven.continuum.builddefinition.BuildDefinitionService; |
32 | import org.apache.maven.continuum.builddefinition.BuildDefinitionServiceException; |
33 | import org.apache.maven.continuum.configuration.ConfigurationService; |
34 | import org.apache.maven.continuum.execution.maven.m2.MavenBuilderHelper; |
35 | import org.apache.maven.continuum.execution.maven.m2.MavenTwoBuildExecutor; |
36 | import org.apache.maven.continuum.model.project.BuildDefinition; |
37 | import org.apache.maven.continuum.model.project.BuildDefinitionTemplate; |
38 | import org.apache.maven.continuum.model.project.Project; |
39 | import org.apache.maven.continuum.model.project.ProjectGroup; |
40 | import org.apache.maven.continuum.model.project.Schedule; |
41 | import org.apache.maven.continuum.project.builder.AbstractContinuumProjectBuilder; |
42 | import org.apache.maven.continuum.project.builder.ContinuumProjectBuilder; |
43 | import org.apache.maven.continuum.project.builder.ContinuumProjectBuilderException; |
44 | import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult; |
45 | import org.apache.maven.continuum.store.ContinuumStoreException; |
46 | import org.apache.maven.project.MavenProject; |
47 | import org.codehaus.plexus.util.StringUtils; |
48 | |
49 | /** |
50 | * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a> |
51 | * @version $Id: MavenTwoContinuumProjectBuilder.java 760328 2009-03-31 04:55:00Z evenisse $ |
52 | * @plexus.component role="org.apache.maven.continuum.project.builder.ContinuumProjectBuilder" role-hint="maven-two-builder" |
53 | */ |
54 | public class MavenTwoContinuumProjectBuilder |
55 | extends AbstractContinuumProjectBuilder |
56 | implements ContinuumProjectBuilder |
57 | { |
58 | public static final String ID = "maven-two-builder"; |
59 | |
60 | private static final String POM_PART = "/pom.xml"; |
61 | |
62 | /** |
63 | * @plexus.requirement |
64 | */ |
65 | private LocalRepositoryDao localRepositoryDao; |
66 | |
67 | /** |
68 | * @plexus.requirement |
69 | */ |
70 | private MavenBuilderHelper builderHelper; |
71 | |
72 | /** |
73 | * @plexus.requirement |
74 | */ |
75 | private ScheduleDao scheduleDao; |
76 | |
77 | /** |
78 | * @plexus.requirement |
79 | */ |
80 | private BuildDefinitionService buildDefinitionService; |
81 | |
82 | /** |
83 | * @plexus.configuration |
84 | */ |
85 | private List<String> excludedPackagingTypes = new ArrayList<String>(); |
86 | |
87 | // ---------------------------------------------------------------------- |
88 | // AbstractContinuumProjectBuilder Implementation |
89 | // ---------------------------------------------------------------------- |
90 | public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password ) |
91 | throws ContinuumProjectBuilderException |
92 | { |
93 | return buildProjectsFromMetadata( url, username, password, true ); |
94 | } |
95 | |
96 | public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password, |
97 | boolean loadRecursiveProjects ) |
98 | throws ContinuumProjectBuilderException |
99 | { |
100 | try |
101 | { |
102 | return buildProjectsFromMetadata( url, username, password, loadRecursiveProjects, |
103 | buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate() ); |
104 | } |
105 | catch ( BuildDefinitionServiceException e ) |
106 | { |
107 | throw new ContinuumProjectBuilderException( e.getMessage(), e ); |
108 | } |
109 | } |
110 | |
111 | public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password, |
112 | boolean loadRecursiveProjects, |
113 | BuildDefinitionTemplate buildDefinitionTemplate ) |
114 | throws ContinuumProjectBuilderException |
115 | { |
116 | // ---------------------------------------------------------------------- |
117 | // We need to roll the project data into a file so that we can use it |
118 | // ---------------------------------------------------------------------- |
119 | |
120 | ContinuumProjectBuildingResult result = new ContinuumProjectBuildingResult(); |
121 | |
122 | try |
123 | { |
124 | readModules( url, result, true, username, password, null, loadRecursiveProjects, buildDefinitionTemplate ); |
125 | } |
126 | catch ( BuildDefinitionServiceException e ) |
127 | { |
128 | throw new ContinuumProjectBuilderException( e.getMessage(), e ); |
129 | } |
130 | return result; |
131 | } |
132 | |
133 | // ---------------------------------------------------------------------- |
134 | // |
135 | // ---------------------------------------------------------------------- |
136 | |
137 | private void readModules( URL url, ContinuumProjectBuildingResult result, boolean groupPom, String username, |
138 | String password, String scmUrl, boolean loadRecursiveProjects, |
139 | BuildDefinitionTemplate buildDefinitionTemplate ) |
140 | throws ContinuumProjectBuilderException, BuildDefinitionServiceException |
141 | { |
142 | |
143 | MavenProject mavenProject; |
144 | |
145 | File pomFile = null; |
146 | |
147 | try |
148 | { |
149 | pomFile = createMetadataFile( result, url, username, password ); |
150 | |
151 | if ( result.hasErrors() ) |
152 | { |
153 | return; |
154 | } |
155 | |
156 | mavenProject = builderHelper.getMavenProject( result, pomFile ); |
157 | |
158 | if ( result.hasErrors() ) |
159 | { |
160 | return; |
161 | } |
162 | } |
163 | finally |
164 | { |
165 | if ( pomFile != null && pomFile.exists() ) |
166 | { |
167 | pomFile.delete(); |
168 | } |
169 | } |
170 | log.debug( "groupPom " + groupPom ); |
171 | if ( groupPom ) |
172 | { |
173 | ProjectGroup projectGroup = buildProjectGroup( mavenProject, result ); |
174 | |
175 | // project groups have the top lvl build definition which is the default build defintion for the sub |
176 | // projects |
177 | log.debug( "projectGroup != null" + ( projectGroup != null ) ); |
178 | if ( projectGroup != null ) |
179 | { |
180 | List<BuildDefinition> buildDefinitions = |
181 | getBuildDefinitions( buildDefinitionTemplate, loadRecursiveProjects ); |
182 | boolean defaultSetted = false; |
183 | for ( BuildDefinition buildDefinition : buildDefinitions ) |
184 | { |
185 | if ( !defaultSetted && buildDefinition.isDefaultForProject() ) |
186 | { |
187 | buildDefinition.setDefaultForProject( true ); |
188 | defaultSetted = true; |
189 | } |
190 | buildDefinition = buildDefinitionService.addBuildDefinition( |
191 | buildDefinitionService.cloneBuildDefinition( buildDefinition ) ); |
192 | //CONTINUUM-1296 |
193 | String defaultGoal = mavenProject.getBuild().getDefaultGoal(); |
194 | if ( StringUtils.isNotEmpty( defaultGoal ) ) |
195 | { |
196 | buildDefinition.setGoals( defaultGoal ); |
197 | } |
198 | if ( buildDefinition.getSchedule() == null ) |
199 | { |
200 | try |
201 | { |
202 | Schedule schedule = |
203 | scheduleDao.getScheduleByName( ConfigurationService.DEFAULT_SCHEDULE_NAME ); |
204 | |
205 | buildDefinition.setSchedule( schedule ); |
206 | } |
207 | catch ( ContinuumStoreException e ) |
208 | { |
209 | log.warn( "Can't get default schedule.", e ); |
210 | } |
211 | } |
212 | // jdo complains that Collections.singletonList(bd) is a second class object and fails. |
213 | //ArrayList arrayList = new ArrayList(); |
214 | |
215 | //arrayList.add( buildDefinition ); |
216 | |
217 | projectGroup.addBuildDefinition( buildDefinition ); |
218 | // .setBuildDefinitions( arrayList ); |
219 | } |
220 | result.addProjectGroup( projectGroup ); |
221 | } |
222 | } |
223 | |
224 | if ( !excludedPackagingTypes.contains( mavenProject.getPackaging() ) ) |
225 | { |
226 | Project continuumProject = new Project(); |
227 | |
228 | /* |
229 | We are interested in having the scm username and password being passed into this method be taken into |
230 | account during project mapping so make sure we set it to the continuum project instance. |
231 | */ |
232 | if ( username != null && StringUtils.isNotEmpty( username ) ) |
233 | { |
234 | continuumProject.setScmUsername( username ); |
235 | |
236 | if ( password != null && StringUtils.isNotEmpty( password ) ) |
237 | { |
238 | continuumProject.setScmPassword( password ); |
239 | } |
240 | } |
241 | |
242 | builderHelper.mapMavenProjectToContinuumProject( result, mavenProject, continuumProject, groupPom ); |
243 | |
244 | if ( result.hasErrors() ) |
245 | { |
246 | log.info( |
247 | "Error adding project: Unknown error mapping project " + url + ": " + result.getErrorsAsString() ); |
248 | return; |
249 | } |
250 | |
251 | // Rewrite scmurl from the one found in added project due to a bug in scm url resolution |
252 | // for projects that doesn't have module name != artifactId |
253 | if ( StringUtils.isNotEmpty( scmUrl ) ) |
254 | { |
255 | continuumProject.setScmUrl( scmUrl ); |
256 | } |
257 | else |
258 | { |
259 | scmUrl = continuumProject.getScmUrl(); |
260 | } |
261 | |
262 | if ( !"HEAD".equals( mavenProject.getScm().getTag() ) ) |
263 | { |
264 | continuumProject.setScmTag( mavenProject.getScm().getTag() ); |
265 | } |
266 | result.addProject( continuumProject, MavenTwoBuildExecutor.ID ); |
267 | } |
268 | |
269 | List<String> modules = mavenProject.getModules(); |
270 | |
271 | String prefix = url.toExternalForm(); |
272 | |
273 | String suffix = ""; |
274 | |
275 | int i = prefix.indexOf( '?' ); |
276 | |
277 | int lastSlash; |
278 | |
279 | if ( i != -1 ) |
280 | { |
281 | suffix = prefix.substring( i ); |
282 | |
283 | lastSlash = prefix.lastIndexOf( "/", i ); |
284 | } |
285 | else |
286 | { |
287 | lastSlash = prefix.lastIndexOf( "/" ); |
288 | } |
289 | |
290 | prefix = prefix.substring( 0, lastSlash ); |
291 | if ( loadRecursiveProjects ) |
292 | { |
293 | for ( String module : modules ) |
294 | { |
295 | if ( StringUtils.isNotEmpty( module ) ) |
296 | { |
297 | String urlString = prefix + "/" + module + POM_PART + suffix; |
298 | |
299 | URL moduleUrl; |
300 | |
301 | try |
302 | { |
303 | moduleUrl = new URL( urlString ); |
304 | } |
305 | catch ( MalformedURLException e ) |
306 | { |
307 | log.debug( "Error adding project module: Malformed URL " + urlString, e ); |
308 | result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL, urlString ); |
309 | continue; |
310 | } |
311 | |
312 | String moduleScmUrl; |
313 | if ( scmUrl.endsWith( "/" ) ) |
314 | { |
315 | moduleScmUrl = scmUrl + module; |
316 | } |
317 | else |
318 | { |
319 | moduleScmUrl = scmUrl + "/" + module; |
320 | } |
321 | // we are in recursive loading mode |
322 | readModules( moduleUrl, result, false, username, password, moduleScmUrl, true, |
323 | buildDefinitionTemplate ); |
324 | } |
325 | } |
326 | } |
327 | } |
328 | |
329 | private List<BuildDefinition> getBuildDefinitions( BuildDefinitionTemplate template, boolean loadRecursiveProjects ) |
330 | throws ContinuumProjectBuilderException, BuildDefinitionServiceException |
331 | { |
332 | List<BuildDefinition> buildDefinitions = new ArrayList<BuildDefinition>(); |
333 | for ( BuildDefinition buildDefinition : (List<BuildDefinition>) template.getBuildDefinitions() ) |
334 | { |
335 | // due to CONTINUUM-1207 CONTINUUM-1436 user can do what they want with arguments |
336 | // we must remove if exists --non-recursive or -N |
337 | if ( !loadRecursiveProjects ) |
338 | { |
339 | if ( StringUtils.isEmpty( buildDefinition.getArguments() ) ) |
340 | { |
341 | // strange for a mvn build |
342 | log.info( "build definition '" + buildDefinition.getId() + "' has empty args" ); |
343 | } |
344 | else |
345 | { |
346 | String arguments = buildDefinition.getArguments().replace( "--non-recursive", "" ); |
347 | arguments = arguments.replace( "-N", "" ); |
348 | buildDefinition.setArguments( arguments ); |
349 | } |
350 | } |
351 | buildDefinition.setTemplate( false ); |
352 | buildDefinitions.add( buildDefinition ); |
353 | } |
354 | return buildDefinitions; |
355 | |
356 | } |
357 | |
358 | private ProjectGroup buildProjectGroup( MavenProject mavenProject, ContinuumProjectBuildingResult result ) |
359 | { |
360 | ProjectGroup projectGroup = new ProjectGroup(); |
361 | |
362 | // ---------------------------------------------------------------------- |
363 | // Group id |
364 | // ---------------------------------------------------------------------- |
365 | |
366 | if ( StringUtils.isEmpty( mavenProject.getGroupId() ) ) |
367 | { |
368 | result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_GROUPID ); |
369 | |
370 | return null; |
371 | } |
372 | |
373 | projectGroup.setGroupId( mavenProject.getGroupId() ); |
374 | |
375 | // ---------------------------------------------------------------------- |
376 | // Name |
377 | // ---------------------------------------------------------------------- |
378 | |
379 | String name = mavenProject.getName(); |
380 | |
381 | if ( StringUtils.isEmpty( name ) ) |
382 | { |
383 | name = mavenProject.getGroupId(); |
384 | } |
385 | |
386 | projectGroup.setName( name ); |
387 | |
388 | // ---------------------------------------------------------------------- |
389 | // Description |
390 | // ---------------------------------------------------------------------- |
391 | |
392 | projectGroup.setDescription( mavenProject.getDescription() ); |
393 | |
394 | // ---------------------------------------------------------------------- |
395 | // Local Repository |
396 | // ---------------------------------------------------------------------- |
397 | |
398 | try |
399 | { |
400 | LocalRepository repository = localRepositoryDao.getLocalRepositoryByName( "DEFAULT" ); |
401 | |
402 | projectGroup.setLocalRepository( repository ); |
403 | } |
404 | catch ( ContinuumStoreException e ) |
405 | { |
406 | log.warn( "Can't get default repository.", e ); |
407 | } |
408 | |
409 | return projectGroup; |
410 | } |
411 | |
412 | |
413 | public BuildDefinitionTemplate getDefaultBuildDefinitionTemplate() |
414 | throws ContinuumProjectBuilderException |
415 | { |
416 | try |
417 | { |
418 | return buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate(); |
419 | } |
420 | catch ( BuildDefinitionServiceException e ) |
421 | { |
422 | throw new ContinuumProjectBuilderException( e.getMessage(), e ); |
423 | } |
424 | } |
425 | |
426 | } |