Coverage Report - org.apache.maven.shared.model.fileset.util.FileSetManager
 
Classes in this File Line Coverage Branch Coverage Complexity
FileSetManager
52%
109/211
32%
53/168
4.5
 
 1  
 package org.apache.maven.shared.model.fileset.util;
 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.plugin.logging.Log;
 23  
 import org.apache.maven.shared.io.logging.DefaultMessageHolder;
 24  
 import org.apache.maven.shared.io.logging.MessageHolder;
 25  
 import org.apache.maven.shared.io.logging.MessageLevels;
 26  
 import org.apache.maven.shared.io.logging.MojoLogSink;
 27  
 import org.apache.maven.shared.io.logging.PlexusLoggerSink;
 28  
 import org.apache.maven.shared.model.fileset.FileSet;
 29  
 import org.apache.maven.shared.model.fileset.mappers.FileNameMapper;
 30  
 import org.apache.maven.shared.model.fileset.mappers.MapperException;
 31  
 import org.apache.maven.shared.model.fileset.mappers.MapperUtil;
 32  
 import org.codehaus.plexus.logging.Logger;
 33  
 import org.codehaus.plexus.util.DirectoryScanner;
 34  
 import org.codehaus.plexus.util.FileUtils;
 35  
 
 36  
 import java.io.File;
 37  
 import java.io.IOException;
 38  
 import java.util.ArrayList;
 39  
 import java.util.Arrays;
 40  
 import java.util.Collection;
 41  
 import java.util.Collections;
 42  
 import java.util.HashSet;
 43  
 import java.util.Iterator;
 44  
 import java.util.LinkedHashMap;
 45  
 import java.util.LinkedList;
 46  
 import java.util.List;
 47  
 import java.util.Map;
 48  
 import java.util.Set;
 49  
 
 50  
 /**
 51  
  * Provides operations for use with FileSet instances, such as retrieving the included/excluded files, deleting all
 52  
  * matching entries, etc.
 53  
  *
 54  
  * @author jdcasey
 55  
  * @version $Id: org.apache.maven.shared.model.fileset.util.FileSetManager.html 886882 2013-11-16 21:55:43Z hboutemy $
 56  
  */
 57  
 public class FileSetManager
 58  
 {
 59  1
     private static final String[] EMPTY_STRING_ARRAY = new String[0];
 60  
 
 61  
     private final boolean verbose;
 62  
 
 63  
     private MessageHolder messages;
 64  
 
 65  
     // ----------------------------------------------------------------------
 66  
     // Constructors
 67  
     // ----------------------------------------------------------------------
 68  
 
 69  
     /**
 70  
      * Create a new manager instance with the supplied log instance and flag for whether to output verbose messages.
 71  
      *
 72  
      * @param log The mojo log instance
 73  
      * @param verbose Whether to output verbose messages
 74  
      */
 75  
     public FileSetManager( Log log, boolean verbose )
 76  0
     {
 77  0
         if ( verbose )
 78  
         {
 79  0
             this.messages = new DefaultMessageHolder( MessageLevels.LEVEL_DEBUG, MessageLevels.LEVEL_INFO,
 80  
                                                       new MojoLogSink( log ) );
 81  
         }
 82  
         else
 83  
         {
 84  0
             this.messages = new DefaultMessageHolder( MessageLevels.LEVEL_INFO, MessageLevels.LEVEL_INFO,
 85  
                                                       new MojoLogSink( log ) );
 86  
         }
 87  
 
 88  0
         this.verbose = verbose;
 89  0
     }
 90  
 
 91  
     /**
 92  
      * Create a new manager instance with the supplied log instance. Verbose flag is set to false.
 93  
      *
 94  
      * @param log The mojo log instance
 95  
      */
 96  
     public FileSetManager( Log log )
 97  0
     {
 98  0
         this.messages = new DefaultMessageHolder( MessageLevels.LEVEL_INFO, MessageLevels.LEVEL_INFO,
 99  
                                                   new MojoLogSink( log ) );
 100  0
         this.verbose = false;
 101  0
     }
 102  
 
 103  
     /**
 104  
      * Create a new manager instance with the supplied log instance and flag for whether to output verbose messages.
 105  
      *
 106  
      * @param log The mojo log instance
 107  
      * @param verbose Whether to output verbose messages
 108  
      */
 109  
     public FileSetManager( Logger log, boolean verbose )
 110  0
     {
 111  0
         if ( verbose )
 112  
         {
 113  0
             this.messages = new DefaultMessageHolder( MessageLevels.LEVEL_DEBUG, MessageLevels.LEVEL_INFO,
 114  
                                                       new PlexusLoggerSink( log ) );
 115  
         }
 116  
         else
 117  
         {
 118  0
             this.messages = new DefaultMessageHolder( MessageLevels.LEVEL_INFO, MessageLevels.LEVEL_INFO,
 119  
                                                       new PlexusLoggerSink( log ) );
 120  
         }
 121  
 
 122  0
         this.verbose = verbose;
 123  0
     }
 124  
 
 125  
     /**
 126  
      * Create a new manager instance with the supplied log instance. Verbose flag is set to false.
 127  
      *
 128  
      * @param log The mojo log instance
 129  
      */
 130  
     public FileSetManager( Logger log )
 131  0
     {
 132  0
         this.messages = new DefaultMessageHolder( MessageLevels.LEVEL_INFO, MessageLevels.LEVEL_INFO,
 133  
                                                   new PlexusLoggerSink( log ) );
 134  0
         this.verbose = false;
 135  0
     }
 136  
 
 137  
     /**
 138  
      * Create a new manager instance with an empty messages. Verbose flag is set to false.
 139  
      */
 140  
     public FileSetManager()
 141  10
     {
 142  10
         this.verbose = false;
 143  10
     }
 144  
 
 145  
     // ----------------------------------------------------------------------
 146  
     // Public methods
 147  
     // ----------------------------------------------------------------------
 148  
 
 149  
     /**
 150  
      *
 151  
      * @param fileSet
 152  
      * @return the included files as map
 153  
      * @throws MapperException if any
 154  
      * @see #getIncludedFiles(FileSet)
 155  
      */
 156  
     public Map mapIncludedFiles( FileSet fileSet )
 157  
         throws MapperException
 158  
     {
 159  0
         String[] sourcePaths = getIncludedFiles( fileSet );
 160  0
         Map mappedPaths = new LinkedHashMap();
 161  
 
 162  0
         FileNameMapper fileMapper = MapperUtil.getFileNameMapper( fileSet.getMapper() );
 163  
 
 164  0
         for ( int i = 0; i < sourcePaths.length; i++ )
 165  
         {
 166  0
             String sourcePath = sourcePaths[i];
 167  
 
 168  
             String destPath;
 169  0
             if ( fileMapper != null )
 170  
             {
 171  0
                 destPath = fileMapper.mapFileName( sourcePath );
 172  
             }
 173  
             else
 174  
             {
 175  0
                 destPath = sourcePath;
 176  
             }
 177  
 
 178  0
             mappedPaths.put( sourcePath, destPath );
 179  
         }
 180  
 
 181  0
         return mappedPaths;
 182  
     }
 183  
 
 184  
     /**
 185  
      * Get all the filenames which have been included by the rules in this fileset.
 186  
      *
 187  
      * @param fileSet
 188  
      *            The fileset defining rules for inclusion/exclusion, and base directory.
 189  
      * @return the array of matching filenames, relative to the basedir of the file-set.
 190  
      */
 191  
     public String[] getIncludedFiles( FileSet fileSet )
 192  
     {
 193  2
         DirectoryScanner scanner = scan( fileSet );
 194  
 
 195  2
         if ( scanner != null )
 196  
         {
 197  2
             return scanner.getIncludedFiles();
 198  
         }
 199  
 
 200  0
         return EMPTY_STRING_ARRAY;
 201  
     }
 202  
 
 203  
     /**
 204  
      * Get all the directory names which have been included by the rules in this fileset.
 205  
      *
 206  
      * @param fileSet
 207  
      *            The fileset defining rules for inclusion/exclusion, and base directory.
 208  
      * @return the array of matching dirnames, relative to the basedir of the file-set.
 209  
      */
 210  
     public String[] getIncludedDirectories( FileSet fileSet )
 211  
     {
 212  0
         DirectoryScanner scanner = scan( fileSet );
 213  
 
 214  0
         if ( scanner != null )
 215  
         {
 216  0
             return scanner.getIncludedDirectories();
 217  
         }
 218  
 
 219  0
         return EMPTY_STRING_ARRAY;
 220  
     }
 221  
 
 222  
     /**
 223  
      * Get all the filenames which have been excluded by the rules in this fileset.
 224  
      *
 225  
      * @param fileSet
 226  
      *            The fileset defining rules for inclusion/exclusion, and base directory.
 227  
      * @return the array of non-matching filenames, relative to the basedir of the file-set.
 228  
      */
 229  
     public String[] getExcludedFiles( FileSet fileSet )
 230  
     {
 231  0
         DirectoryScanner scanner = scan( fileSet );
 232  
 
 233  0
         if ( scanner != null )
 234  
         {
 235  0
             return scanner.getExcludedFiles();
 236  
         }
 237  
 
 238  0
         return EMPTY_STRING_ARRAY;
 239  
     }
 240  
 
 241  
     /**
 242  
      * Get all the directory names which have been excluded by the rules in this fileset.
 243  
      *
 244  
      * @param fileSet
 245  
      *            The fileset defining rules for inclusion/exclusion, and base directory.
 246  
      * @return the array of non-matching dirnames, relative to the basedir of the file-set.
 247  
      */
 248  
     public String[] getExcludedDirectories( FileSet fileSet )
 249  
     {
 250  0
         DirectoryScanner scanner = scan( fileSet );
 251  
 
 252  0
         if ( scanner != null )
 253  
         {
 254  0
             return scanner.getExcludedDirectories();
 255  
         }
 256  
 
 257  0
         return EMPTY_STRING_ARRAY;
 258  
     }
 259  
 
 260  
     /**
 261  
      * Delete the matching files and directories for the given file-set definition.
 262  
      *
 263  
      * @param fileSet The file-set matching rules, along with search base directory
 264  
      * @throws IOException If a matching file cannot be deleted
 265  
      */
 266  
     public void delete( FileSet fileSet )
 267  
         throws IOException
 268  
     {
 269  8
         delete( fileSet, true );
 270  8
     }
 271  
 
 272  
     /**
 273  
      * Delete the matching files and directories for the given file-set definition.
 274  
      *
 275  
      * @param fileSet The file-set matching rules, along with search base directory.
 276  
      * @param throwsError Throw IOException when errors have occurred by deleting files or directories.
 277  
      * @throws IOException If a matching file cannot be deleted and <code>throwsError=true</code>, otherwise
 278  
      * print warning messages.
 279  
      */
 280  
     public void delete( FileSet fileSet, boolean throwsError )
 281  
         throws IOException
 282  
     {
 283  8
         Set deletablePaths = findDeletablePaths( fileSet );
 284  
 
 285  8
         if ( messages != null && messages.isDebugEnabled() )
 286  
         {
 287  0
             messages
 288  
                 .addDebugMessage( "Found deletable paths: " + String.valueOf( deletablePaths ).replace( ',', '\n' ) ).flush();
 289  
         }
 290  
 
 291  8
         List warnMessages = new LinkedList();
 292  
 
 293  8
         for ( Iterator it = deletablePaths.iterator(); it.hasNext(); )
 294  
         {
 295  20
             String path = (String) it.next();
 296  
 
 297  20
             File file = new File( fileSet.getDirectory(), path );
 298  
 
 299  20
             if ( file.exists() )
 300  
             {
 301  15
                 if ( file.isDirectory() )
 302  
                 {
 303  4
                     if ( fileSet.isFollowSymlinks() || !isSymlink( file ) )
 304  
                     {
 305  4
                         if ( verbose && messages != null )
 306  
                         {
 307  0
                             messages.addInfoMessage( "Deleting directory: " + file ).flush();
 308  
                         }
 309  
     
 310  4
                         removeDir( file, fileSet.isFollowSymlinks(), throwsError, warnMessages );
 311  
                     }
 312  
                     else
 313  
                     { // delete a symlink to a directory without follow
 314  0
                         if ( verbose && messages != null )
 315  
                         {
 316  0
                             messages.addInfoMessage( "Deleting symlink to directory: " + file ).flush();
 317  
                         }
 318  
     
 319  0
                         if ( !file.delete() )
 320  
                         {
 321  0
                             String message = "Unable to delete symlink " + file.getAbsolutePath();
 322  0
                             if ( throwsError )
 323  
                             {
 324  0
                                 throw new IOException( message );
 325  
                             }
 326  
 
 327  0
                             if ( !warnMessages.contains( message ) )
 328  
                             {
 329  0
                                 warnMessages.add( message );
 330  
                             }
 331  0
                         }
 332  
                     }
 333  
                 }
 334  
                 else
 335  
                 {
 336  11
                     if ( verbose && messages != null )
 337  
                     {
 338  0
                         messages.addInfoMessage( "Deleting file: " + file ).flush();
 339  
                     }
 340  
 
 341  11
                     if ( !delete( file ) )
 342  
                     {
 343  0
                         String message = "Failed to delete file " + file.getAbsolutePath() + ". Reason is unknown.";
 344  0
                         if ( throwsError )
 345  
                         {
 346  0
                             throw new IOException( message );
 347  
                         }
 348  
 
 349  0
                         warnMessages.add( message );
 350  
                     }
 351  
                 }
 352  
             }
 353  20
         }
 354  
 
 355  8
         if ( messages != null && messages.isWarningEnabled() && !throwsError && ( warnMessages.size() > 0 ) )
 356  
         {
 357  0
             for ( Iterator it = warnMessages.iterator(); it.hasNext(); )
 358  
             {
 359  0
                 String msg = (String) it.next();
 360  
 
 361  0
                 messages.addWarningMessage( msg ).flush();
 362  0
             }
 363  
         }
 364  8
     }
 365  
 
 366  
     // ----------------------------------------------------------------------
 367  
     // Private methods
 368  
     // ----------------------------------------------------------------------
 369  
 
 370  
     private boolean isSymlink( File file )
 371  
         throws IOException
 372  
     {
 373  4
         File fileInCanonicalParent = null;
 374  4
         File parentDir = file.getParentFile();
 375  4
         if ( parentDir == null )
 376  
         {
 377  0
             fileInCanonicalParent = file;
 378  
         }
 379  
         else
 380  
         {
 381  4
             fileInCanonicalParent = new File( parentDir.getCanonicalPath(), file.getName() );
 382  
         }
 383  4
         if ( messages != null && messages.isDebugEnabled() )
 384  
         {
 385  0
             messages.addDebugMessage(
 386  
                                       "Checking for symlink:\nFile's canonical path: "
 387  
                                           + fileInCanonicalParent.getCanonicalPath()
 388  
                                           + "\nFile's absolute path with canonical parent: "
 389  
                                           + fileInCanonicalParent.getPath() ).flush();
 390  
         }
 391  4
         return !fileInCanonicalParent.getCanonicalFile().equals( fileInCanonicalParent.getAbsoluteFile() );
 392  
     }
 393  
 
 394  
     private Set findDeletablePaths( FileSet fileSet )
 395  
     {
 396  8
         Set includes = findDeletableDirectories( fileSet );
 397  8
         includes.addAll( findDeletableFiles( fileSet, includes ) );
 398  
 
 399  8
         return includes;
 400  
     }
 401  
 
 402  
     private Set findDeletableDirectories( FileSet fileSet )
 403  
     {
 404  8
         if ( verbose && messages != null )
 405  
         {
 406  0
             messages.addInfoMessage( "Scanning for deletable directories." ).flush();
 407  
         }
 408  
 
 409  8
         DirectoryScanner scanner = scan( fileSet );
 410  
 
 411  8
         if ( scanner == null )
 412  
         {
 413  0
             return Collections.EMPTY_SET;
 414  
         }
 415  
 
 416  8
         Set includes = new HashSet( Arrays.asList( scanner.getIncludedDirectories() ) );
 417  8
         Collection excludes = new ArrayList( Arrays.asList( scanner.getExcludedDirectories() ) );
 418  8
         Collection linksForDeletion = new ArrayList();
 419  
 
 420  8
         if ( !fileSet.isFollowSymlinks() )
 421  
         {
 422  5
             if ( verbose && messages != null )
 423  
             {
 424  0
                 messages
 425  
                     .addInfoMessage( "Adding symbolic link dirs which were previously excluded to the list being deleted." ).flush();
 426  
             }
 427  
 
 428  
             // we need to see which entries were only excluded because they're symlinks...
 429  5
             scanner.setFollowSymlinks( true );
 430  5
             scanner.scan();
 431  
 
 432  5
             if ( messages != null && messages.isDebugEnabled() )
 433  
             {
 434  0
                 messages.addDebugMessage( "Originally marked for delete: " + includes ).flush();
 435  0
                 messages.addDebugMessage( "Marked for preserve (with followSymlinks == false): " + excludes ).flush();
 436  
             }
 437  
 
 438  5
             List includedDirsAndSymlinks = Arrays.asList( scanner.getIncludedDirectories() );
 439  
 
 440  5
             linksForDeletion.addAll( excludes );
 441  5
             linksForDeletion.retainAll( includedDirsAndSymlinks );
 442  
 
 443  5
             if ( messages != null && messages.isDebugEnabled() )
 444  
             {
 445  0
                 messages.addDebugMessage( "Symlinks marked for deletion (originally mismarked): " + linksForDeletion ).flush();
 446  
             }
 447  
 
 448  5
             excludes.removeAll( includedDirsAndSymlinks );
 449  
         }
 450  
 
 451  8
         excludeParentDirectoriesOfExcludedPaths( excludes, includes );
 452  
 
 453  8
         includes.addAll( linksForDeletion );
 454  
 
 455  8
         return includes;
 456  
     }
 457  
 
 458  
     private Set findDeletableFiles( FileSet fileSet, Set deletableDirectories )
 459  
     {
 460  8
         if ( verbose && messages != null )
 461  
         {
 462  0
             messages.addInfoMessage( "Re-scanning for deletable files." ).flush();
 463  
         }
 464  
 
 465  8
         DirectoryScanner scanner = scan( fileSet );
 466  
 
 467  8
         if ( scanner == null )
 468  
         {
 469  0
             return deletableDirectories;
 470  
         }
 471  
 
 472  8
         Set includes = deletableDirectories;
 473  8
         includes.addAll( Arrays.asList( scanner.getIncludedFiles() ) );
 474  8
         Collection excludes = new ArrayList( Arrays.asList( scanner.getExcludedFiles() ) );
 475  8
         Collection linksForDeletion = new ArrayList();
 476  
 
 477  8
         if ( !fileSet.isFollowSymlinks() )
 478  
         {
 479  5
             if ( verbose && messages != null )
 480  
             {
 481  0
                 messages
 482  
                     .addInfoMessage( "Adding symbolic link files which were previously excluded to the list being deleted." ).flush();
 483  
             }
 484  
 
 485  
             // we need to see which entries were only excluded because they're symlinks...
 486  5
             scanner.setFollowSymlinks( true );
 487  5
             scanner.scan();
 488  
 
 489  5
             if ( messages != null && messages.isDebugEnabled() )
 490  
             {
 491  0
                 messages.addDebugMessage( "Originally marked for delete: " + includes ).flush();
 492  0
                 messages.addDebugMessage( "Marked for preserve (with followSymlinks == false): " + excludes ).flush();
 493  
             }
 494  
 
 495  5
             List includedFilesAndSymlinks = Arrays.asList( scanner.getIncludedFiles() );
 496  
 
 497  5
             linksForDeletion.addAll( excludes );
 498  5
             linksForDeletion.retainAll( includedFilesAndSymlinks );
 499  
 
 500  5
             if ( messages != null && messages.isDebugEnabled() )
 501  
             {
 502  0
                 messages.addDebugMessage( "Symlinks marked for deletion (originally mismarked): " + linksForDeletion ).flush();
 503  
             }
 504  
 
 505  5
             excludes.removeAll( includedFilesAndSymlinks );
 506  
         }
 507  
 
 508  8
         excludeParentDirectoriesOfExcludedPaths( excludes, includes );
 509  
 
 510  8
         includes.addAll( linksForDeletion );
 511  
 
 512  8
         return includes;
 513  
     }
 514  
 
 515  
     /**
 516  
      * Removes all parent directories of the already excluded files/directories from the given set of deletable
 517  
      * directories. I.e. if "subdir/excluded.txt" should not be deleted, "subdir" should be excluded from deletion, too.
 518  
      * 
 519  
      * @param excludedPaths The relative paths of the files/directories which are excluded from deletion, must not be
 520  
      *            <code>null</code>.
 521  
      * @param deletablePaths The relative paths to files/directories which are scheduled for deletion, must not be
 522  
      *            <code>null</code>.
 523  
      */
 524  
     private void excludeParentDirectoriesOfExcludedPaths( Collection excludedPaths, Set deletablePaths )
 525  
     {
 526  16
         for ( Iterator it = excludedPaths.iterator(); it.hasNext(); )
 527  
         {
 528  8
             String path = (String) it.next();
 529  
 
 530  8
             String parentPath = new File( path ).getParent();
 531  
 
 532  8
             while ( parentPath != null )
 533  
             {
 534  0
                 if ( messages != null && messages.isDebugEnabled() )
 535  
                 {
 536  0
                     messages.addDebugMessage( "Verifying path " + parentPath
 537  
                         + " is not present; contains file which is excluded." ).flush();
 538  
                 }
 539  
 
 540  0
                 boolean removed = deletablePaths.remove( parentPath );
 541  
 
 542  0
                 if ( removed && messages != null && messages.isDebugEnabled() )
 543  
                 {
 544  0
                     messages.addDebugMessage( "Path " + parentPath + " was removed from delete list." ).flush();
 545  
                 }
 546  
 
 547  0
                 parentPath = new File( parentPath ).getParent();
 548  0
             }
 549  8
         }
 550  
 
 551  16
         if ( !excludedPaths.isEmpty() )
 552  
         {
 553  8
             if ( messages != null && messages.isDebugEnabled() )
 554  
             {
 555  0
                 messages.addDebugMessage( "Verifying path " + "."
 556  
                     + " is not present; contains file which is excluded." ).flush();
 557  
             }
 558  
 
 559  8
             boolean removed = deletablePaths.remove( "" );
 560  
 
 561  8
             if ( removed && messages != null && messages.isDebugEnabled() )
 562  
             {
 563  0
                 messages.addDebugMessage( "Path " + "." + " was removed from delete list." ).flush();
 564  
             }
 565  
         }
 566  16
     }
 567  
 
 568  
     /**
 569  
      * Delete a directory
 570  
      *
 571  
      * @param dir the directory to delete
 572  
      * @param followSymlinks whether to follow symbolic links, or simply delete the link
 573  
      * @param throwsError Throw IOException when errors have occurred by deleting files or directories.
 574  
      * @param warnMessages A list of warning messages used when <code>throwsError=false</code>.
 575  
      * @throws IOException If a matching file cannot be deleted and <code>throwsError=true</code>.
 576  
      */
 577  
     private void removeDir( File dir, boolean followSymlinks, boolean throwsError, List warnMessages )
 578  
         throws IOException
 579  
     {
 580  4
         String[] list = dir.list();
 581  4
         if ( list == null )
 582  
         {
 583  0
             list = new String[0];
 584  
         }
 585  
 
 586  9
         for ( int i = 0; i < list.length; i++ )
 587  
         {
 588  5
             String s = list[i];
 589  5
             File f = new File( dir, s );
 590  5
             if ( f.isDirectory() && ( followSymlinks || !isSymlink( f ) ) )
 591  
             {
 592  0
                 removeDir( f, followSymlinks, throwsError, warnMessages );
 593  
             }
 594  
             else
 595  
             {
 596  5
                 if ( !delete( f ) )
 597  
                 {
 598  0
                     String message = "Unable to delete file " + f.getAbsolutePath();
 599  0
                     if ( throwsError )
 600  
                     {
 601  0
                         throw new IOException( message );
 602  
                     }
 603  
 
 604  0
                     if ( !warnMessages.contains( message ) )
 605  
                     {
 606  0
                         warnMessages.add( message );
 607  
                     }
 608  
                 }
 609  
             }
 610  
         }
 611  
 
 612  4
         if ( !delete( dir ) )
 613  
         {
 614  0
             String message = "Unable to delete directory " + dir.getAbsolutePath();
 615  0
             if ( throwsError )
 616  
             {
 617  0
                 throw new IOException( message );
 618  
             }
 619  
 
 620  0
             if ( !warnMessages.contains( message ) )
 621  
             {
 622  0
                 warnMessages.add( message );
 623  
             }
 624  
         }
 625  4
     }
 626  
 
 627  
     /**
 628  
      * Delete a file
 629  
      *
 630  
      * @param f a file
 631  
      */
 632  
     private boolean delete( File f )
 633  
     {
 634  
         try
 635  
         {
 636  20
             FileUtils.forceDelete( f );
 637  
         }
 638  0
         catch ( IOException e )
 639  
         {
 640  0
             return false;
 641  20
         }
 642  
 
 643  20
         return true;
 644  
     }
 645  
 
 646  
     private DirectoryScanner scan( FileSet fileSet )
 647  
     {
 648  18
         File basedir = new File( fileSet.getDirectory() );
 649  18
         if ( !basedir.exists() || !basedir.isDirectory() )
 650  
         {
 651  0
             return null;
 652  
         }
 653  
 
 654  18
         DirectoryScanner scanner = new DirectoryScanner();
 655  
 
 656  18
         String[] includesArray = fileSet.getIncludesArray();
 657  18
         String[] excludesArray = fileSet.getExcludesArray();
 658  
 
 659  18
         if ( includesArray.length > 0 )
 660  
         {
 661  8
             scanner.setIncludes( includesArray );
 662  
         }
 663  
 
 664  18
         if ( excludesArray.length > 0 )
 665  
         {
 666  10
             scanner.setExcludes( excludesArray );
 667  
         }
 668  
 
 669  18
         if ( fileSet.isUseDefaultExcludes() )
 670  
         {
 671  0
             scanner.addDefaultExcludes();
 672  
         }
 673  
 
 674  18
         scanner.setBasedir( basedir );
 675  18
         scanner.setFollowSymlinks( fileSet.isFollowSymlinks() );
 676  
 
 677  18
         scanner.scan();
 678  
 
 679  18
         return scanner;
 680  
     }
 681  
 
 682  
 }