001package org.apache.maven.wagon.providers.scm; 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 java.io.File; 023import java.io.IOException; 024import java.text.DecimalFormat; 025import java.util.ArrayList; 026import java.util.List; 027import java.util.Random; 028 029import org.apache.maven.scm.CommandParameter; 030import org.apache.maven.scm.CommandParameters; 031import org.apache.maven.scm.ScmBranch; 032import org.apache.maven.scm.ScmException; 033import org.apache.maven.scm.ScmFile; 034import org.apache.maven.scm.ScmFileSet; 035import org.apache.maven.scm.ScmResult; 036import org.apache.maven.scm.ScmRevision; 037import org.apache.maven.scm.ScmTag; 038import org.apache.maven.scm.ScmVersion; 039import org.apache.maven.scm.command.add.AddScmResult; 040import org.apache.maven.scm.command.checkout.CheckOutScmResult; 041import org.apache.maven.scm.command.list.ListScmResult; 042import org.apache.maven.scm.command.update.UpdateScmResult; 043import org.apache.maven.scm.manager.NoSuchScmProviderException; 044import org.apache.maven.scm.manager.ScmManager; 045import org.apache.maven.scm.provider.ScmProvider; 046import org.apache.maven.scm.provider.ScmProviderRepository; 047import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost; 048import org.apache.maven.scm.repository.ScmRepository; 049import org.apache.maven.scm.repository.ScmRepositoryException; 050import org.apache.maven.wagon.AbstractWagon; 051import org.apache.maven.wagon.ConnectionException; 052import org.apache.maven.wagon.ResourceDoesNotExistException; 053import org.apache.maven.wagon.TransferFailedException; 054import org.apache.maven.wagon.authorization.AuthorizationException; 055import org.apache.maven.wagon.events.TransferEvent; 056import org.apache.maven.wagon.resource.Resource; 057import org.codehaus.plexus.util.FileUtils; 058import org.codehaus.plexus.util.StringUtils; 059 060/** 061 * Wagon provider to get and put files from and to SCM systems, using Maven-SCM as underlying transport. 062 * <p/> 063 * TODO it probably creates problems if the same wagon is used in two different SCM protocols, as instance variables can 064 * keep incorrect state. 065 * TODO: For doing releases, we either have to be able to add files with checking out the repository structure which may not be 066 * possible, or the checkout directory needs to be a constant. Doing releases won't scale if you have to checkout the 067 * whole repository structure in order to add 3 files. 068 * 069 * @author <a href="brett@apache.org">Brett Porter</a> 070 * @author <a href="evenisse@apache.org">Emmanuel Venisse</a> 071 * @author <a href="carlos@apache.org">Carlos Sanchez</a> 072 * @author Jason van Zyl 073 * 074 * @plexus.component role="org.apache.maven.wagon.Wagon" role-hint="scm" instantiation-strategy="per-lookup" 075 */ 076public class ScmWagon 077 extends AbstractWagon 078{ 079 /** 080 * @plexus.requirement 081 */ 082 private volatile ScmManager scmManager; 083 084 /** 085 * The SCM version, if any. 086 * 087 * @parameter 088 */ 089 private String scmVersion; 090 091 /** 092 * The SCM version type, if any. Defaults to "branch". 093 * 094 * @parameter 095 */ 096 private String scmVersionType; 097 098 /** 099 * Empty string or subdir ending with slash. 100 */ 101 private String partCOSubdir = ""; 102 103 private boolean haveRecursiveCO; 104 105 private File checkoutDirectory; 106 107 /** 108 * Get the {@link ScmManager} used in this Wagon 109 * 110 * @return the {@link ScmManager} 111 */ 112 public ScmManager getScmManager() 113 { 114 return scmManager; 115 } 116 117 /** 118 * Set the {@link ScmManager} used in this Wagon 119 * 120 * @param scmManager 121 */ 122 public void setScmManager( ScmManager scmManager ) 123 { 124 this.scmManager = scmManager; 125 } 126 127 /** 128 * Get the scmVersion used in this Wagon 129 * 130 * @return the scmVersion 131 */ 132 public String getScmVersion() 133 { 134 return scmVersion; 135 } 136 137 /** 138 * Set the scmVersion 139 * 140 * @param scmVersion the scmVersion to set 141 */ 142 public void setScmVersion( String scmVersion ) 143 { 144 this.scmVersion = scmVersion; 145 } 146 147 /** 148 * Get the scmVersionType used in this Wagon 149 * 150 * @return the scmVersionType 151 */ 152 public String getScmVersionType() 153 { 154 return scmVersionType; 155 } 156 157 /** 158 * Set the scmVersionType 159 * 160 * @param scmVersionType the scmVersionType to set 161 */ 162 public void setScmVersionType( String scmVersionType ) 163 { 164 this.scmVersionType = scmVersionType; 165 } 166 167 /** 168 * Get the directory where Wagon will checkout files from SCM. This directory will be deleted! 169 * 170 * @return directory 171 */ 172 public File getCheckoutDirectory() 173 { 174 return checkoutDirectory; 175 } 176 177 /** 178 * Set the directory where Wagon will checkout files from SCM. This directory will be deleted! 179 * 180 * @param checkoutDirectory 181 */ 182 public void setCheckoutDirectory( File checkoutDirectory ) 183 { 184 this.checkoutDirectory = checkoutDirectory; 185 } 186 187 /** 188 * Convenience method to get the {@link ScmProvider} implementation to handle the provided SCM type 189 * 190 * @param scmType type of SCM, eg. <code>svn</code>, <code>cvs</code> 191 * @return the {@link ScmProvider} that will handle provided SCM type 192 * @throws NoSuchScmProviderException if there is no {@link ScmProvider} able to handle that SCM type 193 */ 194 public ScmProvider getScmProvider( String scmType ) 195 throws NoSuchScmProviderException 196 { 197 return getScmManager().getProviderByType( scmType ); 198 } 199 200 /** 201 * This will cleanup the checkout directory 202 */ 203 public void openConnectionInternal() 204 throws ConnectionException 205 { 206 if ( checkoutDirectory == null ) 207 { 208 checkoutDirectory = createCheckoutDirectory(); 209 } 210 211 if ( checkoutDirectory.exists() ) 212 { 213 removeCheckoutDirectory(); 214 } 215 216 checkoutDirectory.mkdirs(); 217 } 218 219 private File createCheckoutDirectory() 220 { 221 File checkoutDirectory; 222 223 DecimalFormat fmt = new DecimalFormat( "#####" ); 224 225 Random rand = new Random( System.currentTimeMillis() + Runtime.getRuntime().freeMemory() ); 226 227 synchronized ( rand ) 228 { 229 do 230 { 231 checkoutDirectory = new File( System.getProperty( "java.io.tmpdir" ), 232 "wagon-scm" + fmt.format( Math.abs( rand.nextInt() ) ) + ".checkout" ); 233 } 234 while ( checkoutDirectory.exists() ); 235 } 236 237 return checkoutDirectory; 238 } 239 240 241 private void removeCheckoutDirectory() 242 throws ConnectionException 243 { 244 if ( checkoutDirectory == null ) 245 { 246 return; // Silently return. 247 } 248 249 try 250 { 251 deleteCheckoutDirectory(); 252 } 253 catch ( IOException e ) 254 { 255 throw new ConnectionException( "Unable to cleanup checkout directory", e ); 256 } 257 } 258 259 /** 260 * Construct the ScmVersion to use for operations. 261 * <p/> 262 * <p>If scmVersion is supplied, scmVersionType must also be supplied to 263 * take effect.</p> 264 */ 265 private ScmVersion makeScmVersion() 266 { 267 if ( StringUtils.isBlank( scmVersion ) ) 268 { 269 return null; 270 } 271 if ( scmVersion.length() > 0 ) 272 { 273 if ( "revision".equals( scmVersionType ) ) 274 { 275 return new ScmRevision( scmVersion ); 276 } 277 else if ( "tag".equals( scmVersionType ) ) 278 { 279 return new ScmTag( scmVersion ); 280 } 281 else if ( "branch".equals( scmVersionType ) ) 282 { 283 return new ScmBranch( scmVersion ); 284 } 285 } 286 287 return null; 288 } 289 290 private ScmRepository getScmRepository( String url ) 291 throws ScmRepositoryException, NoSuchScmProviderException 292 { 293 String username = null; 294 295 String password = null; 296 297 String privateKey = null; 298 299 String passphrase = null; 300 301 if ( authenticationInfo != null ) 302 { 303 username = authenticationInfo.getUserName(); 304 305 password = authenticationInfo.getPassword(); 306 307 privateKey = authenticationInfo.getPrivateKey(); 308 309 passphrase = authenticationInfo.getPassphrase(); 310 } 311 312 ScmRepository scmRepository = getScmManager().makeScmRepository( url ); 313 314 ScmProviderRepository providerRepository = scmRepository.getProviderRepository(); 315 316 if ( StringUtils.isNotEmpty( username ) ) 317 { 318 providerRepository.setUser( username ); 319 } 320 321 if ( StringUtils.isNotEmpty( password ) ) 322 { 323 providerRepository.setPassword( password ); 324 } 325 326 if ( providerRepository instanceof ScmProviderRepositoryWithHost ) 327 { 328 ScmProviderRepositoryWithHost providerRepo = (ScmProviderRepositoryWithHost) providerRepository; 329 330 if ( StringUtils.isNotEmpty( privateKey ) ) 331 { 332 providerRepo.setPrivateKey( privateKey ); 333 } 334 335 if ( StringUtils.isNotEmpty( passphrase ) ) 336 { 337 providerRepo.setPassphrase( passphrase ); 338 } 339 } 340 341 return scmRepository; 342 } 343 344 public void put( File source, String targetName ) 345 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 346 { 347 if ( source.isDirectory() ) 348 { 349 throw new IllegalArgumentException( "Source is a directory: " + source ); 350 } 351 putInternal( source, targetName ); 352 } 353 354 /** 355 * Puts both files and directories 356 * 357 * @param source 358 * @param targetName 359 * @throws TransferFailedException 360 */ 361 private void putInternal( File source, String targetName ) 362 throws TransferFailedException 363 { 364 Resource target = new Resource( targetName ); 365 366 firePutInitiated( target, source ); 367 368 try 369 { 370 ScmRepository scmRepository = getScmRepository( getRepository().getUrl() ); 371 372 target.setContentLength( source.length() ); 373 target.setLastModified( source.lastModified() ); 374 375 firePutStarted( target, source ); 376 377 String msg = "Wagon: Adding " + source.getName() + " to repository"; 378 379 ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() ); 380 381 boolean isDirectory = source.isDirectory(); 382 String checkoutTargetName = isDirectory ? targetName : getDirname( targetName ); 383 boolean recursive = false; 384 if ( isDirectory ) 385 { 386 for ( File f : source.listFiles() ) 387 { 388 if ( f.isDirectory() ) 389 { 390 recursive = true; 391 break; 392 } 393 } 394 } 395 396 String relPath = ensureDirs( scmProvider, scmRepository, checkoutTargetName, target, recursive ); 397 398 File newCheckoutDirectory = new File( checkoutDirectory, relPath ); 399 400 File scmFile = new File( newCheckoutDirectory, isDirectory ? "" : FileUtils.removePath( targetName, '/' ) ); 401 402 boolean fileAlreadyInScm = scmFile.exists(); 403 404 if ( !scmFile.equals( source ) ) 405 { 406 if ( isDirectory ) 407 { 408 FileUtils.copyDirectoryStructure( source, scmFile ); 409 } 410 else 411 { 412 FileUtils.copyFile( source, scmFile ); 413 } 414 } 415 416 if ( !fileAlreadyInScm || scmFile.isDirectory() ) 417 { 418 int addedFiles = addFiles( scmProvider, scmRepository, newCheckoutDirectory, 419 isDirectory ? "" : scmFile.getName() ); 420 421 if ( !fileAlreadyInScm && addedFiles == 0 ) 422 { 423 throw new ScmException( 424 "Unable to add file to SCM: " + scmFile + "; see error messages above for more information" ); 425 } 426 } 427 428 ScmResult result = 429 scmProvider.checkIn( scmRepository, new ScmFileSet( checkoutDirectory ), makeScmVersion(), msg ); 430 431 checkScmResult( result ); 432 } 433 catch ( ScmException e ) 434 { 435 fireTransferError( target, e, TransferEvent.REQUEST_PUT ); 436 437 throw new TransferFailedException( "Error interacting with SCM: " + e.getMessage(), e ); 438 } 439 catch ( IOException e ) 440 { 441 fireTransferError( target, e, TransferEvent.REQUEST_PUT ); 442 443 throw new TransferFailedException( "Error interacting with SCM: " + e.getMessage(), e ); 444 } 445 446 if ( source.isFile() ) 447 { 448 postProcessListeners( target, source, TransferEvent.REQUEST_PUT ); 449 } 450 451 firePutCompleted( target, source ); 452 } 453 454 /** 455 * Returns the relative path to targetName in the checkout dir. If the targetName already exists in the scm, this 456 * will be the empty string. 457 * 458 * @param scmProvider 459 * @param scmRepository 460 * @param targetName 461 * @return 462 * @throws TransferFailedException 463 * @throws IOException 464 */ 465 private String ensureDirs( ScmProvider scmProvider, ScmRepository scmRepository, String targetName, 466 Resource resource, boolean recursiveArg ) 467 throws TransferFailedException, IOException 468 { 469 if ( checkoutDirectory == null ) 470 { 471 checkoutDirectory = createCheckoutDirectory(); 472 } 473 474 String target = targetName; 475 476 // totally ignore scmRepository parent stuff since that is not supported by all scms. 477 // Instead, assume that that url exists. If not, then that's an error. 478 // Check whether targetName, which is a relative path into the scm, exists. 479 // If it doesn't, check the parent, etc. 480 481 boolean recursive = recursiveArg; 482 483 for ( ;; ) 484 { 485 try 486 { 487 ScmResult res = tryPartialCheckout( target, recursive ); 488 if ( !res.isSuccess() ) 489 { 490 throw new ScmException( "command failed: " + res.getCommandOutput().trim() ); 491 } 492 break; 493 } 494 catch ( ScmException e ) 495 { 496 recursive = false; 497 if ( partCOSubdir.length() == 0 ) 498 { 499 fireTransferError( resource, e, TransferEvent.REQUEST_GET ); 500 501 throw new TransferFailedException( "Error checking out: " + e.getMessage(), e ); 502 } 503 target = getDirname( target ); 504 } 505 } 506 507 // now create the subdirs in target, if it's a parent of targetName 508 509 String res = 510 partCOSubdir.length() >= targetName.length() ? "" : targetName.substring( partCOSubdir.length() ) + '/'; 511 512 ArrayList<File> createdDirs = new ArrayList<File>(); 513 File deepDir = new File( checkoutDirectory, res ); 514 515 boolean added = false; 516 try 517 { 518 mkdirsThrow( deepDir, createdDirs ); 519 if ( createdDirs.size() != 0 ) 520 { 521 File topNewDir = createdDirs.get( 0 ); 522 String relTopNewDir = 523 topNewDir.getPath().substring( checkoutDirectory.getPath().length() + 1 ).replace( '\\', '/' ); 524 525 addFiles( scmProvider, scmRepository, checkoutDirectory, relTopNewDir ); 526 added = true; 527 } 528 } 529 catch ( ScmException e ) 530 { 531 fireTransferError( resource, e, TransferEvent.REQUEST_PUT ); 532 533 throw new TransferFailedException( "Failed to add directory " + createdDirs.get( 0 ) + " to working copy", 534 e ); 535 } 536 finally 537 { 538 if ( !added && createdDirs.size() != 0 ) 539 { 540 FileUtils.deleteDirectory( createdDirs.get( 0 ) ); 541 } 542 } 543 544 return res; 545 } 546 547 private static void mkdirsThrow( File f, List<File> createdDirs ) 548 throws IOException 549 { 550 if ( !f.isDirectory() ) 551 { 552 File parent = f.getParentFile(); 553 mkdirsThrow( parent, createdDirs ); 554 if ( !f.mkdir() ) 555 { 556 throw new IOException( "Failed to create directory " + f.getAbsolutePath() ); 557 } 558 createdDirs.add( f ); 559 } 560 } 561 562 /** 563 * Add a file or directory to a SCM repository. If it's a directory all its contents are added recursively. 564 * <p/> 565 * TODO this is less than optimal, SCM API should provide a way to add a directory recursively 566 * 567 * @param scmProvider SCM provider 568 * @param scmRepository SCM repository 569 * @param basedir local directory corresponding to scmRepository 570 * @param scmFilePath path of the file or directory to add, relative to basedir 571 * @return the number of files added. 572 * @throws ScmException 573 */ 574 private int addFiles( ScmProvider scmProvider, ScmRepository scmRepository, File basedir, String scmFilePath ) 575 throws ScmException 576 { 577 int addedFiles = 0; 578 579 File scmFile = new File( basedir, scmFilePath ); 580 581 if ( scmFilePath.length() != 0 ) 582 { 583 AddScmResult result = 584 scmProvider.add( scmRepository, new ScmFileSet( basedir, new File( scmFilePath ) ), mkBinaryFlag() ); 585 586 /* 587 * TODO dirty fix to work around files with property svn:eol-style=native if a file has that property, first 588 * time file is added it fails, second time it succeeds the solution is check if the scm provider is svn and 589 * unset that property when the SCM API allows it 590 */ 591 if ( !result.isSuccess() ) 592 { 593 result = 594 scmProvider.add( scmRepository, new ScmFileSet( basedir, new File( scmFilePath ) ), 595 mkBinaryFlag() ); 596 } 597 598 addedFiles = result.getAddedFiles().size(); 599 } 600 601 String reservedScmFile = scmProvider.getScmSpecificFilename(); 602 603 if ( scmFile.isDirectory() ) 604 { 605 for ( File file : scmFile.listFiles() ) 606 { 607 if ( reservedScmFile != null && !reservedScmFile.equals( file.getName() ) ) 608 { 609 addedFiles += addFiles( scmProvider, scmRepository, basedir, 610 ( scmFilePath.length() == 0 ? "" : scmFilePath + "/" ) 611 + file.getName() ); 612 } 613 } 614 } 615 616 return addedFiles; 617 } 618 619 private CheckOutScmResult checkOut( ScmProvider scmProvider, ScmRepository scmRepository, ScmFileSet fileSet, 620 boolean recursive ) 621 throws ScmException 622 { 623 ScmVersion ver = makeScmVersion(); 624 CommandParameters parameters = mkBinaryFlag(); 625 // TODO: AbstractScmProvider 6f7dd0c ignores checkOut() parameter "version" 626 parameters.setScmVersion( CommandParameter.SCM_VERSION, ver ); 627 parameters.setString( CommandParameter.RECURSIVE, Boolean.toString( recursive ) ); 628 parameters.setString( CommandParameter.SHALLOW, Boolean.toString( true ) ); 629 630 return scmProvider.checkOut( scmRepository, fileSet, ver, parameters ); 631 } 632 633 private CommandParameters mkBinaryFlag() throws ScmException 634 { 635 CommandParameters parameters = new CommandParameters(); 636 parameters.setString( CommandParameter.BINARY, Boolean.toString( true ) ); 637 return parameters; 638 } 639 640 /** 641 * @return true 642 */ 643 public boolean supportsDirectoryCopy() 644 { 645 return true; 646 } 647 648 private boolean supportsPartialCheckout( ScmProvider scmProvider ) 649 { 650 String scmType = scmProvider.getScmType(); 651 return ( "svn".equals( scmType ) || "cvs".equals( scmType ) ); 652 } 653 654 private boolean isAlwaysRecursive( ScmProvider scmProvider ) 655 { 656 String scmType = scmProvider.getScmType(); 657 return ( "git".equals( scmType ) || "cvs".equals( scmType ) ); 658 } 659 660 public void putDirectory( File sourceDirectory, String destinationDirectory ) 661 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 662 { 663 if ( !sourceDirectory.isDirectory() ) 664 { 665 throw new IllegalArgumentException( "Source is not a directory: " + sourceDirectory ); 666 } 667 668 putInternal( sourceDirectory, destinationDirectory ); 669 } 670 671 /** 672 * Check that the ScmResult was a successful operation 673 * 674 * @param result 675 * @throws TransferFailedException if result was not a successful operation 676 * @throws ScmException 677 */ 678 private void checkScmResult( ScmResult result ) 679 throws ScmException 680 { 681 if ( !result.isSuccess() ) 682 { 683 throw new ScmException( 684 "Unable to commit file. " + result.getProviderMessage() + " " + ( result.getCommandOutput() == null 685 ? "" 686 : result.getCommandOutput() ) ); 687 } 688 } 689 690 public void closeConnection() 691 throws ConnectionException 692 { 693 removeCheckoutDirectory(); 694 } 695 696 /** 697 * Not implemented 698 * 699 * @throws UnsupportedOperationException always 700 */ 701 public boolean getIfNewer( String resourceName, File destination, long timestamp ) 702 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 703 { 704 throw new UnsupportedOperationException( "Not currently supported: getIfNewer" ); 705 } 706 707 public void get( String resourceName, File destination ) 708 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 709 { 710 Resource resource = new Resource( resourceName ); 711 712 fireGetInitiated( resource, destination ); 713 714 fireGetStarted( resource, destination ); 715 716 try 717 { 718 String subdir = getDirname( resourceName ); 719 ScmResult res = tryPartialCheckout( subdir, false ); 720 if ( !res.isSuccess() && ( partCOSubdir.length() == 0 || res instanceof UpdateScmResult ) ) 721 { 722 // inability to checkout SVN or CVS subdir is not fatal. We just assume it doesn't exist 723 // inability to update existing subdir or checkout root is fatal 724 throw new ScmException( "command failed: " + res.getCommandOutput().trim() ); 725 } 726 resourceName = resourceName.substring( partCOSubdir.length() ); 727 728 // TODO: limitations: 729 // - destination filename must match that in the repository - should allow the "-d" CVS equiv to be passed 730 // in 731 // - we don't get granular exceptions from SCM (ie, auth, not found) 732 // - need to make it non-recursive to save time 733 // - exists() check doesn't test if it is in SCM already 734 735 File scmFile = new File( checkoutDirectory, resourceName ); 736 737 if ( !scmFile.exists() ) 738 { 739 throw new ResourceDoesNotExistException( "Unable to find resource " + destination + " after checkout" ); 740 } 741 742 if ( !scmFile.equals( destination ) ) 743 { 744 FileUtils.copyFile( scmFile, destination ); 745 } 746 } 747 catch ( ScmException e ) 748 { 749 fireTransferError( resource, e, TransferEvent.REQUEST_GET ); 750 751 throw new TransferFailedException( "Error getting file from SCM", e ); 752 } 753 catch ( IOException e ) 754 { 755 fireTransferError( resource, e, TransferEvent.REQUEST_GET ); 756 757 throw new TransferFailedException( "Error getting file from SCM", e ); 758 } 759 760 postProcessListeners( resource, destination, TransferEvent.REQUEST_GET ); 761 762 fireGetCompleted( resource, destination ); 763 } 764 765 private ScmResult tryPartialCheckout( String subdir, boolean recursiveArg ) 766 throws ScmException, IOException 767 { 768 String url = getRepository().getUrl(); 769 770 String desiredPartCOSubdir = ""; 771 772 ScmRepository scmRepository = getScmRepository( url ); 773 ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() ); 774 if ( subdir.length() != 0 && supportsPartialCheckout( scmProvider ) ) 775 { 776 url += ( url.endsWith( "/" ) ? "" : "/" ) + subdir; 777 778 desiredPartCOSubdir = subdir + "/"; 779 780 scmRepository = getScmRepository( url ); 781 } 782 783 boolean recursive = recursiveArg | isAlwaysRecursive( scmProvider ); 784 785 if ( !desiredPartCOSubdir.equals( partCOSubdir ) ) 786 { 787 deleteCheckoutDirectory(); 788 partCOSubdir = desiredPartCOSubdir; 789 } 790 791 if ( recursive && !haveRecursiveCO ) 792 { 793 deleteCheckoutDirectory(); 794 } 795 796 ScmResult res; 797 if ( checkoutDirExists( scmProvider ) ) 798 { 799 res = scmProvider.update( scmRepository, new ScmFileSet( checkoutDirectory ), makeScmVersion() ); 800 } 801 else 802 { 803 res = checkOut( scmProvider, scmRepository, new ScmFileSet( checkoutDirectory ), recursive ); 804 haveRecursiveCO = recursive && res.isSuccess(); 805 } 806 return res; 807 } 808 809 private void deleteCheckoutDirectory() 810 throws IOException 811 { 812 haveRecursiveCO = false; 813 FileUtils.deleteDirectory( checkoutDirectory ); 814 } 815 816 private boolean checkoutDirExists( ScmProvider scmProvider ) 817 { 818 String reservedScmFile = scmProvider.getScmSpecificFilename(); 819 File pathToCheck = reservedScmFile == null ? checkoutDirectory : new File( checkoutDirectory, reservedScmFile ); 820 return pathToCheck.exists(); 821 } 822 823 /** 824 * @return a List<String> with filenames/directories at the resourcepath. 825 * @see org.apache.maven.wagon.AbstractWagon#getFileList(java.lang.String) 826 */ 827 public List<String> getFileList( String resourcePath ) 828 throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException 829 { 830 try 831 { 832 ScmRepository repository = getScmRepository( getRepository().getUrl() ); 833 834 ScmProvider provider = getScmProvider( repository.getProvider() ); 835 836 ListScmResult result = 837 provider.list( repository, new ScmFileSet( new File( "." ), new File( resourcePath ) ), false, 838 makeScmVersion() ); 839 840 if ( !result.isSuccess() ) 841 { 842 throw new ResourceDoesNotExistException( result.getProviderMessage() ); 843 } 844 845 List<String> files = new ArrayList<String>(); 846 847 for ( ScmFile f : result.getFiles() ) 848 { 849 files.add( f.getPath() ); 850 } 851 852 return files; 853 } 854 catch ( ScmException e ) 855 { 856 throw new TransferFailedException( "Error getting filelist from SCM", e ); 857 } 858 } 859 860 public boolean resourceExists( String resourceName ) 861 throws TransferFailedException, AuthorizationException 862 { 863 try 864 { 865 getFileList( resourceName ); 866 867 return true; 868 } 869 catch ( ResourceDoesNotExistException e ) 870 { 871 return false; 872 } 873 } 874 875 private String getDirname( String resourceName ) 876 { 877 return FileUtils.getPath( resourceName, '/' ); 878 } 879}