1 package org.apache.maven.report.projectinfo;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.commons.lang.SystemUtils;
23 import org.apache.maven.doxia.sink.Sink;
24 import org.apache.maven.model.Model;
25 import org.apache.maven.model.Scm;
26 import org.apache.maven.plugin.logging.Log;
27 import org.apache.maven.plugins.annotations.Component;
28 import org.apache.maven.plugins.annotations.Mojo;
29 import org.apache.maven.plugins.annotations.Parameter;
30 import org.apache.maven.scm.manager.NoSuchScmProviderException;
31 import org.apache.maven.scm.manager.ScmManager;
32 import org.apache.maven.scm.provider.cvslib.repository.CvsScmProviderRepository;
33 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
34 import org.apache.maven.scm.provider.hg.repository.HgScmProviderRepository;
35 import org.apache.maven.scm.provider.perforce.repository.PerforceScmProviderRepository;
36 import org.apache.maven.scm.provider.starteam.repository.StarteamScmProviderRepository;
37 import org.apache.maven.scm.provider.svn.repository.SvnScmProviderRepository;
38 import org.apache.maven.scm.repository.ScmRepository;
39 import org.apache.maven.scm.repository.ScmRepositoryException;
40 import org.codehaus.plexus.i18n.I18N;
41 import org.codehaus.plexus.util.StringUtils;
42
43 import java.util.ArrayList;
44 import java.util.List;
45 import java.util.Locale;
46
47
48
49
50
51
52
53
54 @Mojo( name = "scm" )
55 public class ScmReport
56 extends AbstractProjectInfoReport
57 {
58
59
60
61
62
63
64
65 @Component
66 protected ScmManager scmManager;
67
68
69
70
71 @Parameter( defaultValue = "${project.artifactId}" )
72 private String checkoutDirectoryName;
73
74
75
76
77
78
79
80 @Parameter( defaultValue = "${project.scm.connection}" )
81 private String anonymousConnection;
82
83
84
85
86
87
88
89 @Parameter( defaultValue = "${project.scm.developerConnection}" )
90 private String developerConnection;
91
92
93
94
95
96
97 @Parameter( defaultValue = "${project.scm.url}" )
98 private String webAccessUrl;
99
100
101
102
103
104
105 @Parameter( defaultValue = "${project.scm.tag}" )
106 private String scmTag;
107
108
109
110
111
112 @Override
113 public boolean canGenerateReport()
114 {
115 boolean result = super.canGenerateReport();
116 if ( result && skipEmptyReport )
117 {
118 Scm scm = getProject().getModel().getScm();
119 result = scm != null;
120
121 if ( result && StringUtils.isEmpty( anonymousConnection )
122 && StringUtils.isEmpty( developerConnection )
123 && StringUtils.isEmpty( scm.getUrl() ) )
124 {
125 result = false;
126 }
127 }
128
129 return result;
130 }
131
132 @Override
133 public void executeReport( Locale locale )
134 {
135 ScmRenderer r =
136 new ScmRenderer( getLog(), scmManager, getSink(), getProject().getModel(), getI18N( locale ), locale,
137 checkoutDirectoryName, webAccessUrl, anonymousConnection, developerConnection, scmTag );
138
139 r.render();
140 }
141
142
143 public String getOutputName()
144 {
145 return "source-repository";
146 }
147
148 @Override
149 protected String getI18Nsection()
150 {
151 return "scm";
152 }
153
154
155
156
157
158
159
160
161 private static class ScmRenderer
162 extends AbstractProjectInfoRenderer
163 {
164 private Log log;
165
166 private Model model;
167
168 private ScmManager scmManager;
169
170
171
172
173 private String anonymousConnection;
174
175 private String devConnection;
176
177 private String checkoutDirectoryName;
178
179 private String webAccessUrl;
180
181 private String scmTag;
182
183 ScmRenderer( Log log, ScmManager scmManager, Sink sink, Model model, I18N i18n, Locale locale,
184 String checkoutDirName, String webAccessUrl, String anonymousConnection, String devConnection,
185 String scmTag )
186 {
187 super( sink, i18n, locale );
188
189 this.log = log;
190
191 this.scmManager = scmManager;
192
193 this.model = model;
194
195 this.checkoutDirectoryName = checkoutDirName;
196
197 this.webAccessUrl = webAccessUrl;
198
199 this.anonymousConnection = anonymousConnection;
200
201 this.devConnection = devConnection;
202
203 this.scmTag = scmTag;
204 }
205
206 @Override
207 protected String getI18Nsection()
208 {
209 return "scm";
210 }
211
212 @Override
213 public void renderBody()
214 {
215 Scm scm = model.getScm();
216 if ( scm == null || StringUtils.isEmpty( anonymousConnection )
217 && StringUtils.isEmpty( devConnection )
218 && StringUtils.isEmpty( scm.getUrl() ) )
219 {
220 startSection( getTitle() );
221
222 paragraph( getI18nString( "noscm" ) );
223
224 endSection();
225
226 return;
227 }
228
229 ScmRepository anonymousRepository = getScmRepository( anonymousConnection );
230 ScmRepository devRepository = getScmRepository( devConnection );
231
232
233 renderOverviewSection( anonymousRepository, devRepository );
234
235
236 renderWebAccessSection( webAccessUrl );
237
238
239 renderAnonymousAccessSection( anonymousRepository );
240
241
242 renderDeveloperAccessSection( devRepository );
243
244
245 renderAccessBehindFirewallSection( devRepository );
246
247
248 renderAccessThroughProxySection( anonymousRepository, devRepository );
249 }
250
251
252
253
254
255
256
257 private void renderOverviewSection( ScmRepository anonymousRepository, ScmRepository devRepository )
258 {
259 startSection( getI18nString( "overview.title" ) );
260
261 if ( isScmSystem( anonymousRepository, "clearcase" ) || isScmSystem( devRepository, "clearcase" ) )
262 {
263 sink.paragraph();
264 linkPatternedText( getI18nString( "clearcase.intro" ) );
265 sink.paragraph_();
266 }
267 else if ( isScmSystem( anonymousRepository, "cvs" ) || isScmSystem( devRepository, "cvs" ) )
268 {
269 sink.paragraph();
270 linkPatternedText( getI18nString( "cvs.intro" ) );
271 sink.paragraph_();
272 }
273 else if ( isScmSystem( anonymousRepository, "git" ) || isScmSystem( devRepository, "git" ) )
274 {
275 sink.paragraph();
276 linkPatternedText( getI18nString( "git.intro" ) );
277 sink.paragraph_();
278 }
279 else if ( isScmSystem( anonymousRepository, "hg" ) || isScmSystem( devRepository, "hg" ) )
280 {
281 sink.paragraph();
282 linkPatternedText( getI18nString( "hg.intro" ) );
283 sink.paragraph_();
284 }
285 else if ( isScmSystem( anonymousRepository, "perforce" ) || isScmSystem( devRepository, "perforce" ) )
286 {
287 sink.paragraph();
288 linkPatternedText( getI18nString( "perforce.intro" ) );
289 sink.paragraph_();
290 }
291 else if ( isScmSystem( anonymousRepository, "starteam" ) || isScmSystem( devRepository, "starteam" ) )
292 {
293 sink.paragraph();
294 linkPatternedText( getI18nString( "starteam.intro" ) );
295 sink.paragraph_();
296 }
297 else if ( isScmSystem( anonymousRepository, "svn" ) || isScmSystem( devRepository, "svn" ) )
298 {
299 sink.paragraph();
300 linkPatternedText( getI18nString( "svn.intro" ) );
301 sink.paragraph_();
302 }
303 else
304 {
305 paragraph( getI18nString( "general.intro" ) );
306 }
307
308 endSection();
309 }
310
311
312
313
314
315
316 private void renderWebAccessSection( String scmUrl )
317 {
318 startSection( getI18nString( "webaccess.title" ) );
319
320 if ( StringUtils.isEmpty( scmUrl ) )
321 {
322 paragraph( getI18nString( "webaccess.nourl" ) );
323 }
324 else
325 {
326 paragraph( getI18nString( "webaccess.url" ) );
327
328 verbatimLink( scmUrl, scmUrl );
329 }
330
331 endSection();
332 }
333
334
335
336
337
338
339
340
341
342 private void renderAnonymousAccessSection( ScmRepository anonymousRepository )
343 {
344 if ( isScmSystem( anonymousRepository, "clearcase" ) || isScmSystem( anonymousRepository, "perforce" )
345 || isScmSystem( anonymousRepository, "starteam" ) || StringUtils.isEmpty( anonymousConnection ) )
346 {
347 return;
348 }
349
350 startSection( getI18nString( "anonymousaccess.title" ) );
351
352 if ( anonymousRepository != null && isScmSystem( anonymousRepository, "cvs" ) )
353 {
354 CvsScmProviderRepository cvsRepo =
355 (CvsScmProviderRepository) anonymousRepository.getProviderRepository();
356
357 anonymousAccessCVS( cvsRepo );
358 }
359 else if ( anonymousRepository != null && isScmSystem( anonymousRepository, "git" ) )
360 {
361 GitScmProviderRepository gitRepo =
362 (GitScmProviderRepository) anonymousRepository.getProviderRepository();
363
364 anonymousAccessGit( gitRepo );
365 }
366 else if ( anonymousRepository != null && isScmSystem( anonymousRepository, "hg" ) )
367 {
368 HgScmProviderRepository hgRepo = (HgScmProviderRepository) anonymousRepository.getProviderRepository();
369
370 anonymousAccessMercurial( hgRepo );
371 }
372 else if ( anonymousRepository != null && isScmSystem( anonymousRepository, "svn" ) )
373 {
374 SvnScmProviderRepository svnRepo =
375 (SvnScmProviderRepository) anonymousRepository.getProviderRepository();
376
377 anonymousAccessSubversion( svnRepo );
378 }
379 else
380 {
381 paragraph( getI18nString( "anonymousaccess.general.intro" ) );
382
383 verbatimText( anonymousConnection.substring( 4 ) );
384 }
385
386 endSection();
387 }
388
389
390
391
392
393
394 private void renderDeveloperAccessSection( ScmRepository devRepository )
395 {
396 if ( StringUtils.isEmpty( devConnection ) )
397 {
398 return;
399 }
400
401 startSection( getI18nString( "devaccess.title" ) );
402
403 if ( devRepository != null && isScmSystem( devRepository, "clearcase" ) )
404 {
405 developerAccessClearCase();
406 }
407 else if ( devRepository != null && isScmSystem( devRepository, "cvs" ) )
408 {
409 CvsScmProviderRepository cvsRepo = (CvsScmProviderRepository) devRepository.getProviderRepository();
410
411 developerAccessCVS( cvsRepo );
412 }
413 else if ( devRepository != null && isScmSystem( devRepository, "git" ) )
414 {
415 GitScmProviderRepository gitRepo = (GitScmProviderRepository) devRepository.getProviderRepository();
416
417 developerAccessGit( gitRepo );
418 }
419 else if ( devRepository != null && isScmSystem( devRepository, "hg" ) )
420 {
421 HgScmProviderRepository hgRepo = (HgScmProviderRepository) devRepository.getProviderRepository();
422
423 developerAccessMercurial( hgRepo );
424 }
425 else if ( devRepository != null && isScmSystem( devRepository, "perforce" ) )
426 {
427 PerforceScmProviderRepository perforceRepo =
428 (PerforceScmProviderRepository) devRepository.getProviderRepository();
429
430 developerAccessPerforce( perforceRepo );
431 }
432 else if ( devRepository != null && isScmSystem( devRepository, "starteam" ) )
433 {
434 StarteamScmProviderRepository starteamRepo =
435 (StarteamScmProviderRepository) devRepository.getProviderRepository();
436
437 developerAccessStarteam( starteamRepo );
438 }
439 else if ( devRepository != null && isScmSystem( devRepository, "svn" ) )
440 {
441 SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) devRepository.getProviderRepository();
442
443 developerAccessSubversion( svnRepo );
444 }
445 else
446 {
447 paragraph( getI18nString( "devaccess.general.intro" ) );
448
449 verbatimText( devConnection.substring( 4 ) );
450 }
451
452 endSection();
453 }
454
455
456
457
458
459
460 private void renderAccessBehindFirewallSection( ScmRepository devRepository )
461 {
462 startSection( getI18nString( "accessbehindfirewall.title" ) );
463
464 if ( devRepository != null && isScmSystem( devRepository, "svn" ) )
465 {
466 SvnScmProviderRepository svnRepo = (SvnScmProviderRepository) devRepository.getProviderRepository();
467
468 paragraph( getI18nString( "accessbehindfirewall.svn.intro" ) );
469
470 verbatimText( "$ svn checkout " + svnRepo.getUrl() + " " + checkoutDirectoryName );
471 }
472 else if ( devRepository != null && isScmSystem( devRepository, "cvs" ) )
473 {
474 linkPatternedText( getI18nString( "accessbehindfirewall.cvs.intro" ) );
475 }
476 else
477 {
478 paragraph( getI18nString( "accessbehindfirewall.general.intro" ) );
479 }
480
481 endSection();
482 }
483
484
485
486
487
488
489
490 private void renderAccessThroughProxySection( ScmRepository anonymousRepository, ScmRepository devRepository )
491 {
492 if ( isScmSystem( anonymousRepository, "svn" ) || isScmSystem( devRepository, "svn" ) )
493 {
494 startSection( getI18nString( "accessthroughtproxy.title" ) );
495
496 paragraph( getI18nString( "accessthroughtproxy.svn.intro1" ) );
497 paragraph( getI18nString( "accessthroughtproxy.svn.intro2" ) );
498 paragraph( getI18nString( "accessthroughtproxy.svn.intro3" ) );
499
500 verbatimText( "[global]" + SystemUtils.LINE_SEPARATOR + "http-proxy-host = your.proxy.name"
501 + SystemUtils.LINE_SEPARATOR + "http-proxy-port = 3128" + SystemUtils.LINE_SEPARATOR );
502
503 endSection();
504 }
505 }
506
507
508
509
510
511
512
513
514
515
516 private void developerAccessClearCase()
517 {
518 paragraph( getI18nString( "devaccess.clearcase.intro" ) );
519
520 verbatimText( "$ cleartool checkout " );
521 }
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541 private void anonymousAccessCVS( CvsScmProviderRepository cvsRepo )
542 {
543 paragraph( getI18nString( "anonymousaccess.cvs.intro" ) );
544
545 verbatimText( "$ cvs -d " + cvsRepo.getCvsRoot() + " login" + SystemUtils.LINE_SEPARATOR + "$ cvs -z3 -d "
546 + cvsRepo.getCvsRoot() + " co " + cvsRepo.getModule() );
547 }
548
549
550
551 private void gitClone( String url )
552 {
553
554
555 int index = url.indexOf( ".git/" );
556 if ( index > 0 )
557 {
558 url = url.substring( 0, index + 4 );
559 }
560
561 boolean head = StringUtils.isEmpty( scmTag ) || "HEAD".equals( scmTag );
562 verbatimText( "$ git clone " + ( head ? "" : ( "--branch " + scmTag + ' ' ) ) + url );
563 }
564
565
566
567
568
569
570
571
572
573
574 private void anonymousAccessGit( GitScmProviderRepository gitRepo )
575 {
576 sink.paragraph();
577 linkPatternedText( getI18nString( "anonymousaccess.git.intro" ) );
578 sink.paragraph_();
579
580 gitClone( gitRepo.getFetchUrl() );
581 }
582
583
584
585
586
587
588
589
590
591
592
593
594 private void anonymousAccessMercurial( HgScmProviderRepository hgRepo )
595 {
596 sink.paragraph();
597 linkPatternedText( getI18nString( "anonymousaccess.hg.intro" ) );
598 sink.paragraph_();
599
600 verbatimText( "$ hg clone " + hgRepo.getURI() );
601 }
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619 private void developerAccessCVS( CvsScmProviderRepository cvsRepo )
620 {
621 paragraph( getI18nString( "devaccess.cvs.intro" ) );
622
623
624 String cvsRoot = StringUtils.replace( cvsRepo.getCvsRoot(), cvsRepo.getUser(), "username" );
625
626 verbatimText( "$ cvs -d " + cvsRoot + " login" + SystemUtils.LINE_SEPARATOR + "$ cvs -z3 -d " + cvsRoot
627 + " co " + cvsRepo.getModule() );
628 }
629
630
631
632
633
634
635
636
637
638
639
640
641 private void developerAccessGit( GitScmProviderRepository gitRepo )
642 {
643 sink.paragraph();
644 linkPatternedText( getI18nString( "devaccess.git.intro" ) );
645 sink.paragraph_();
646
647 gitClone( gitRepo.getPushUrl() );
648 }
649
650
651
652
653
654
655
656
657
658
659
660
661 private void developerAccessMercurial( HgScmProviderRepository hgRepo )
662 {
663 sink.paragraph();
664 linkPatternedText( getI18nString( "devaccess.hg.intro" ) );
665 sink.paragraph_();
666
667 verbatimText( "$ hg clone " + hgRepo.getURI() );
668 }
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690 private void developerAccessPerforce( PerforceScmProviderRepository perforceRepo )
691 {
692 paragraph( getI18nString( "devaccess.perforce.intro" ) );
693
694 StringBuilder command = new StringBuilder();
695 command.append( "$ p4" );
696 if ( !StringUtils.isEmpty( perforceRepo.getHost() ) )
697 {
698 command.append( " -H " ).append( perforceRepo.getHost() );
699 }
700 if ( perforceRepo.getPort() > 0 )
701 {
702 command.append( " -p " ).append( perforceRepo.getPort() );
703 }
704 command.append( " -u username" );
705 command.append( " -P password" );
706 command.append( " " );
707 command.append( perforceRepo.getPath() );
708 command.append( SystemUtils.LINE_SEPARATOR );
709 command.append( "$ p4 submit -c \"A comment\"" );
710
711 verbatimText( command.toString() );
712 }
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728 private void developerAccessStarteam( StarteamScmProviderRepository starteamRepo )
729 {
730 paragraph( getI18nString( "devaccess.starteam.intro" ) );
731
732 StringBuilder command = new StringBuilder();
733
734
735 String fullUrl = StringUtils.replace( starteamRepo.getFullUrl(), starteamRepo.getUser(), "username" );
736 fullUrl = StringUtils.replace( fullUrl, starteamRepo.getPassword(), "password" );
737
738 command.append( "$ stcmd co -x -nologo -stop -p " );
739 command.append( fullUrl );
740 command.append( " -is" );
741 command.append( SystemUtils.LINE_SEPARATOR );
742 command.append( "$ stcmd ci -x -nologo -stop -p " );
743 command.append( fullUrl );
744 command.append( " -f NCI -is" );
745
746 verbatimText( command.toString() );
747 }
748
749
750
751
752
753
754
755
756
757
758
759
760
761 private void anonymousAccessSubversion( SvnScmProviderRepository svnRepo )
762 {
763 paragraph( getI18nString( "anonymousaccess.svn.intro" ) );
764
765 verbatimText( "$ svn checkout " + svnRepo.getUrl() + " " + checkoutDirectoryName );
766 }
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781 private void developerAccessSubversion( SvnScmProviderRepository svnRepo )
782 {
783 if ( svnRepo.getUrl() != null )
784 {
785 if ( svnRepo.getUrl().startsWith( "https://" ) )
786 {
787 paragraph( getI18nString( "devaccess.svn.intro1.https" ) );
788 }
789 else if ( svnRepo.getUrl().startsWith( "svn://" ) )
790 {
791 paragraph( getI18nString( "devaccess.svn.intro1.svn" ) );
792 }
793 else if ( svnRepo.getUrl().startsWith( "svn+ssh://" ) )
794 {
795 paragraph( getI18nString( "devaccess.svn.intro1.svnssh" ) );
796 }
797 else
798 {
799 paragraph( getI18nString( "devaccess.svn.intro1.other" ) );
800 }
801 }
802
803 StringBuilder sb = new StringBuilder();
804
805 sb.append( "$ svn checkout " ).append( svnRepo.getUrl() ).append( " " ).append( checkoutDirectoryName );
806
807 verbatimText( sb.toString() );
808
809 paragraph( getI18nString( "devaccess.svn.intro2" ) );
810
811 sb = new StringBuilder();
812 sb.append( "$ svn commit --username your-username -m \"A message\"" );
813
814 verbatimText( sb.toString() );
815 }
816
817
818
819
820
821
822
823 public ScmRepository getScmRepository( String scmUrl )
824 {
825 if ( StringUtils.isEmpty( scmUrl ) )
826 {
827 return null;
828 }
829
830 ScmRepository repo = null;
831 List<String> messages = new ArrayList<String>();
832 try
833 {
834 messages.addAll( scmManager.validateScmRepository( scmUrl ) );
835 }
836 catch ( Exception e )
837 {
838 messages.add( e.getMessage() );
839 }
840
841 if ( messages.size() > 0 )
842 {
843 StringBuilder sb = new StringBuilder();
844 boolean isIntroAdded = false;
845 for ( String msg : messages )
846 {
847
848
849 if ( msg.startsWith( "No such provider" ) )
850 {
851 continue;
852 }
853
854 if ( !isIntroAdded )
855 {
856 sb.append( "This SCM url '" );
857 sb.append( scmUrl );
858 sb.append( "' is invalid due to the following errors:" );
859 sb.append( SystemUtils.LINE_SEPARATOR );
860 isIntroAdded = true;
861 }
862 sb.append( " * " );
863 sb.append( msg );
864 sb.append( SystemUtils.LINE_SEPARATOR );
865 }
866
867 if ( StringUtils.isNotEmpty( sb.toString() ) )
868 {
869 sb.append( "For more information about SCM URL Format, please refer to: "
870 + "http://maven.apache.org/scm/scm-url-format.html" );
871
872 throw new IllegalArgumentException( sb.toString() );
873 }
874 }
875
876 try
877 {
878 repo = scmManager.makeScmRepository( scmUrl );
879 }
880 catch ( NoSuchScmProviderException e )
881 {
882 if ( log.isDebugEnabled() )
883 {
884 log.debug( e.getMessage(), e );
885 }
886 }
887 catch ( ScmRepositoryException e )
888 {
889 if ( log.isDebugEnabled() )
890 {
891 log.debug( e.getMessage(), e );
892 }
893 }
894 catch ( Exception e )
895 {
896
897 if ( log.isDebugEnabled() )
898 {
899 log.debug( e.getMessage(), e );
900 }
901 }
902
903 return repo;
904 }
905
906
907
908
909
910
911
912
913
914
915
916
917
918 private static boolean isScmSystem( ScmRepository scmRepository, String scmProvider )
919 {
920 if ( StringUtils.isEmpty( scmProvider ) )
921 {
922 return false;
923 }
924
925 if ( scmRepository != null && scmProvider.equalsIgnoreCase( scmRepository.getProvider() ) )
926 {
927 return true;
928 }
929
930 return false;
931 }
932 }
933 }