View Javadoc
1   package org.apache.maven.scm.manager;
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.maven.scm.ScmBranch;
23  import org.apache.maven.scm.ScmBranchParameters;
24  import org.apache.maven.scm.ScmException;
25  import org.apache.maven.scm.ScmFileSet;
26  import org.apache.maven.scm.ScmTagParameters;
27  import org.apache.maven.scm.ScmVersion;
28  import org.apache.maven.scm.command.add.AddScmResult;
29  import org.apache.maven.scm.command.blame.BlameScmRequest;
30  import org.apache.maven.scm.command.blame.BlameScmResult;
31  import org.apache.maven.scm.command.branch.BranchScmResult;
32  import org.apache.maven.scm.command.changelog.ChangeLogScmRequest;
33  import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
34  import org.apache.maven.scm.command.checkin.CheckInScmResult;
35  import org.apache.maven.scm.command.checkout.CheckOutScmResult;
36  import org.apache.maven.scm.command.diff.DiffScmResult;
37  import org.apache.maven.scm.command.edit.EditScmResult;
38  import org.apache.maven.scm.command.export.ExportScmResult;
39  import org.apache.maven.scm.command.list.ListScmResult;
40  import org.apache.maven.scm.command.mkdir.MkdirScmResult;
41  import org.apache.maven.scm.command.remove.RemoveScmResult;
42  import org.apache.maven.scm.command.status.StatusScmResult;
43  import org.apache.maven.scm.command.tag.TagScmResult;
44  import org.apache.maven.scm.command.unedit.UnEditScmResult;
45  import org.apache.maven.scm.command.update.UpdateScmResult;
46  import org.apache.maven.scm.log.ScmLogger;
47  import org.apache.maven.scm.provider.ScmProvider;
48  import org.apache.maven.scm.provider.ScmProviderRepository;
49  import org.apache.maven.scm.provider.ScmUrlUtils;
50  import org.apache.maven.scm.repository.ScmRepository;
51  import org.apache.maven.scm.repository.ScmRepositoryException;
52  import org.apache.maven.scm.repository.UnknownRepositoryStructure;
53  
54  import java.io.File;
55  import java.util.ArrayList;
56  import java.util.Date;
57  import java.util.HashMap;
58  import java.util.List;
59  import java.util.Map;
60  import java.util.Map.Entry;
61  
62  /**
63   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
64   * @author <a href="mailto:brett@apache.org">Brett Porter</a>
65   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
66   *
67   */
68  public abstract class AbstractScmManager
69      implements ScmManager
70  {
71      private Map<String, ScmProvider> scmProviders = new HashMap<String, ScmProvider>();
72  
73      private ScmLogger logger;
74  
75      private Map<String, String> userProviderTypes = new HashMap<String, String>();
76  
77      protected void setScmProviders( Map<String, ScmProvider> providers )
78      {
79          this.scmProviders = providers;
80      }
81  
82      /**
83       * @deprecated use {@link #setScmProvider(String, ScmProvider)} instead
84       */
85      protected void addScmProvider( String providerType, ScmProvider provider )
86      {
87          setScmProvider( providerType, provider );
88      }
89  
90      /**
91       * Set a provider to be used for a type of SCM.
92       * If there was already a designed provider for that type it will be replaced.
93       *
94       * @param providerType the type of SCM, eg. <code>svn</code>, <code>cvs</code>
95       * @param provider     the provider that will be used for that SCM type
96       */
97      public void setScmProvider( String providerType, ScmProvider provider )
98      {
99          scmProviders.put( providerType, provider );
100     }
101 
102     protected abstract ScmLogger getScmLogger();
103 
104     // ----------------------------------------------------------------------
105     // ScmManager Implementation
106     // ----------------------------------------------------------------------
107 
108     /**
109      * {@inheritDoc}
110      */
111     public ScmProvider getProviderByUrl( String scmUrl )
112         throws ScmRepositoryException, NoSuchScmProviderException
113     {
114         if ( scmUrl == null )
115         {
116             throw new NullPointerException( "The scm url cannot be null." );
117         }
118 
119         String providerType = ScmUrlUtils.getProvider( scmUrl );
120 
121         return getProviderByType( providerType );
122     }
123 
124     /**
125      * {@inheritDoc}
126      */
127     public void setScmProviderImplementation( String providerType, String providerImplementation )
128     {
129         userProviderTypes.put( providerType, providerImplementation );
130     }
131 
132     /**
133      * {@inheritDoc}
134      */
135     public ScmProvider getProviderByType( String providerType )
136         throws NoSuchScmProviderException
137     {
138         if ( logger == null )
139         {
140             logger = getScmLogger();
141 
142             for ( Entry<String, ScmProvider> entry : scmProviders.entrySet() )
143             {
144                 ScmProvider p = entry.getValue();
145 
146                 p.addListener( logger );
147             }
148         }
149 
150         String usedProviderType = System.getProperty( "maven.scm.provider." + providerType + ".implementation" );
151 
152         if ( usedProviderType == null )
153         {
154             if ( userProviderTypes.containsKey( providerType ) )
155             {
156                 usedProviderType = userProviderTypes.get( providerType );
157             }
158             else
159             {
160                 usedProviderType = providerType;
161             }
162         }
163 
164         ScmProvider scmProvider = scmProviders.get( usedProviderType );
165 
166         if ( scmProvider == null )
167         {
168             throw new NoSuchScmProviderException( usedProviderType );
169         }
170 
171         return scmProvider;
172     }
173 
174     /**
175      * {@inheritDoc}
176      */
177     public ScmProvider getProviderByRepository( ScmRepository repository )
178         throws NoSuchScmProviderException
179     {
180         return getProviderByType( repository.getProvider() );
181     }
182 
183     // ----------------------------------------------------------------------
184     // Repository
185     // ----------------------------------------------------------------------
186 
187     /**
188      * {@inheritDoc}
189      */
190     public ScmRepository makeScmRepository( String scmUrl )
191         throws ScmRepositoryException, NoSuchScmProviderException
192     {
193         if ( scmUrl == null )
194         {
195             throw new NullPointerException( "The scm url cannot be null." );
196         }
197 
198         char delimiter = ScmUrlUtils.getDelimiter( scmUrl ).charAt( 0 );
199 
200         String providerType = ScmUrlUtils.getProvider( scmUrl );
201 
202         ScmProvider provider = getProviderByType( providerType );
203 
204         String scmSpecificUrl = cleanScmUrl( scmUrl.substring( providerType.length() + 5 ) );
205 
206         ScmProviderRepository providerRepository = provider.makeProviderScmRepository( scmSpecificUrl, delimiter );
207 
208         return new ScmRepository( providerType, providerRepository );
209     }
210 
211     /**
212      * Clean the SCM url by removing all ../ in path
213      *
214      * @param scmUrl the SCM url
215      * @return the cleaned SCM url
216      */
217     protected String cleanScmUrl( String scmUrl )
218     {
219         if ( scmUrl == null )
220         {
221             throw new NullPointerException( "The scm url cannot be null." );
222         }
223 
224         String pathSeparator = "";
225 
226         int indexOfDoubleDot = -1;
227 
228         // Clean Unix path
229         if ( scmUrl.indexOf( "../" ) > 1 )
230         {
231             pathSeparator = "/";
232 
233             indexOfDoubleDot = scmUrl.indexOf( "../" );
234         }
235 
236         // Clean windows path
237         if ( scmUrl.indexOf( "..\\" ) > 1 )
238         {
239             pathSeparator = "\\";
240 
241             indexOfDoubleDot = scmUrl.indexOf( "..\\" );
242         }
243 
244         if ( indexOfDoubleDot > 1 )
245         {
246             int startOfTextToRemove = scmUrl.substring( 0, indexOfDoubleDot - 1 ).lastIndexOf( pathSeparator );
247 
248             String beginUrl = "";
249             if ( startOfTextToRemove >= 0 )
250             {
251                 beginUrl = scmUrl.substring( 0, startOfTextToRemove );
252             }
253 
254             String endUrl = scmUrl.substring( indexOfDoubleDot + 3 );
255 
256             scmUrl = beginUrl + pathSeparator + endUrl;
257 
258             // Check if we have other double dot
259             if ( scmUrl.indexOf( "../" ) > 1 || scmUrl.indexOf( "..\\" ) > 1 )
260             {
261                 scmUrl = cleanScmUrl( scmUrl );
262             }
263         }
264 
265         return scmUrl;
266     }
267 
268     /**
269      * {@inheritDoc}
270      */
271     public ScmRepository makeProviderScmRepository( String providerType, File path )
272         throws ScmRepositoryException, UnknownRepositoryStructure, NoSuchScmProviderException
273     {
274         if ( providerType == null )
275         {
276             throw new NullPointerException( "The provider type cannot be null." );
277         }
278 
279         ScmProvider provider = getProviderByType( providerType );
280 
281         ScmProviderRepository providerRepository = provider.makeProviderScmRepository( path );
282 
283         return new ScmRepository( providerType, providerRepository );
284     }
285 
286     /**
287      * {@inheritDoc}
288      */
289     public List<String> validateScmRepository( String scmUrl )
290     {
291         List<String> messages = new ArrayList<String>();
292 
293         messages.addAll( ScmUrlUtils.validate( scmUrl ) );
294 
295         String providerType = ScmUrlUtils.getProvider( scmUrl );
296 
297         ScmProvider provider;
298 
299         try
300         {
301             provider = getProviderByType( providerType );
302         }
303         catch ( NoSuchScmProviderException e )
304         {
305             messages.add( "No such provider installed '" + providerType + "'." );
306 
307             return messages;
308         }
309 
310         String scmSpecificUrl = cleanScmUrl( scmUrl.substring( providerType.length() + 5 ) );
311 
312         List<String> providerMessages =
313             provider.validateScmUrl( scmSpecificUrl, ScmUrlUtils.getDelimiter( scmUrl ).charAt( 0 ) );
314 
315         if ( providerMessages == null )
316         {
317             throw new RuntimeException( "The SCM provider cannot return null from validateScmUrl()." );
318         }
319 
320         messages.addAll( providerMessages );
321 
322         return messages;
323     }
324 
325     /**
326      * {@inheritDoc}
327      */
328     public AddScmResult add( ScmRepository repository, ScmFileSet fileSet )
329         throws ScmException
330     {
331         return this.getProviderByRepository( repository ).add( repository, fileSet );
332     }
333 
334     /**
335      * {@inheritDoc}
336      */
337     public AddScmResult add( ScmRepository repository, ScmFileSet fileSet, String message )
338         throws ScmException
339     {
340         return this.getProviderByRepository( repository ).add( repository, fileSet, message );
341     }
342 
343     /**
344      * {@inheritDoc}
345      */
346     public BranchScmResult branch( ScmRepository repository, ScmFileSet fileSet, String branchName )
347         throws ScmException
348     {
349         ScmBranchParameters scmBranchParameters = new ScmBranchParameters( "" );
350         return this.getProviderByRepository( repository ).branch( repository, fileSet, branchName,
351                                                                   scmBranchParameters );
352     }
353 
354     /**
355      * {@inheritDoc}
356      */
357     public BranchScmResult branch( ScmRepository repository, ScmFileSet fileSet, String branchName, String message )
358         throws ScmException
359     {
360         ScmBranchParameters scmBranchParameters = new ScmBranchParameters( message );
361         return this.getProviderByRepository( repository ).branch( repository, fileSet, branchName,
362                                                                   scmBranchParameters );
363     }
364 
365     /**
366      * {@inheritDoc}
367      */
368     public ChangeLogScmResult changeLog( ScmRepository repository, ScmFileSet fileSet, Date startDate, Date endDate,
369                                          int numDays, ScmBranch branch )
370         throws ScmException
371     {
372         return this.getProviderByRepository( repository ).changeLog( repository, fileSet, startDate, endDate, numDays,
373                                                                      branch );
374     }
375 
376     /**
377      * {@inheritDoc}
378      */
379     public ChangeLogScmResult changeLog( ScmRepository repository, ScmFileSet fileSet, Date startDate, Date endDate,
380                                          int numDays, ScmBranch branch, String datePattern )
381         throws ScmException
382     {
383         return this.getProviderByRepository( repository ).changeLog( repository, fileSet, startDate, endDate, numDays,
384                                                                      branch, datePattern );
385     }
386 
387     /**
388      * {@inheritDoc}
389      */
390     public ChangeLogScmResult changeLog( ChangeLogScmRequest scmRequest )
391         throws ScmException
392     {
393         return this.getProviderByRepository( scmRequest.getScmRepository() ).changeLog( scmRequest );
394     }
395 
396     /**
397      * {@inheritDoc}
398      */
399     public ChangeLogScmResult changeLog( ScmRepository repository, ScmFileSet fileSet, ScmVersion startVersion,
400                                          ScmVersion endVersion )
401         throws ScmException
402     {
403         return this.getProviderByRepository( repository ).changeLog( repository, fileSet, startVersion, endVersion );
404     }
405 
406     /**
407      * {@inheritDoc}
408      */
409     public ChangeLogScmResult changeLog( ScmRepository repository, ScmFileSet fileSet, ScmVersion startRevision,
410                                          ScmVersion endRevision, String datePattern )
411         throws ScmException
412     {
413         return this.getProviderByRepository( repository ).changeLog( repository, fileSet, startRevision, endRevision,
414                                                                      datePattern );
415     }
416 
417     /**
418      * {@inheritDoc}
419      */
420     public CheckInScmResult checkIn( ScmRepository repository, ScmFileSet fileSet, String message )
421         throws ScmException
422     {
423         return this.getProviderByRepository( repository ).checkIn( repository, fileSet, message );
424     }
425 
426     /**
427      * {@inheritDoc}
428      */
429     public CheckInScmResult checkIn( ScmRepository repository, ScmFileSet fileSet, ScmVersion revision, String message )
430         throws ScmException
431     {
432         return this.getProviderByRepository( repository ).checkIn( repository, fileSet, revision, message );
433     }
434 
435     /**
436      * {@inheritDoc}
437      */
438     public CheckOutScmResult checkOut( ScmRepository repository, ScmFileSet fileSet )
439         throws ScmException
440     {
441         return this.getProviderByRepository( repository ).checkOut( repository, fileSet );
442     }
443 
444     /**
445      * {@inheritDoc}
446      */
447     public CheckOutScmResult checkOut( ScmRepository repository, ScmFileSet fileSet, ScmVersion version )
448         throws ScmException
449     {
450         return this.getProviderByRepository( repository ).checkOut( repository, fileSet, version );
451     }
452 
453     /**
454      * {@inheritDoc}
455      */
456     public CheckOutScmResult checkOut( ScmRepository repository, ScmFileSet fileSet, boolean recursive )
457         throws ScmException
458     {
459         return this.getProviderByRepository( repository ).checkOut( repository, fileSet, recursive );
460     }
461 
462     /**
463      * {@inheritDoc}
464      */
465     public CheckOutScmResult checkOut( ScmRepository repository, ScmFileSet fileSet, ScmVersion version,
466                                        boolean recursive )
467         throws ScmException
468     {
469         return this.getProviderByRepository( repository ).checkOut( repository, fileSet, version, recursive );
470     }
471 
472     /**
473      * {@inheritDoc}
474      */
475     public DiffScmResult diff( ScmRepository repository, ScmFileSet fileSet, ScmVersion startVersion,
476                                ScmVersion endVersion )
477         throws ScmException
478     {
479         return this.getProviderByRepository( repository ).diff( repository, fileSet, startVersion, endVersion );
480     }
481 
482     /**
483      * {@inheritDoc}
484      */
485     public EditScmResult edit( ScmRepository repository, ScmFileSet fileSet )
486         throws ScmException
487     {
488         return this.getProviderByRepository( repository ).edit( repository, fileSet );
489     }
490 
491     /**
492      * {@inheritDoc}
493      */
494     public ExportScmResult export( ScmRepository repository, ScmFileSet fileSet )
495         throws ScmException
496     {
497         return this.getProviderByRepository( repository ).export( repository, fileSet );
498     }
499 
500     /**
501      * {@inheritDoc}
502      */
503     public ExportScmResult export( ScmRepository repository, ScmFileSet fileSet, ScmVersion version )
504         throws ScmException
505     {
506         return this.getProviderByRepository( repository ).export( repository, fileSet, version );
507     }
508 
509     /**
510      * {@inheritDoc}
511      */
512     public ExportScmResult export( ScmRepository repository, ScmFileSet fileSet, String outputDirectory )
513         throws ScmException
514     {
515         return this.getProviderByRepository( repository ).export( repository, fileSet, (ScmVersion) null,
516                                                                   outputDirectory );
517     }
518 
519     /**
520      * {@inheritDoc}
521      */
522     public ExportScmResult export( ScmRepository repository, ScmFileSet fileSet, ScmVersion version,
523                                    String outputDirectory )
524         throws ScmException
525     {
526         return this.getProviderByRepository( repository ).export( repository, fileSet, version, outputDirectory );
527     }
528 
529     /**
530      * {@inheritDoc}
531      */
532     public ListScmResult list( ScmRepository repository, ScmFileSet fileSet, boolean recursive, ScmVersion version )
533         throws ScmException
534     {
535         return this.getProviderByRepository( repository ).list( repository, fileSet, recursive, version );
536     }
537 
538     /**
539      * {@inheritDoc}
540      */
541     public MkdirScmResult mkdir( ScmRepository repository, ScmFileSet fileSet, String message, boolean createInLocal )
542         throws ScmException
543     {
544         return this.getProviderByRepository( repository ).mkdir( repository, fileSet, message, createInLocal );
545     }
546 
547     /**
548      * {@inheritDoc}
549      */
550     public RemoveScmResult remove( ScmRepository repository, ScmFileSet fileSet, String message )
551         throws ScmException
552     {
553         return this.getProviderByRepository( repository ).remove( repository, fileSet, message );
554     }
555 
556     /**
557      * {@inheritDoc}
558      */
559     public StatusScmResult status( ScmRepository repository, ScmFileSet fileSet )
560         throws ScmException
561     {
562         return this.getProviderByRepository( repository ).status( repository, fileSet );
563     }
564 
565     /**
566      * {@inheritDoc}
567      */
568     public TagScmResult tag( ScmRepository repository, ScmFileSet fileSet, String tagName )
569         throws ScmException
570     {
571         return this.tag( repository, fileSet, tagName, "" );
572     }
573 
574     /**
575      * {@inheritDoc}
576      */
577     public TagScmResult tag( ScmRepository repository, ScmFileSet fileSet, String tagName, String message )
578         throws ScmException
579     {
580         ScmTagParameters scmTagParameters = new ScmTagParameters( message );
581         return this.getProviderByRepository( repository ).tag( repository, fileSet, tagName, scmTagParameters );
582     }
583 
584     /**
585      * {@inheritDoc}
586      */
587     public UnEditScmResult unedit( ScmRepository repository, ScmFileSet fileSet )
588         throws ScmException
589     {
590         return this.getProviderByRepository( repository ).unedit( repository, fileSet );
591     }
592 
593     /**
594      * {@inheritDoc}
595      */
596     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet )
597         throws ScmException
598     {
599         return this.getProviderByRepository( repository ).update( repository, fileSet );
600     }
601 
602     /**
603      * {@inheritDoc}
604      */
605     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, ScmVersion version )
606         throws ScmException
607     {
608         return this.getProviderByRepository( repository ).update( repository, fileSet, version );
609     }
610 
611     /**
612      * {@inheritDoc}
613      */
614     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, boolean runChangelog )
615         throws ScmException
616     {
617         return this.getProviderByRepository( repository ).update( repository, fileSet, runChangelog );
618     }
619 
620     /**
621      * {@inheritDoc}
622      */
623     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, ScmVersion version,
624                                    boolean runChangelog )
625         throws ScmException
626     {
627         return this.getProviderByRepository( repository ).update( repository, fileSet, version, runChangelog );
628     }
629 
630     /**
631      * {@inheritDoc}
632      */
633     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, String datePattern )
634         throws ScmException
635     {
636         return this.getProviderByRepository( repository ).update( repository, fileSet, (ScmVersion) null, datePattern );
637     }
638 
639     /**
640      * {@inheritDoc}
641      */
642     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, ScmVersion version,
643                                    String datePattern )
644         throws ScmException
645     {
646         return this.getProviderByRepository( repository ).update( repository, fileSet, version, datePattern );
647     }
648 
649     /**
650      * {@inheritDoc}
651      */
652     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, Date lastUpdate )
653         throws ScmException
654     {
655         return this.getProviderByRepository( repository ).update( repository, fileSet, (ScmVersion) null, lastUpdate );
656     }
657 
658     /**
659      * {@inheritDoc}
660      */
661     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, ScmVersion version, Date lastUpdate )
662         throws ScmException
663     {
664         return this.getProviderByRepository( repository ).update( repository, fileSet, version, lastUpdate );
665     }
666 
667     /**
668      * {@inheritDoc}
669      */
670     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, Date lastUpdate, String datePattern )
671         throws ScmException
672     {
673         return this.getProviderByRepository( repository ).update( repository, fileSet, (ScmVersion) null, lastUpdate,
674                                                                   datePattern );
675     }
676 
677     /**
678      * {@inheritDoc}
679      */
680     public UpdateScmResult update( ScmRepository repository, ScmFileSet fileSet, ScmVersion version, Date lastUpdate,
681                                    String datePattern )
682         throws ScmException
683     {
684         return this.getProviderByRepository( repository ).update( repository, fileSet, version, lastUpdate,
685                                                                   datePattern );
686     }
687 
688     /**
689      * {@inheritDoc}
690      */
691     public BlameScmResult blame( ScmRepository repository, ScmFileSet fileSet, String filename )
692         throws ScmException
693     {
694         return this.getProviderByRepository( repository ).blame( repository, fileSet, filename );
695     }
696 
697     public BlameScmResult blame( BlameScmRequest blameScmRequest )
698         throws ScmException
699     {
700         return this.getProviderByRepository( blameScmRequest.getScmRepository() ).blame( blameScmRequest );
701     }
702 }