View Javadoc

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