Coverage Report - org.apache.maven.wagon.providers.scm.ScmWagon
 
Classes in this File Line Coverage Branch Coverage Complexity
ScmWagon
75 %
159/212
65 %
62/94
3,893
 
 1  
 package org.apache.maven.wagon.providers.scm;
 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 org.apache.maven.scm.ScmBranch;
 23  
 import org.apache.maven.scm.ScmException;
 24  
 import org.apache.maven.scm.ScmFile;
 25  
 import org.apache.maven.scm.ScmFileSet;
 26  
 import org.apache.maven.scm.ScmResult;
 27  
 import org.apache.maven.scm.ScmRevision;
 28  
 import org.apache.maven.scm.ScmTag;
 29  
 import org.apache.maven.scm.ScmVersion;
 30  
 import org.apache.maven.scm.command.add.AddScmResult;
 31  
 import org.apache.maven.scm.command.checkout.CheckOutScmResult;
 32  
 import org.apache.maven.scm.command.list.ListScmResult;
 33  
 import org.apache.maven.scm.manager.NoSuchScmProviderException;
 34  
 import org.apache.maven.scm.manager.ScmManager;
 35  
 import org.apache.maven.scm.provider.ScmProvider;
 36  
 import org.apache.maven.scm.provider.ScmProviderRepository;
 37  
 import org.apache.maven.scm.provider.ScmProviderRepositoryWithHost;
 38  
 import org.apache.maven.scm.repository.ScmRepository;
 39  
 import org.apache.maven.scm.repository.ScmRepositoryException;
 40  
 import org.apache.maven.wagon.AbstractWagon;
 41  
 import org.apache.maven.wagon.ConnectionException;
 42  
 import org.apache.maven.wagon.ResourceDoesNotExistException;
 43  
 import org.apache.maven.wagon.TransferFailedException;
 44  
 import org.apache.maven.wagon.authorization.AuthorizationException;
 45  
 import org.apache.maven.wagon.events.TransferEvent;
 46  
 import org.apache.maven.wagon.resource.Resource;
 47  
 import org.codehaus.plexus.util.FileUtils;
 48  
 import org.codehaus.plexus.util.StringUtils;
 49  
 
 50  
 import java.io.File;
 51  
 import java.io.IOException;
 52  
 import java.text.DecimalFormat;
 53  
 import java.util.ArrayList;
 54  
 import java.util.Iterator;
 55  
 import java.util.List;
 56  
 import java.util.Random;
 57  
 import java.util.Stack;
 58  
 
 59  
 /**
 60  
  * Wagon provider to get and put files from and to SCM systems, using Maven-SCM as underlying transport.
 61  
  * <p/>
 62  
  * TODO it probably creates problems if the same wagon is used in two different SCM protocols, as instance variables can
 63  
  * keep incorrect state.
 64  
  * TODO: For doing releases we either have to be able to add files with checking out the repository structure which may not be
 65  
  * possible, or the checkout directory needs to be a constant. Doing releases won't scale if you have to checkout the
 66  
  * whole repository structure in order to add 3 files.
 67  
  *
 68  
  * @author <a href="brett@apache.org">Brett Porter</a>
 69  
  * @author <a href="evenisse@apache.org">Emmanuel Venisse</a>
 70  
  * @author <a href="carlos@apache.org">Carlos Sanchez</a>
 71  
  * @author Jason van Zyl
 72  
  * @version $Id: ScmWagon.java 1174113 2011-09-22 13:16:22Z olamy $
 73  
  * @plexus.component role="org.apache.maven.wagon.Wagon" role-hint="scm" instantiation-strategy="per-lookup"
 74  
  */
 75  14
 public class ScmWagon
 76  
     extends AbstractWagon
 77  
 {
 78  
     /**
 79  
      * @plexus.requirement
 80  
      */
 81  
     private ScmManager scmManager;
 82  
 
 83  
     /**
 84  
      * The SCM version, if any.
 85  
      *
 86  
      * @parameter
 87  
      */
 88  
     private String scmVersion;
 89  
 
 90  
     /**
 91  
      * The SCM version type, if any. Defaults to "branch".
 92  
      *
 93  
      * @parameter
 94  
      */
 95  
     private String scmVersionType;
 96  
 
 97  
     private File checkoutDirectory;
 98  
 
 99  
     /**
 100  
      * Get the {@link ScmManager} used in this Wagon
 101  
      *
 102  
      * @return the {@link ScmManager}
 103  
      */
 104  
     public ScmManager getScmManager()
 105  
     {
 106  92
         return scmManager;
 107  
     }
 108  
 
 109  
     /**
 110  
      * Set the {@link ScmManager} used in this Wagon
 111  
      *
 112  
      * @param scmManager
 113  
      */
 114  
     public void setScmManager( ScmManager scmManager )
 115  
     {
 116  14
         this.scmManager = scmManager;
 117  14
     }
 118  
 
 119  
     /**
 120  
      * Get the scmVersion used in this Wagon
 121  
      *
 122  
      * @return the scmVersion
 123  
      */
 124  
     public String getScmVersion()
 125  
     {
 126  0
         return scmVersion;
 127  
     }
 128  
 
 129  
     /**
 130  
      * Set the scmVersion
 131  
      *
 132  
      * @param scmVersion the scmVersion to set
 133  
      */
 134  
     public void setScmVersion( String scmVersion )
 135  
     {
 136  0
         this.scmVersion = scmVersion;
 137  0
     }
 138  
 
 139  
     /**
 140  
      * Get the scmVersionType used in this Wagon
 141  
      *
 142  
      * @return the scmVersionType
 143  
      */
 144  
     public String getScmVersionType()
 145  
     {
 146  0
         return scmVersionType;
 147  
     }
 148  
 
 149  
     /**
 150  
      * Set the scmVersionType
 151  
      *
 152  
      * @param scmVersionType the scmVersionType to set
 153  
      */
 154  
     public void setScmVersionType( String scmVersionType )
 155  
     {
 156  0
         this.scmVersionType = scmVersionType;
 157  0
     }
 158  
 
 159  
     /**
 160  
      * Get the directory where Wagon will checkout files from SCM. This directory will be deleted!
 161  
      *
 162  
      * @return directory
 163  
      */
 164  
     public File getCheckoutDirectory()
 165  
     {
 166  0
         return checkoutDirectory;
 167  
     }
 168  
 
 169  
     /**
 170  
      * Set the directory where Wagon will checkout files from SCM. This directory will be deleted!
 171  
      *
 172  
      * @param checkoutDirectory
 173  
      */
 174  
     public void setCheckoutDirectory( File checkoutDirectory )
 175  
     {
 176  14
         this.checkoutDirectory = checkoutDirectory;
 177  14
     }
 178  
 
 179  
     /**
 180  
      * Convenience method to get the {@link ScmProvider} implementation to handle the provided SCM type
 181  
      *
 182  
      * @param scmType type of SCM, eg. <code>svn</code>, <code>cvs</code>
 183  
      * @return the {@link ScmProvider} that will handle provided SCM type
 184  
      * @throws NoSuchScmProviderException if there is no {@link ScmProvider} able to handle that SCM type
 185  
      */
 186  
     public ScmProvider getScmProvider( String scmType )
 187  
         throws NoSuchScmProviderException
 188  
     {
 189  34
         return getScmManager().getProviderByType( scmType );
 190  
     }
 191  
 
 192  
     /**
 193  
      * This will cleanup the checkout directory
 194  
      */
 195  
     public void openConnectionInternal()
 196  
         throws ConnectionException
 197  
     {
 198  15
         if ( checkoutDirectory == null )
 199  
         {
 200  0
             checkoutDirectory = createCheckoutDirectory();
 201  
         }
 202  
 
 203  15
         if ( checkoutDirectory.exists() )
 204  
         {
 205  3
             removeCheckoutDirectory();
 206  
         }
 207  
 
 208  15
         checkoutDirectory.mkdirs();
 209  15
     }
 210  
 
 211  
     private File createCheckoutDirectory()
 212  
     {
 213  
         File checkoutDirectory;
 214  
 
 215  10
         DecimalFormat fmt = new DecimalFormat( "#####" );
 216  
 
 217  10
         Random rand = new Random( System.currentTimeMillis() + Runtime.getRuntime().freeMemory() );
 218  
 
 219  10
         synchronized ( rand )
 220  
         {
 221  
             do
 222  
             {
 223  10
                 checkoutDirectory = new File( System.getProperty( "java.io.tmpdir" ),
 224  
                                               "wagon-scm" + fmt.format( Math.abs( rand.nextInt() ) ) + ".checkout" );
 225  
             }
 226  10
             while ( checkoutDirectory.exists() );
 227  10
         }
 228  
 
 229  10
         return checkoutDirectory;
 230  
     }
 231  
 
 232  
 
 233  
     private void removeCheckoutDirectory()
 234  
         throws ConnectionException
 235  
     {
 236  18
         if ( checkoutDirectory == null )
 237  
         {
 238  0
             return; // Silently return.
 239  
         }
 240  
 
 241  
         try
 242  
         {
 243  18
             FileUtils.deleteDirectory( checkoutDirectory );
 244  
         }
 245  0
         catch ( IOException e )
 246  
         {
 247  0
             throw new ConnectionException( "Unable to cleanup checkout directory", e );
 248  18
         }
 249  18
     }
 250  
 
 251  
     /**
 252  
      * Construct the ScmVersion to use for operations.
 253  
      * <p/>
 254  
      * <p>If scmVersion is supplied, scmVersionType must also be supplied to
 255  
      * take effect.</p>
 256  
      */
 257  
     private ScmVersion makeScmVersion()
 258  
     {
 259  55
         if ( StringUtils.isBlank( scmVersion ) )
 260  
         {
 261  55
             return null;
 262  
         }
 263  0
         if ( scmVersion.length() > 0 )
 264  
         {
 265  0
             if ( "revision".equals( scmVersionType ) )
 266  
             {
 267  0
                 return new ScmRevision( scmVersion );
 268  
             }
 269  0
             else if ( "tag".equals( scmVersionType ) )
 270  
             {
 271  0
                 return new ScmTag( scmVersion );
 272  
             }
 273  0
             else if ( "branch".equals( scmVersionType ) )
 274  
             {
 275  0
                 return new ScmBranch( scmVersion );
 276  
             }
 277  
         }
 278  
 
 279  0
         return null;
 280  
     }
 281  
 
 282  
     private ScmRepository getScmRepository( String url )
 283  
         throws ScmRepositoryException, NoSuchScmProviderException
 284  
     {
 285  44
         String username = null;
 286  
 
 287  44
         String password = null;
 288  
 
 289  44
         String privateKey = null;
 290  
 
 291  44
         String passphrase = null;
 292  
 
 293  44
         if ( authenticationInfo != null )
 294  
         {
 295  44
             username = authenticationInfo.getUserName();
 296  
 
 297  44
             password = authenticationInfo.getPassword();
 298  
 
 299  44
             privateKey = authenticationInfo.getPrivateKey();
 300  
 
 301  44
             passphrase = authenticationInfo.getPassphrase();
 302  
         }
 303  
 
 304  44
         ScmRepository scmRepository = getScmManager().makeScmRepository( url );
 305  
 
 306  44
         ScmProviderRepository providerRepository = scmRepository.getProviderRepository();
 307  
 
 308  44
         if ( StringUtils.isNotEmpty( username ) )
 309  
         {
 310  0
             providerRepository.setUser( username );
 311  
         }
 312  
 
 313  44
         if ( StringUtils.isNotEmpty( password ) )
 314  
         {
 315  0
             providerRepository.setPassword( password );
 316  
         }
 317  
 
 318  44
         if ( providerRepository instanceof ScmProviderRepositoryWithHost )
 319  
         {
 320  44
             ScmProviderRepositoryWithHost providerRepo = (ScmProviderRepositoryWithHost) providerRepository;
 321  
 
 322  44
             if ( StringUtils.isNotEmpty( privateKey ) )
 323  
             {
 324  0
                 providerRepo.setPrivateKey( privateKey );
 325  
             }
 326  
 
 327  44
             if ( StringUtils.isNotEmpty( passphrase ) )
 328  
             {
 329  0
                 providerRepo.setPassphrase( passphrase );
 330  
             }
 331  
         }
 332  
 
 333  44
         return scmRepository;
 334  
     }
 335  
 
 336  
     public void put( File source, String targetName )
 337  
         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
 338  
     {
 339  6
         if ( source.isDirectory() )
 340  
         {
 341  0
             throw new IllegalArgumentException( "Source is a directory: " + source );
 342  
         }
 343  6
         putInternal( source, targetName );
 344  6
     }
 345  
 
 346  
     /**
 347  
      * Puts both files and directories
 348  
      *
 349  
      * @param source
 350  
      * @param targetName
 351  
      * @throws TransferFailedException
 352  
      */
 353  
     private void putInternal( File source, String targetName )
 354  
         throws TransferFailedException
 355  
     {
 356  10
         Resource target = new Resource( targetName );
 357  
 
 358  10
         firePutInitiated( target, source );
 359  
 
 360  
         try
 361  
         {
 362  10
             ScmRepository scmRepository = getScmRepository( getRepository().getUrl() );
 363  
 
 364  10
             target.setContentLength( source.length() );
 365  10
             target.setLastModified( source.lastModified() );
 366  
 
 367  10
             firePutStarted( target, source );
 368  
 
 369  10
             String msg = "Wagon: Adding " + source.getName() + " to repository";
 370  
 
 371  10
             ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() );
 372  
 
 373  10
             String checkoutTargetName = source.isDirectory() ? targetName : getDirname( targetName );
 374  10
             String relPath = checkOut( scmProvider, scmRepository, checkoutTargetName, target );
 375  
 
 376  10
             File newCheckoutDirectory = new File( checkoutDirectory, relPath );
 377  
 
 378  10
             File scmFile = new File( newCheckoutDirectory, source.isDirectory() ? "" : getFilename( targetName ) );
 379  
 
 380  10
             boolean fileAlreadyInScm = scmFile.exists();
 381  
 
 382  10
             if ( !scmFile.equals( source ) )
 383  
             {
 384  10
                 if ( source.isDirectory() )
 385  
                 {
 386  4
                     FileUtils.copyDirectoryStructure( source, scmFile );
 387  
                 }
 388  
                 else
 389  
                 {
 390  6
                     FileUtils.copyFile( source, scmFile );
 391  
                 }
 392  
             }
 393  
 
 394  10
             if ( !fileAlreadyInScm || scmFile.isDirectory() )
 395  
             {
 396  10
                 int addedFiles = addFiles( scmProvider, scmRepository, newCheckoutDirectory,
 397  
                                            source.isDirectory() ? "" : scmFile.getName() );
 398  
 
 399  10
                 if ( !fileAlreadyInScm && addedFiles == 0 )
 400  
                 {
 401  0
                     throw new ScmException(
 402  
                         "Unable to add file to SCM: " + scmFile + "; see error messages above for more information" );
 403  
                 }
 404  
             }
 405  
 
 406  10
             ScmResult result =
 407  
                 scmProvider.checkIn( scmRepository, new ScmFileSet( checkoutDirectory ), makeScmVersion(), msg );
 408  
 
 409  10
             checkScmResult( result );
 410  
         }
 411  0
         catch ( ScmException e )
 412  
         {
 413  0
             fireTransferError( target, e, TransferEvent.REQUEST_GET );
 414  
 
 415  0
             throw new TransferFailedException( "Error interacting with SCM: " + e.getMessage(), e );
 416  
         }
 417  0
         catch ( IOException e )
 418  
         {
 419  0
             fireTransferError( target, e, TransferEvent.REQUEST_GET );
 420  
 
 421  0
             throw new TransferFailedException( "Error interacting with SCM: " + e.getMessage(), e );
 422  10
         }
 423  
 
 424  10
         if ( source.isFile() )
 425  
         {
 426  6
             postProcessListeners( target, source, TransferEvent.REQUEST_PUT );
 427  
         }
 428  
 
 429  10
         firePutCompleted( target, source );
 430  10
     }
 431  
 
 432  
     /**
 433  
      * Returns the relative path to targetName in the checkout dir. If the targetName already exists in the scm, this
 434  
      * will be the empty string.
 435  
      *
 436  
      * @param scmProvider
 437  
      * @param scmRepository
 438  
      * @param targetName
 439  
      * @return
 440  
      * @throws TransferFailedException
 441  
      */
 442  
     private String checkOut( ScmProvider scmProvider, ScmRepository scmRepository, String targetName,
 443  
                              Resource resource )
 444  
         throws TransferFailedException
 445  
     {
 446  10
         checkoutDirectory = createCheckoutDirectory();
 447  
 
 448  10
         Stack stack = new Stack();
 449  
 
 450  10
         String target = targetName;
 451  
 
 452  
         // totally ignore scmRepository parent stuff since that is not supported by all scms.
 453  
         // Instead, assume that that url exists. If not, then that's an error.
 454  
         // Check whether targetName, which is a relative path into the scm, exists.
 455  
         // If it doesn't, check the parent, etc.
 456  
 
 457  
         try
 458  
         {
 459  16
             while ( target.length() > 0 && !scmProvider.list( scmRepository,
 460  
                                                               new ScmFileSet( new File( "." ), new File( target ) ),
 461  
                                                               false, makeScmVersion() ).isSuccess() )
 462  
             {
 463  6
                 stack.push( getFilename( target ) );
 464  6
                 target = getDirname( target );
 465  
             }
 466  
         }
 467  0
         catch ( ScmException e )
 468  
         {
 469  0
             fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
 470  
 
 471  0
             throw new TransferFailedException( "Error listing repository: " + e.getMessage(), e );
 472  10
         }
 473  
 
 474  
         // ok, we've established that target exists, or is empty.
 475  
         // Check the resource out; if it doesn't exist, that means we're in the svn repo url root,
 476  
         // and the configuration is incorrect. We will not try repo.getParent since most scm's don't
 477  
         // implement that.
 478  
 
 479  
         try
 480  
         {
 481  10
             String repoUrl = getRepository().getUrl();
 482  10
             if ( "svn".equals( scmProvider.getScmType() ) )
 483  
             {
 484  
                 // Subversion is the only SCM that adds path structure to represent tags and branches.
 485  
                 // The rest use scmVersion and scmVersionType.
 486  10
                 repoUrl += "/" + target.replace( '\\', '/' );
 487  
             }
 488  10
             scmRepository = getScmRepository( repoUrl );
 489  10
             CheckOutScmResult ret =
 490  
                 scmProvider.checkOut( scmRepository, new ScmFileSet( new File( checkoutDirectory, "" ) ),
 491  
                                       makeScmVersion(), false );
 492  
 
 493  10
             checkScmResult( ret );
 494  
         }
 495  0
         catch ( ScmException e )
 496  
         {
 497  0
             fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
 498  
 
 499  0
             throw new TransferFailedException( "Error checking out: " + e.getMessage(), e );
 500  10
         }
 501  
 
 502  
         // now create the subdirs in target, if it's a parent of targetName
 503  
 
 504  10
         String relPath = "";
 505  
 
 506  16
         while ( !stack.isEmpty() )
 507  
         {
 508  6
             String p = (String) stack.pop();
 509  6
             relPath += p + "/";
 510  
 
 511  6
             File newDir = new File( checkoutDirectory, relPath );
 512  6
             if ( !newDir.mkdirs() )
 513  
             {
 514  0
                 throw new TransferFailedException(
 515  
                     "Failed to create directory " + newDir.getAbsolutePath() + "; parent should exist: "
 516  
                         + checkoutDirectory );
 517  
             }
 518  
 
 519  
             try
 520  
             {
 521  6
                 addFiles( scmProvider, scmRepository, checkoutDirectory, relPath );
 522  
             }
 523  0
             catch ( ScmException e )
 524  
             {
 525  0
                 fireTransferError( resource, e, TransferEvent.REQUEST_PUT );
 526  
 
 527  0
                 throw new TransferFailedException( "Failed to add directory " + newDir + " to working copy", e );
 528  6
             }
 529  6
         }
 530  
 
 531  10
         return relPath;
 532  
     }
 533  
 
 534  
     /**
 535  
      * Add a file or directory to a SCM repository. If it's a directory all its contents are added recursively.
 536  
      * <p/>
 537  
      * TODO this is less than optimal, SCM API should provide a way to add a directory recursively
 538  
      *
 539  
      * @param scmProvider   SCM provider
 540  
      * @param scmRepository SCM repository
 541  
      * @param basedir       local directory corresponding to scmRepository
 542  
      * @param scmFilePath   path of the file or directory to add, relative to basedir
 543  
      * @return the number of files added.
 544  
      * @throws ScmException
 545  
      */
 546  
     private int addFiles( ScmProvider scmProvider, ScmRepository scmRepository, File basedir, String scmFilePath )
 547  
         throws ScmException
 548  
     {
 549  53
         int addedFiles = 0;
 550  
 
 551  53
         File scmFile = new File( basedir, scmFilePath );
 552  
 
 553  53
         if ( scmFilePath.length() != 0 )
 554  
         {
 555  49
             AddScmResult result = scmProvider.add( scmRepository, new ScmFileSet( basedir, new File( scmFilePath ) ) );
 556  
 
 557  
             /*
 558  
              * TODO dirty fix to work around files with property svn:eol-style=native if a file has that property, first
 559  
              * time file is added it fails, second time it succeeds the solution is check if the scm provider is svn and
 560  
              * unset that property when the SCM API allows it
 561  
              */
 562  49
             if ( !result.isSuccess() )
 563  
             {
 564  0
                 result = scmProvider.add( scmRepository, new ScmFileSet( basedir, new File( scmFilePath ) ) );
 565  
             }
 566  
 
 567  49
             addedFiles = result.getAddedFiles().size();
 568  
         }
 569  
 
 570  53
         String reservedScmFile = scmProvider.getScmSpecificFilename();
 571  
 
 572  53
         if ( scmFile.isDirectory() )
 573  
         {
 574  28
             File[] files = scmFile.listFiles();
 575  
 
 576  93
             for ( int i = 0; i < files.length; i++ )
 577  
             {
 578  65
                 if ( reservedScmFile != null && !reservedScmFile.equals( files[i].getName() ) )
 579  
                 {
 580  37
                     addedFiles += addFiles( scmProvider, scmRepository, basedir,
 581  
                                             ( scmFilePath.length() == 0 ? "" : scmFilePath + "/" )
 582  
                                                 + files[i].getName() );
 583  
                 }
 584  
             }
 585  
         }
 586  
 
 587  53
         return addedFiles;
 588  
     }
 589  
 
 590  
     /**
 591  
      * @return true
 592  
      */
 593  
     public boolean supportsDirectoryCopy()
 594  
     {
 595  4
         return true;
 596  
     }
 597  
 
 598  
     public void putDirectory( File sourceDirectory, String destinationDirectory )
 599  
         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
 600  
     {
 601  4
         if ( !sourceDirectory.isDirectory() )
 602  
         {
 603  0
             throw new IllegalArgumentException( "Source is not a directory: " + sourceDirectory );
 604  
         }
 605  
 
 606  4
         putInternal( sourceDirectory, destinationDirectory );
 607  4
     }
 608  
 
 609  
     /**
 610  
      * Check that the ScmResult was a successful operation
 611  
      *
 612  
      * @param result
 613  
      * @throws TransferFailedException if result was not a successful operation
 614  
      * @throws ScmException
 615  
      */
 616  
     private void checkScmResult( ScmResult result )
 617  
         throws ScmException
 618  
     {
 619  20
         if ( !result.isSuccess() )
 620  
         {
 621  0
             throw new ScmException(
 622  
                 "Unable to commit file. " + result.getProviderMessage() + " " + ( result.getCommandOutput() == null
 623  
                     ? ""
 624  
                     : result.getCommandOutput() ) );
 625  
         }
 626  20
     }
 627  
 
 628  
     public void closeConnection()
 629  
         throws ConnectionException
 630  
     {
 631  15
         removeCheckoutDirectory();
 632  15
     }
 633  
 
 634  
     /**
 635  
      * Not implemented
 636  
      *
 637  
      * @throws UnsupportedOperationException always
 638  
      */
 639  
     public boolean getIfNewer( String resourceName, File destination, long timestamp )
 640  
         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
 641  
     {
 642  0
         throw new UnsupportedOperationException( "Not currently supported: getIfNewer" );
 643  
     }
 644  
 
 645  
     public void get( String resourceName, File destination )
 646  
         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
 647  
     {
 648  19
         Resource resource = new Resource( resourceName );
 649  
 
 650  19
         fireGetInitiated( resource, destination );
 651  
 
 652  19
         String url = getRepository().getUrl() + "/" + resourceName;
 653  
 
 654  
         // remove the file
 655  19
         url = url.substring( 0, url.lastIndexOf( '/' ) );
 656  
 
 657  
         try
 658  
         {
 659  19
             ScmRepository scmRepository = getScmRepository( url );
 660  
 
 661  19
             fireGetStarted( resource, destination );
 662  
 
 663  
             // TODO: limitations:
 664  
             // - destination filename must match that in the repository - should allow the "-d" CVS equiv to be passed
 665  
             //   in
 666  
             // - we don't get granular exceptions from SCM (ie, auth, not found)
 667  
             // - need to make it non-recursive to save time
 668  
             // - exists() check doesn't test if it is in SCM already
 669  
 
 670  19
             File scmFile = new File( checkoutDirectory, resourceName );
 671  
 
 672  19
             File basedir = scmFile.getParentFile();
 673  
 
 674  19
             ScmProvider scmProvider = getScmProvider( scmRepository.getProvider() );
 675  
 
 676  19
             String reservedScmFile = scmProvider.getScmSpecificFilename();
 677  
 
 678  19
             if ( reservedScmFile != null && new File( basedir, reservedScmFile ).exists() )
 679  
             {
 680  18
                 scmProvider.update( scmRepository, new ScmFileSet( basedir ), makeScmVersion() );
 681  
             }
 682  
             else
 683  
             {
 684  
                 // TODO: this should be checking out a full hierarchy (requires the -d equiv)
 685  1
                 basedir.mkdirs();
 686  
 
 687  1
                 scmProvider.checkOut( scmRepository, new ScmFileSet( basedir ), makeScmVersion() );
 688  
             }
 689  
 
 690  19
             if ( !scmFile.exists() )
 691  
             {
 692  1
                 throw new ResourceDoesNotExistException( "Unable to find resource " + destination + " after checkout" );
 693  
             }
 694  
 
 695  18
             if ( !scmFile.equals( destination ) )
 696  
             {
 697  18
                 FileUtils.copyFile( scmFile, destination );
 698  
             }
 699  
         }
 700  0
         catch ( ScmException e )
 701  
         {
 702  0
             fireTransferError( resource, e, TransferEvent.REQUEST_GET );
 703  
 
 704  0
             throw new TransferFailedException( "Error getting file from SCM", e );
 705  
         }
 706  0
         catch ( IOException e )
 707  
         {
 708  0
             fireTransferError( resource, e, TransferEvent.REQUEST_GET );
 709  
 
 710  0
             throw new TransferFailedException( "Error getting file from SCM", e );
 711  18
         }
 712  
 
 713  18
         postProcessListeners( resource, destination, TransferEvent.REQUEST_GET );
 714  
 
 715  18
         fireGetCompleted( resource, destination );
 716  18
     }
 717  
 
 718  
     /**
 719  
      * @return a List&lt;String&gt; with filenames/directories at the resourcepath.
 720  
      * @see org.apache.maven.wagon.AbstractWagon#getFileList(java.lang.String)
 721  
      */
 722  
     public List<String> getFileList( String resourcePath )
 723  
         throws TransferFailedException, ResourceDoesNotExistException, AuthorizationException
 724  
     {
 725  
         try
 726  
         {
 727  5
             ScmRepository repository = getScmRepository( getRepository().getUrl() );
 728  
 
 729  5
             ScmProvider provider = getScmProvider( repository.getProvider() );
 730  
 
 731  5
             ListScmResult result =
 732  
                 provider.list( repository, new ScmFileSet( new File( "." ), new File( resourcePath ) ), false,
 733  
                                makeScmVersion() );
 734  
 
 735  5
             if ( !result.isSuccess() )
 736  
             {
 737  2
                 throw new ResourceDoesNotExistException( result.getProviderMessage() );
 738  
             }
 739  
 
 740  3
             List<String> files = new ArrayList<String>();
 741  
 
 742  3
             for ( Iterator<ScmFile> it = result.getFiles().iterator(); it.hasNext(); )
 743  
             {
 744  8
                 ScmFile f = it.next();
 745  8
                 files.add( f.getPath() );
 746  8
             }
 747  
 
 748  3
             return files;
 749  
         }
 750  0
         catch ( ScmException e )
 751  
         {
 752  0
             throw new TransferFailedException( "Error getting filelist from SCM", e );
 753  
         }
 754  
     }
 755  
 
 756  
     public boolean resourceExists( String resourceName )
 757  
         throws TransferFailedException, AuthorizationException
 758  
     {
 759  
         try
 760  
         {
 761  2
             getFileList( resourceName );
 762  
 
 763  1
             return true;
 764  
         }
 765  1
         catch ( ResourceDoesNotExistException e )
 766  
         {
 767  1
             return false;
 768  
         }
 769  
     }
 770  
 
 771  
     private String getFilename( String filename )
 772  
     {
 773  12
         String fname = StringUtils.replace( filename, "/", File.separator );
 774  12
         return FileUtils.filename( fname );
 775  
     }
 776  
 
 777  
     private String getDirname( String filename )
 778  
     {
 779  12
         String fname = StringUtils.replace( filename, "/", File.separator );
 780  12
         return FileUtils.dirname( fname );
 781  
     }
 782  
 }