1 package org.apache.continuum.buildagent.build.execution.maven.m2;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.artifact.manager.WagonManager;
23 import org.apache.maven.artifact.repository.ArtifactRepository;
24 import org.apache.maven.artifact.repository.ArtifactRepositoryFactory;
25 import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
26 import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
27 import org.apache.maven.continuum.model.project.Project;
28 import org.apache.maven.continuum.model.project.ProjectDependency;
29 import org.apache.maven.continuum.model.project.ProjectDeveloper;
30 import org.apache.maven.continuum.model.project.ProjectNotifier;
31 import org.apache.maven.continuum.project.builder.ContinuumProjectBuildingResult;
32 import org.apache.maven.model.Dependency;
33 import org.apache.maven.model.Developer;
34 import org.apache.maven.model.Extension;
35 import org.apache.maven.model.Model;
36 import org.apache.maven.model.Notifier;
37 import org.apache.maven.model.Plugin;
38 import org.apache.maven.model.Profile;
39 import org.apache.maven.model.ReportPlugin;
40 import org.apache.maven.model.Scm;
41 import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
42 import org.apache.maven.profiles.DefaultProfileManager;
43 import org.apache.maven.profiles.ProfileManager;
44 import org.apache.maven.project.InvalidProjectModelException;
45 import org.apache.maven.project.MavenProject;
46 import org.apache.maven.project.MavenProjectBuilder;
47 import org.apache.maven.project.ProjectBuildingException;
48 import org.apache.maven.project.validation.ModelValidationResult;
49 import org.apache.maven.settings.MavenSettingsBuilder;
50 import org.apache.maven.settings.Mirror;
51 import org.apache.maven.settings.Proxy;
52 import org.apache.maven.settings.Server;
53 import org.apache.maven.settings.Settings;
54 import org.apache.maven.settings.io.xpp3.SettingsXpp3Writer;
55 import org.codehaus.plexus.PlexusConstants;
56 import org.codehaus.plexus.PlexusContainer;
57 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
58 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
59 import org.codehaus.plexus.context.Context;
60 import org.codehaus.plexus.context.ContextException;
61 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
62 import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
63 import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
64 import org.codehaus.plexus.util.StringUtils;
65 import org.codehaus.plexus.util.xml.Xpp3Dom;
66 import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70 import java.io.File;
71 import java.io.IOException;
72 import java.io.StringWriter;
73 import java.util.ArrayList;
74 import java.util.List;
75
76
77
78
79
80 public class DefaultBuildAgentMavenBuilderHelper
81 implements BuildAgentMavenBuilderHelper, Contextualizable, Initializable
82 {
83 private static final Logger log = LoggerFactory.getLogger( DefaultBuildAgentMavenBuilderHelper.class );
84
85
86
87
88 private MavenProjectBuilder projectBuilder;
89
90
91
92
93 private MavenSettingsBuilder mavenSettingsBuilder;
94
95
96
97
98 private ArtifactRepositoryFactory artifactRepositoryFactory;
99
100
101
102
103 private ArtifactRepositoryLayout defaultRepositoryLayout;
104
105 private PlexusContainer container;
106
107 public MavenProject getMavenProject( ContinuumProjectBuildingResult result, File file )
108 {
109 MavenProject project;
110
111 try
112 {
113
114
115
116 Settings settings = getSettings();
117
118 if ( log.isDebugEnabled() )
119 {
120 writeSettings( settings );
121 }
122
123 ProfileManager profileManager = new DefaultProfileManager( container, settings );
124
125 project = projectBuilder.build( file, getRepository( settings ), profileManager, false );
126
127 if ( log.isDebugEnabled() )
128 {
129 writePom( project );
130 writeActiveProfileStatement( project );
131 }
132
133 }
134 catch ( ProjectBuildingException e )
135 {
136 StringBuffer messages = new StringBuffer();
137
138 Throwable cause = e.getCause();
139
140 if ( cause != null )
141 {
142 while ( ( cause.getCause() != null ) && ( cause instanceof ProjectBuildingException ) )
143 {
144 cause = cause.getCause();
145 }
146 }
147
148 if ( e instanceof InvalidProjectModelException )
149 {
150 InvalidProjectModelException ex = (InvalidProjectModelException) e;
151
152 ModelValidationResult validationResult = ex.getValidationResult();
153
154 if ( validationResult != null && validationResult.getMessageCount() > 0 )
155 {
156 for ( String valmsg : (List<String>) validationResult.getMessages() )
157 {
158 result.addError( ContinuumProjectBuildingResult.ERROR_VALIDATION, valmsg );
159 messages.append( valmsg );
160 messages.append( "\n" );
161 }
162 }
163 }
164
165 if ( cause instanceof ArtifactNotFoundException )
166 {
167 result.addError( ContinuumProjectBuildingResult.ERROR_ARTIFACT_NOT_FOUND, ( cause ).toString() );
168 return null;
169 }
170
171 result.addError( ContinuumProjectBuildingResult.ERROR_PROJECT_BUILDING, e.getMessage() );
172
173 String msg = "Cannot build maven project from " + file + " (" + e.getMessage() + ").\n" + messages;
174
175 file.delete();
176
177 log.error( msg );
178
179 return null;
180 }
181
182 catch ( Exception e )
183 {
184 result.addError( ContinuumProjectBuildingResult.ERROR_PROJECT_BUILDING, e.getMessage() );
185
186 String msg = "Cannot build maven project from " + file + " (" + e.getMessage() + ").";
187
188 file.delete();
189
190 log.error( msg );
191
192 return null;
193 }
194
195
196
197
198
199
200 Scm scm = project.getScm();
201
202 if ( scm == null )
203 {
204 result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_SCM, getProjectName( project ) );
205
206 log.error( "Missing 'scm' element in the " + getProjectName( project ) + " POM." );
207
208 return null;
209 }
210
211 String url = scm.getConnection();
212
213 if ( StringUtils.isEmpty( url ) )
214 {
215 result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_SCM_CONNECTION, getProjectName( project ) );
216
217 log.error( "Missing 'connection' element in the 'scm' element in the " + getProjectName( project ) +
218 " POM." );
219
220 return null;
221 }
222
223 return project;
224 }
225
226 public void mapMetadataToProject( ContinuumProjectBuildingResult result, File metadata, Project continuumProject )
227 {
228 MavenProject mavenProject = getMavenProject( result, metadata );
229
230 if ( mavenProject == null )
231 {
232 result.addError( ContinuumProjectBuildingResult.ERROR_UNKNOWN,
233 "Can't load the maven project. Verify that your scm url is correct and remove/readd the project." );
234 return;
235 }
236
237 mapMavenProjectToContinuumProject( result, mavenProject, continuumProject, false );
238 }
239
240 public void mapMavenProjectToContinuumProject( ContinuumProjectBuildingResult result, MavenProject mavenProject,
241 Project continuumProject, boolean groupPom )
242 {
243 if ( mavenProject == null )
244 {
245 result.addError( ContinuumProjectBuildingResult.ERROR_UNKNOWN, "The maven project is null." );
246 return;
247 }
248
249
250
251
252
253 continuumProject.setName( getProjectName( mavenProject ) );
254
255
256
257
258
259
260 if ( StringUtils.isEmpty( continuumProject.getScmUrl() ) )
261 {
262 String scmUrl = getScmUrl( mavenProject );
263
264 continuumProject.setScmUrl( scmUrl );
265
266 if ( !"HEAD".equals( mavenProject.getScm().getTag() ) )
267 {
268 continuumProject.setScmTag( mavenProject.getScm().getTag() );
269 }
270 }
271
272
273
274
275
276 continuumProject.setVersion( getVersion( mavenProject ) );
277
278
279
280
281
282 if ( !StringUtils.isEmpty( mavenProject.getGroupId() ) )
283 {
284 continuumProject.setGroupId( mavenProject.getGroupId() );
285 }
286 else
287 {
288 result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_GROUPID );
289 return;
290 }
291
292
293
294
295
296 if ( !StringUtils.isEmpty( mavenProject.getArtifactId() ) )
297 {
298 continuumProject.setArtifactId( mavenProject.getArtifactId() );
299 }
300 else
301 {
302 result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_ARTIFACTID );
303 return;
304 }
305
306
307
308
309
310 if ( !StringUtils.isEmpty( mavenProject.getUrl() ) )
311 {
312 continuumProject.setUrl( mavenProject.getUrl() );
313 }
314
315
316
317
318
319 if ( mavenProject.getDevelopers() != null )
320 {
321 List<ProjectDeveloper> developers = new ArrayList<ProjectDeveloper>();
322
323 for ( Developer d : (List<Developer>) mavenProject.getDevelopers() )
324 {
325 ProjectDeveloper cd = new ProjectDeveloper();
326
327 cd.setScmId( d.getId() );
328
329 cd.setName( d.getName() );
330
331 cd.setEmail( d.getEmail() );
332
333 developers.add( cd );
334 }
335
336 continuumProject.setDevelopers( developers );
337 }
338
339
340
341
342
343 if ( mavenProject.getParent() != null )
344 {
345 MavenProject parentProject = mavenProject.getParent();
346
347 ProjectDependency parent = new ProjectDependency();
348
349 parent.setGroupId( parentProject.getGroupId() );
350
351 parent.setArtifactId( parentProject.getArtifactId() );
352
353 parent.setVersion( parentProject.getVersion() );
354
355 continuumProject.setParent( parent );
356 }
357
358
359
360
361
362 List<ProjectDependency> dependencies = new ArrayList<ProjectDependency>();
363
364 for ( Dependency dependency : (List<Dependency>) mavenProject.getDependencies() )
365 {
366 ProjectDependency cd = new ProjectDependency();
367
368 cd.setGroupId( dependency.getGroupId() );
369
370 cd.setArtifactId( dependency.getArtifactId() );
371
372 cd.setVersion( dependency.getVersion() );
373
374 dependencies.add( cd );
375 }
376
377 for ( Plugin dependency : (List<Plugin>) mavenProject.getBuildPlugins() )
378 {
379 ProjectDependency cd = new ProjectDependency();
380
381 cd.setGroupId( dependency.getGroupId() );
382
383 cd.setArtifactId( dependency.getArtifactId() );
384
385 cd.setVersion( dependency.getVersion() );
386
387 dependencies.add( cd );
388 }
389
390 for ( ReportPlugin dependency : (List<ReportPlugin>) mavenProject.getReportPlugins() )
391 {
392 ProjectDependency cd = new ProjectDependency();
393
394 cd.setGroupId( dependency.getGroupId() );
395
396 cd.setArtifactId( dependency.getArtifactId() );
397
398 cd.setVersion( dependency.getVersion() );
399
400 dependencies.add( cd );
401 }
402
403 for ( Extension dependency : (List<Extension>) mavenProject.getBuildExtensions() )
404 {
405 ProjectDependency cd = new ProjectDependency();
406
407 cd.setGroupId( dependency.getGroupId() );
408
409 cd.setArtifactId( dependency.getArtifactId() );
410
411 cd.setVersion( dependency.getVersion() );
412
413 dependencies.add( cd );
414 }
415
416 continuumProject.setDependencies( dependencies );
417
418
419
420
421
422 List<ProjectNotifier> userNotifiers = new ArrayList<ProjectNotifier>();
423
424 if ( continuumProject.getNotifiers() != null )
425 {
426 for ( int i = 0; i < continuumProject.getNotifiers().size(); i++ )
427 {
428 ProjectNotifier notifier = (ProjectNotifier) continuumProject.getNotifiers().get( i );
429
430 if ( notifier.isFromUser() )
431 {
432 ProjectNotifier userNotifier = new ProjectNotifier();
433
434 userNotifier.setType( notifier.getType() );
435
436 userNotifier.setEnabled( notifier.isEnabled() );
437
438 userNotifier.setConfiguration( notifier.getConfiguration() );
439
440 userNotifier.setFrom( notifier.getFrom() );
441
442 userNotifier.setRecipientType( notifier.getRecipientType() );
443
444 userNotifier.setSendOnError( notifier.isSendOnError() );
445
446 userNotifier.setSendOnFailure( notifier.isSendOnFailure() );
447
448 userNotifier.setSendOnSuccess( notifier.isSendOnSuccess() );
449
450 userNotifier.setSendOnWarning( notifier.isSendOnWarning() );
451
452 userNotifier.setSendOnScmFailure( notifier.isSendOnScmFailure() );
453
454 userNotifiers.add( userNotifier );
455 }
456 }
457 }
458
459 List<ProjectNotifier> notifiers = getNotifiers( result, mavenProject, continuumProject );
460 if ( notifiers != null )
461 {
462 continuumProject.setNotifiers( notifiers );
463 }
464
465 for ( ProjectNotifier notifier : userNotifiers )
466 {
467 continuumProject.addNotifier( notifier );
468 }
469 }
470
471 private String getScmUrl( MavenProject project )
472 {
473 return project.getScm().getConnection();
474 }
475
476 private List<ProjectNotifier> getNotifiers( ContinuumProjectBuildingResult result, MavenProject mavenProject,
477 Project continuumProject )
478 {
479 List<ProjectNotifier> notifiers = new ArrayList<ProjectNotifier>();
480
481 if ( mavenProject.getCiManagement() != null && mavenProject.getCiManagement().getNotifiers() != null )
482 {
483 for ( Notifier projectNotifier : (List<Notifier>) mavenProject.getCiManagement().getNotifiers() )
484 {
485 ProjectNotifier notifier = new ProjectNotifier();
486
487 if ( StringUtils.isEmpty( projectNotifier.getType() ) )
488 {
489 result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_NOTIFIER_TYPE );
490 return null;
491 }
492
493 notifier.setType( projectNotifier.getType() );
494
495 if ( projectNotifier.getConfiguration() == null )
496 {
497 result.addError( ContinuumProjectBuildingResult.ERROR_MISSING_NOTIFIER_CONFIGURATION );
498 return null;
499 }
500
501 notifier.setConfiguration( projectNotifier.getConfiguration() );
502
503 notifier.setFrom( ProjectNotifier.FROM_PROJECT );
504
505 notifier.setSendOnSuccess( projectNotifier.isSendOnSuccess() );
506
507 notifier.setSendOnFailure( projectNotifier.isSendOnFailure() );
508
509 notifier.setSendOnError( projectNotifier.isSendOnError() );
510
511 notifier.setSendOnWarning( projectNotifier.isSendOnWarning() );
512
513 notifier.setSendOnScmFailure( false );
514
515 notifiers.add( notifier );
516 }
517 }
518
519 return notifiers;
520 }
521
522 private String getVersion( MavenProject project )
523 {
524 return project.getVersion();
525 }
526
527 private Settings getSettings()
528 throws SettingsConfigurationException
529 {
530 try
531 {
532 return mavenSettingsBuilder.buildSettings( false );
533 }
534 catch ( IOException e )
535 {
536 throw new SettingsConfigurationException( "Error reading settings file", e );
537 }
538 catch ( XmlPullParserException e )
539 {
540 throw new SettingsConfigurationException( e.getMessage(), e.getDetail(), e.getLineNumber(),
541 e.getColumnNumber() );
542 }
543 }
544
545 private ArtifactRepository getRepository( Settings settings )
546 {
547 return artifactRepositoryFactory.createArtifactRepository( "local", "file://" + settings.getLocalRepository(),
548 defaultRepositoryLayout, null, null );
549 }
550
551 public String getProjectName( MavenProject project )
552 {
553 String name = project.getName();
554
555 if ( StringUtils.isEmpty( name ) )
556 {
557 return project.getId();
558 }
559
560 return name;
561 }
562
563 private void writeSettings( Settings settings )
564 {
565 StringWriter sWriter = new StringWriter();
566
567 SettingsXpp3Writer settingsWriter = new SettingsXpp3Writer();
568
569 try
570 {
571 settingsWriter.write( sWriter, settings );
572
573 StringBuffer message = new StringBuffer();
574
575 message.append( "\n************************************************************************************" );
576 message.append( "\nEffective Settings" );
577 message.append( "\n************************************************************************************" );
578 message.append( "\n" );
579 message.append( sWriter.toString() );
580 message.append( "\n************************************************************************************" );
581 message.append( "\n\n" );
582
583 log.debug( message.toString() );
584 }
585 catch ( IOException e )
586 {
587 log.warn( "Cannot serialize Settings to XML.", e );
588 }
589 }
590
591 private void writePom( MavenProject project )
592 {
593 StringBuffer message = new StringBuffer();
594
595 Model pom = project.getModel();
596
597 StringWriter sWriter = new StringWriter();
598
599 MavenXpp3Writer pomWriter = new MavenXpp3Writer();
600
601 try
602 {
603 pomWriter.write( sWriter, pom );
604
605 message.append( "\n************************************************************************************" );
606 message.append( "\nEffective POM for project \'" ).append( project.getId() ).append( "\'" );
607 message.append( "\n************************************************************************************" );
608 message.append( "\n" );
609 message.append( sWriter.toString() );
610 message.append( "\n************************************************************************************" );
611 message.append( "\n\n" );
612
613 log.debug( message.toString() );
614 }
615 catch ( IOException e )
616 {
617 log.warn( "Cannot serialize POM to XML.", e );
618 }
619 }
620
621 private void writeActiveProfileStatement( MavenProject project )
622 {
623 List<Profile> profiles = project.getActiveProfiles();
624
625 StringBuffer message = new StringBuffer();
626
627 message.append( "\n" );
628
629 message.append( "\n************************************************************************************" );
630 message.append( "\nActive Profiles for Project \'" ).append( project.getId() ).append( "\'" );
631 message.append( "\n************************************************************************************" );
632 message.append( "\n" );
633
634 if ( profiles == null || profiles.isEmpty() )
635 {
636 message.append( "There are no active profiles." );
637 }
638 else
639 {
640 message.append( "The following profiles are active:\n" );
641
642 for ( Profile profile : profiles )
643 {
644 message.append( "\n - " ).append( profile.getId() ).append( " (source: " ).append(
645 profile.getSource() ).append( ")" );
646 }
647
648 }
649
650 message.append( "\n************************************************************************************" );
651 message.append( "\n\n" );
652
653 log.debug( message.toString() );
654 }
655
656 public void contextualize( Context context )
657 throws ContextException
658 {
659 container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
660 }
661
662 public void initialize()
663 throws InitializationException
664 {
665 try
666 {
667 Settings settings = getSettings();
668
669 resolveParameters( settings );
670 }
671 catch ( Exception e )
672 {
673 throw new InitializationException( "Can't initialize '" + getClass().getName() + "'", e );
674 }
675 }
676
677
678
679
680
681
682
683 private void resolveParameters( Settings settings )
684 throws ComponentLookupException, ComponentLifecycleException, SettingsConfigurationException
685 {
686 WagonManager wagonManager = (WagonManager) container.lookup( WagonManager.ROLE );
687
688 try
689 {
690 Proxy proxy = settings.getActiveProxy();
691
692 if ( proxy != null )
693 {
694 if ( proxy.getHost() == null )
695 {
696 throw new SettingsConfigurationException( "Proxy in settings.xml has no host" );
697 }
698
699 wagonManager.addProxy( proxy.getProtocol(), proxy.getHost(), proxy.getPort(), proxy.getUsername(),
700 proxy.getPassword(), proxy.getNonProxyHosts() );
701 }
702
703 for ( Server server : (List<Server>) settings.getServers() )
704 {
705 wagonManager.addAuthenticationInfo( server.getId(), server.getUsername(), server.getPassword(),
706 server.getPrivateKey(), server.getPassphrase() );
707
708 wagonManager.addPermissionInfo( server.getId(), server.getFilePermissions(),
709 server.getDirectoryPermissions() );
710
711 if ( server.getConfiguration() != null )
712 {
713 wagonManager.addConfiguration( server.getId(), (Xpp3Dom) server.getConfiguration() );
714 }
715 }
716
717 for ( Mirror mirror : (List<Mirror>) settings.getMirrors() )
718 {
719 wagonManager.addMirror( mirror.getId(), mirror.getMirrorOf(), mirror.getUrl() );
720 }
721 }
722 finally
723 {
724 container.release( wagonManager );
725 }
726 }
727 }