001 package org.apache.maven.scm.manager;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements. See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership. The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License. You may obtain a copy of the License at
011 *
012 * http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied. See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022 import org.apache.maven.scm.ScmBranch;
023 import org.apache.maven.scm.ScmBranchParameters;
024 import org.apache.maven.scm.ScmException;
025 import org.apache.maven.scm.ScmFileSet;
026 import org.apache.maven.scm.ScmTagParameters;
027 import org.apache.maven.scm.ScmVersion;
028 import org.apache.maven.scm.command.add.AddScmResult;
029 import org.apache.maven.scm.command.blame.BlameScmRequest;
030 import org.apache.maven.scm.command.blame.BlameScmResult;
031 import org.apache.maven.scm.command.branch.BranchScmResult;
032 import org.apache.maven.scm.command.changelog.ChangeLogScmRequest;
033 import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
034 import org.apache.maven.scm.command.checkin.CheckInScmResult;
035 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
036 import org.apache.maven.scm.command.diff.DiffScmResult;
037 import org.apache.maven.scm.command.edit.EditScmResult;
038 import org.apache.maven.scm.command.export.ExportScmResult;
039 import org.apache.maven.scm.command.list.ListScmResult;
040 import org.apache.maven.scm.command.mkdir.MkdirScmResult;
041 import org.apache.maven.scm.command.remove.RemoveScmResult;
042 import org.apache.maven.scm.command.status.StatusScmResult;
043 import org.apache.maven.scm.command.tag.TagScmResult;
044 import org.apache.maven.scm.command.unedit.UnEditScmResult;
045 import org.apache.maven.scm.command.update.UpdateScmResult;
046 import org.apache.maven.scm.log.ScmLogger;
047 import org.apache.maven.scm.provider.ScmProvider;
048 import org.apache.maven.scm.provider.ScmProviderRepository;
049 import org.apache.maven.scm.provider.ScmUrlUtils;
050 import org.apache.maven.scm.repository.ScmRepository;
051 import org.apache.maven.scm.repository.ScmRepositoryException;
052 import org.apache.maven.scm.repository.UnknownRepositoryStructure;
053
054 import java.io.File;
055 import java.util.ArrayList;
056 import java.util.Date;
057 import java.util.HashMap;
058 import java.util.List;
059 import java.util.Map;
060 import java.util.Map.Entry;
061
062 /**
063 * @author <a href="mailto:trygvis@inamo.no">Trygve Laugstøl</a>
064 * @author <a href="mailto:brett@apache.org">Brett Porter</a>
065 * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
066 *
067 */
068 public abstract class AbstractScmManager
069 implements ScmManager
070 {
071 private Map<String, ScmProvider> scmProviders = new HashMap<String, ScmProvider>();
072
073 private ScmLogger logger;
074
075 private Map<String, String> userProviderTypes = new HashMap<String, String>();
076
077 protected void setScmProviders( Map<String, ScmProvider> providers )
078 {
079 this.scmProviders = providers;
080 }
081
082 /**
083 * @deprecated use {@link #setScmProvider(String, ScmProvider)} instead
084 */
085 protected void addScmProvider( String providerType, ScmProvider provider )
086 {
087 setScmProvider( providerType, provider );
088 }
089
090 /**
091 * Set a provider to be used for a type of SCM.
092 * If there was already a designed provider for that type it will be replaced.
093 *
094 * @param providerType the type of SCM, eg. <code>svn</code>, <code>cvs</code>
095 * @param provider the provider that will be used for that SCM type
096 */
097 public void setScmProvider( String providerType, ScmProvider provider )
098 {
099 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 }