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