001package 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 022import org.apache.maven.scm.ScmBranch; 023import org.apache.maven.scm.ScmBranchParameters; 024import org.apache.maven.scm.ScmException; 025import org.apache.maven.scm.ScmFileSet; 026import org.apache.maven.scm.ScmTagParameters; 027import org.apache.maven.scm.ScmVersion; 028import org.apache.maven.scm.command.add.AddScmResult; 029import org.apache.maven.scm.command.blame.BlameScmRequest; 030import org.apache.maven.scm.command.blame.BlameScmResult; 031import org.apache.maven.scm.command.branch.BranchScmResult; 032import org.apache.maven.scm.command.changelog.ChangeLogScmRequest; 033import org.apache.maven.scm.command.changelog.ChangeLogScmResult; 034import org.apache.maven.scm.command.checkin.CheckInScmResult; 035import org.apache.maven.scm.command.checkout.CheckOutScmResult; 036import org.apache.maven.scm.command.diff.DiffScmResult; 037import org.apache.maven.scm.command.edit.EditScmResult; 038import org.apache.maven.scm.command.export.ExportScmResult; 039import org.apache.maven.scm.command.list.ListScmResult; 040import org.apache.maven.scm.command.mkdir.MkdirScmResult; 041import org.apache.maven.scm.command.remove.RemoveScmResult; 042import org.apache.maven.scm.command.status.StatusScmResult; 043import org.apache.maven.scm.command.tag.TagScmResult; 044import org.apache.maven.scm.command.unedit.UnEditScmResult; 045import org.apache.maven.scm.command.update.UpdateScmResult; 046import org.apache.maven.scm.log.ScmLogger; 047import org.apache.maven.scm.provider.ScmProvider; 048import org.apache.maven.scm.provider.ScmProviderRepository; 049import org.apache.maven.scm.provider.ScmUrlUtils; 050import org.apache.maven.scm.repository.ScmRepository; 051import org.apache.maven.scm.repository.ScmRepositoryException; 052import org.apache.maven.scm.repository.UnknownRepositoryStructure; 053 054import java.io.File; 055import java.util.ArrayList; 056import java.util.Date; 057import java.util.HashMap; 058import java.util.List; 059import java.util.Map; 060import 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 */ 068public 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 * @param providerType the type of SCM, eg. <code>svn</code>, <code>git</code> 086 * @param provider the provider that will be used for that SCM type 087 */ 088 protected void addScmProvider( String providerType, ScmProvider provider ) 089 { 090 setScmProvider( providerType, provider ); 091 } 092 093 /** 094 * Set a provider to be used for a type of SCM. 095 * If there was already a designed provider for that type it will be replaced. 096 * 097 * @param providerType the type of SCM, eg. <code>svn</code>, <code>git</code> 098 * @param provider the provider that will be used for that SCM type 099 */ 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}