1 package org.apache.maven.continuum.project.builder.maven;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.continuum.dao.LocalRepositoryDao;
23 import org.apache.continuum.dao.ProjectGroupDao;
24 import org.apache.continuum.dao.ScheduleDao;
25 import org.apache.continuum.model.repository.LocalRepository;
26 import org.apache.maven.continuum.builddefinition.BuildDefinitionService;
27 import org.apache.maven.continuum.builddefinition.BuildDefinitionServiceException;
28 import org.apache.maven.continuum.configuration.ConfigurationService;
29 import org.apache.maven.continuum.execution.maven.m2.MavenBuilderHelper;
30 import org.apache.maven.continuum.execution.maven.m2.MavenTwoBuildExecutor;
31 import org.apache.maven.continuum.model.project.BuildDefinition;
32 import org.apache.maven.continuum.model.project.BuildDefinitionTemplate;
33 import org.apache.maven.continuum.model.project.Project;
34 import org.apache.maven.continuum.model.project.ProjectGroup;
35 import org.apache.maven.continuum.model.project.Schedule;
36 import org.apache.maven.continuum.project.builder.AbstractContinuumProjectBuilder;
37 import org.apache.maven.continuum.project.builder.ContinuumProjectBuilder;
38 import org.apache.maven.continuum.project.builder.ContinuumProjectBuilderException;
39 import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult;
40 import org.apache.maven.continuum.store.ContinuumStoreException;
41 import org.apache.maven.project.MavenProject;
42 import org.codehaus.plexus.util.StringUtils;
43
44 import java.io.File;
45 import java.net.MalformedURLException;
46 import java.net.URL;
47 import java.util.ArrayList;
48 import java.util.List;
49
50
51
52
53
54
55 public class MavenTwoContinuumProjectBuilder
56 extends AbstractContinuumProjectBuilder
57 implements ContinuumProjectBuilder
58 {
59 public static final String ID = "maven-two-builder";
60
61 private static final String POM_PART = "/pom.xml";
62
63
64
65
66 private LocalRepositoryDao localRepositoryDao;
67
68
69
70
71 private MavenBuilderHelper builderHelper;
72
73
74
75
76 private ScheduleDao scheduleDao;
77
78
79
80
81 private BuildDefinitionService buildDefinitionService;
82
83
84
85
86 private List<String> excludedPackagingTypes = new ArrayList<String>();
87
88 private Project rootProject;
89
90
91
92
93 private ProjectGroupDao projectGroupDao;
94
95
96
97
98 public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password )
99 throws ContinuumProjectBuilderException
100 {
101 return buildProjectsFromMetadata( url, username, password, true, false );
102 }
103
104 public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
105 boolean loadRecursiveProjects,
106 boolean checkoutInSingleDirectory )
107 throws ContinuumProjectBuilderException
108 {
109 try
110 {
111 return buildProjectsFromMetadata( url, username, password, loadRecursiveProjects,
112 buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate(),
113 checkoutInSingleDirectory );
114 }
115 catch ( BuildDefinitionServiceException e )
116 {
117 throw new ContinuumProjectBuilderException( e.getMessage(), e );
118 }
119 }
120
121 public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
122 boolean loadRecursiveProjects,
123 BuildDefinitionTemplate buildDefinitionTemplate,
124 boolean checkoutInSingleDirectory )
125 throws ContinuumProjectBuilderException
126 {
127 return buildProjectsFromMetadata( url, username, password, loadRecursiveProjects, buildDefinitionTemplate, checkoutInSingleDirectory, -1 );
128 }
129
130 public ContinuumProjectBuildingResult buildProjectsFromMetadata( URL url, String username, String password,
131 boolean loadRecursiveProjects,
132 BuildDefinitionTemplate buildDefinitionTemplate,
133 boolean checkoutInSingleDirectory,
134 int projectGroupId )
135 throws ContinuumProjectBuilderException
136 {
137
138
139
140
141 ContinuumProjectBuildingResult result = new ContinuumProjectBuildingResult();
142
143 try
144 {
145 ProjectGroup projectGroup = null;
146 if ( projectGroupId > 0 )
147 {
148 projectGroup = projectGroupDao.getProjectGroupWithBuildDetailsByProjectGroupId( projectGroupId );
149 }
150
151 readModules( url, result, projectGroup, username, password, null, loadRecursiveProjects, buildDefinitionTemplate,
152 checkoutInSingleDirectory );
153 }
154 catch ( BuildDefinitionServiceException e )
155 {
156 throw new ContinuumProjectBuilderException( e.getMessage(), e );
157 }
158 catch ( ContinuumStoreException e )
159 {
160 throw new ContinuumProjectBuilderException( e.getMessage(), e );
161 }
162 return result;
163 }
164
165
166
167
168
169 private void readModules( URL url, ContinuumProjectBuildingResult result, ProjectGroup projectGroup, String username,
170 String password, String scmUrl, boolean loadRecursiveProjects,
171 BuildDefinitionTemplate buildDefinitionTemplate, boolean checkoutInSingleDirectory )
172 throws ContinuumProjectBuilderException, BuildDefinitionServiceException
173 {
174
175 MavenProject mavenProject;
176
177 File pomFile = null;
178
179 try
180 {
181 pomFile = createMetadataFile( result, url, username, password );
182
183 if ( result.hasErrors() )
184 {
185 return;
186 }
187
188 mavenProject = builderHelper.getMavenProject( result, pomFile );
189
190 if ( result.hasErrors() )
191 {
192 return;
193 }
194 }
195 finally
196 {
197 if ( pomFile != null && pomFile.exists() )
198 {
199 pomFile.delete();
200 }
201 }
202 log.debug( "projectGroup " + projectGroup );
203
204 if ( projectGroup == null )
205 {
206 projectGroup = buildProjectGroup( mavenProject, result );
207
208
209
210 log.debug( "projectGroup != null" + ( projectGroup != null ) );
211 if ( projectGroup != null )
212 {
213 List<BuildDefinition> buildDefinitions = getBuildDefinitions( buildDefinitionTemplate,
214 loadRecursiveProjects,
215 mavenProject.getBuild().getDefaultGoal() );
216 for ( BuildDefinition buildDefinition : buildDefinitions )
217 {
218 buildDefinition = persistBuildDefinition( buildDefinition );
219
220 projectGroup.addBuildDefinition( buildDefinition );
221 }
222 }
223 }
224 if ( result.getProjectGroups().isEmpty() )
225 {
226 result.addProjectGroup( projectGroup );
227 }
228
229 if ( !excludedPackagingTypes.contains( mavenProject.getPackaging() ) )
230 {
231 Project continuumProject = new Project();
232
233
234
235
236
237 if ( username != null && StringUtils.isNotEmpty( username ) )
238 {
239 continuumProject.setScmUsername( username );
240
241 if ( password != null && StringUtils.isNotEmpty( password ) )
242 {
243 continuumProject.setScmPassword( password );
244 }
245 }
246
247 continuumProject.setCheckedOutInSingleDirectory( checkoutInSingleDirectory );
248
249
250 builderHelper.mapMavenProjectToContinuumProject( result, mavenProject, continuumProject, true );
251
252 if ( result.hasErrors() )
253 {
254 log.info(
255 "Error adding project: Unknown error mapping project " + url + ": " + result.getErrorsAsString() );
256 return;
257 }
258
259
260
261 if ( StringUtils.isNotEmpty( scmUrl ) )
262 {
263 continuumProject.setScmUrl( scmUrl );
264 }
265 else
266 {
267 scmUrl = continuumProject.getScmUrl();
268 }
269
270 if ( !"HEAD".equals( mavenProject.getScm().getTag() ) )
271 {
272 continuumProject.setScmTag( mavenProject.getScm().getTag() );
273 }
274
275
276
277 if ( !loadRecursiveProjects && buildDefinitionTemplate.equals( getDefaultBuildDefinitionTemplate() ) )
278 {
279 List<BuildDefinition> buildDefinitions = projectGroup.getBuildDefinitions();
280 for ( BuildDefinition buildDefinition : buildDefinitions )
281 {
282 if ( buildDefinition.isDefaultForProject() )
283 {
284
285 BuildDefinition projectBuildDef = buildDefinitionService.cloneBuildDefinition( buildDefinition );
286 projectBuildDef.setDefaultForProject( true );
287
288 String arguments = projectBuildDef.getArguments().replace( "--non-recursive", "" );
289 arguments = arguments.replace( "-N", "" );
290 arguments = arguments.trim();
291
292
293 if ( !projectBuildDef.getArguments().equals( arguments ) )
294 {
295 log.info( "Adding default build definition for project '" + continuumProject.getName() +
296 "' without '--non-recursive' flag." );
297
298 projectBuildDef.setArguments( arguments );
299 continuumProject.addBuildDefinition( projectBuildDef );
300 }
301
302 break;
303 }
304 }
305 }
306
307 result.addProject( continuumProject, MavenTwoBuildExecutor.ID );
308
309 if ( checkoutInSingleDirectory && rootProject == null )
310 {
311 rootProject = continuumProject;
312 result.setRootProject( rootProject );
313 }
314 }
315
316 List<String> modules = mavenProject.getModules();
317
318 String prefix = url.toExternalForm();
319
320 String suffix = "";
321
322 int i = prefix.indexOf( '?' );
323
324 int lastSlash;
325
326 if ( i != -1 )
327 {
328 suffix = prefix.substring( i );
329
330 lastSlash = prefix.lastIndexOf( "/", i );
331 }
332 else
333 {
334 lastSlash = prefix.lastIndexOf( "/" );
335 }
336
337 prefix = prefix.substring( 0, lastSlash );
338 if ( loadRecursiveProjects )
339 {
340 for ( String module : modules )
341 {
342 if ( StringUtils.isNotEmpty( module ) )
343 {
344 String urlString = prefix + "/" + module + POM_PART + suffix;
345
346 URL moduleUrl;
347
348 try
349 {
350 urlString = StringUtils.replace( urlString, '\\', '/' );
351 moduleUrl = new URL( urlString );
352 }
353 catch ( MalformedURLException e )
354 {
355 log.debug( "Error adding project module: Malformed URL " + urlString, e );
356 result.addError( ContinuumProjectBuildingResult.ERROR_MALFORMED_URL, urlString );
357 continue;
358 }
359
360 String moduleScmUrl = "";
361
362 String modulePath = StringUtils.replace( new String( module ), '\\', '/' );
363
364
365 if ( modulePath.indexOf( "../" ) != -1 )
366 {
367 int depth = StringUtils.countMatches( StringUtils.substring( modulePath, 0,
368 modulePath.lastIndexOf( '/' ) +
369 1 ), "/" );
370
371 String baseUrl = "";
372 for ( int j = 1; j <= depth; j++ )
373 {
374 scmUrl = StringUtils.chompLast( new String( scmUrl ), "/" );
375 baseUrl = StringUtils.substring( scmUrl, 0, scmUrl.lastIndexOf( '/' ) );
376 }
377 moduleScmUrl = baseUrl + "/" + StringUtils.substring( modulePath, modulePath.lastIndexOf(
378 "../" ) + 3 );
379 }
380 else
381 {
382 scmUrl = StringUtils.chompLast( scmUrl, "/" );
383 moduleScmUrl = scmUrl + "/" + modulePath;
384 }
385
386 readModules( moduleUrl, result, projectGroup, username, password, moduleScmUrl, true,
387 buildDefinitionTemplate, checkoutInSingleDirectory );
388 }
389 }
390 }
391 }
392
393 private BuildDefinition persistBuildDefinition( BuildDefinition buildDefinition )
394 throws BuildDefinitionServiceException
395 {
396 buildDefinition = buildDefinitionService.addBuildDefinition( buildDefinition );
397 if ( buildDefinition.getSchedule() == null )
398 {
399 try
400 {
401 Schedule schedule = scheduleDao.getScheduleByName(
402 ConfigurationService.DEFAULT_SCHEDULE_NAME );
403
404 buildDefinition.setSchedule( schedule );
405 }
406 catch ( ContinuumStoreException e )
407 {
408 log.warn( "Can't get default schedule.", e );
409 }
410 }
411 return buildDefinition;
412 }
413
414 private List<BuildDefinition> getBuildDefinitions( BuildDefinitionTemplate template, boolean loadRecursiveProjects,
415 String defaultGoal )
416 throws ContinuumProjectBuilderException, BuildDefinitionServiceException
417 {
418 List<BuildDefinition> buildDefinitions = new ArrayList<BuildDefinition>();
419 boolean defaultSet = false;
420 for ( BuildDefinition buildDefinition : template.getBuildDefinitions() )
421 {
422 buildDefinition = buildDefinitionService.cloneBuildDefinition( buildDefinition );
423
424 if ( !defaultSet && buildDefinition.isDefaultForProject() )
425 {
426 defaultSet = true;
427
428
429 if ( StringUtils.isNotEmpty( defaultGoal ) )
430 {
431 buildDefinition.setGoals( defaultGoal );
432 }
433 }
434 else
435 {
436 buildDefinition.setDefaultForProject( false );
437 }
438
439
440
441 if ( !loadRecursiveProjects )
442 {
443 if ( StringUtils.isEmpty( buildDefinition.getArguments() ) )
444 {
445
446 log.info( "build definition '" + buildDefinition.getId() + "' has empty args" );
447 }
448 else
449 {
450 String arguments = buildDefinition.getArguments().replace( "--non-recursive", "" );
451 arguments = arguments.replace( "-N", "" );
452 arguments = arguments.trim();
453 buildDefinition.setArguments( arguments );
454 }
455 }
456 buildDefinition.setTemplate( false );
457 buildDefinitions.add( buildDefinition );
458 }
459 return buildDefinitions;
460
461 }
462
463 private ProjectGroup buildProjectGroup( MavenProject mavenProject, ContinuumProjectBuildingResult result )
464 {
465 ProjectGroup projectGroup = new ProjectGroup();
466
467
468
469
470
471 if ( StringUtils.isEmpty( mavenProject.getGroupId() ) )
472 {
473 result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_GROUPID );
474
475 return null;
476 }
477
478 projectGroup.setGroupId( mavenProject.getGroupId() );
479
480
481
482
483
484 String name = mavenProject.getName();
485
486 if ( StringUtils.isEmpty( name ) )
487 {
488 name = mavenProject.getGroupId();
489 }
490
491 projectGroup.setName( name );
492
493
494
495
496
497 projectGroup.setDescription( mavenProject.getDescription() );
498
499
500
501
502
503 try
504 {
505 LocalRepository repository = localRepositoryDao.getLocalRepositoryByName( "DEFAULT" );
506
507 projectGroup.setLocalRepository( repository );
508 }
509 catch ( ContinuumStoreException e )
510 {
511 log.warn( "Can't get default repository.", e );
512 }
513
514 return projectGroup;
515 }
516
517
518 public BuildDefinitionTemplate getDefaultBuildDefinitionTemplate()
519 throws ContinuumProjectBuilderException
520 {
521 try
522 {
523 return buildDefinitionService.getDefaultMavenTwoBuildDefinitionTemplate();
524 }
525 catch ( BuildDefinitionServiceException e )
526 {
527 throw new ContinuumProjectBuilderException( e.getMessage(), e );
528 }
529 }
530
531 }