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 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}