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