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