Coverage Report - org.codehaus.plexus.util.DirectoryWalker
 
Classes in this File Line Coverage Branch Coverage Complexity
DirectoryWalker
63%
79/125
53%
28/52
2.069
DirectoryWalker$DirStackEntry
88%
8/9
N/A
2.069
 
 1  
 package org.codehaus.plexus.util;
 2  
 
 3  
 /*
 4  
  * Copyright The Codehaus Foundation.
 5  
  *
 6  
  * Licensed under the Apache License, Version 2.0 (the "License");
 7  
  * you may not use this file except in compliance with the License.
 8  
  * You may obtain a copy of the License at
 9  
  *
 10  
  *     http://www.apache.org/licenses/LICENSE-2.0
 11  
  *
 12  
  * Unless required by applicable law or agreed to in writing, software
 13  
  * distributed under the License is distributed on an "AS IS" BASIS,
 14  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 15  
  * See the License for the specific language governing permissions and
 16  
  * limitations under the License.
 17  
  */
 18  
 
 19  
 import java.io.File;
 20  
 import java.util.ArrayList;
 21  
 import java.util.Iterator;
 22  
 import java.util.List;
 23  
 import java.util.Stack;
 24  
 
 25  
 /**
 26  
  * DirectoryWalker
 27  
  * 
 28  
  * @version $Id$
 29  
  */
 30  
 public class DirectoryWalker
 31  
 {
 32  
     /**
 33  
      * DirStackEntry is an Item on the {@link DirectoryWalker#dirStack}
 34  
      */
 35  
     class DirStackEntry
 36  
     {
 37  
         /**
 38  
          * Count of files in the directory.
 39  
          */
 40  
         public int count;
 41  
 
 42  
         /**
 43  
          * Current Directory.
 44  
          */
 45  
         public File dir;
 46  
 
 47  
         /**
 48  
          * Index (or offset) within the directory count.
 49  
          */
 50  
         public int index;
 51  
 
 52  
         /**
 53  
          * Offset for percentage calculations. Based on parent DirStackEntry.
 54  
          */
 55  
         public double percentageOffset;
 56  
 
 57  
         /**
 58  
          * Size of percentage space to work with.
 59  
          */
 60  
         public double percentageSize;
 61  
 
 62  
         /**
 63  
          * Create a DirStackEntry.
 64  
          *
 65  
          * @param d the directory to track
 66  
          * @param length the length of entries in the directory.
 67  
          */
 68  
         public DirStackEntry( File d, int length )
 69  4
         {
 70  4
             dir = d;
 71  4
             count = length;
 72  4
         }
 73  
 
 74  
         /**
 75  
          * Calculate the next percentage offset. Used by the next DirStackEntry.
 76  
          *
 77  
          * @return the value for the next percentage offset.
 78  
          */
 79  
         public double getNextPercentageOffset()
 80  
         {
 81  3
             return percentageOffset + ( index * ( percentageSize / count ) );
 82  
         }
 83  
 
 84  
         /**
 85  
          * Calculate the next percentage size. Used by the next DirStackEntry.
 86  
          *
 87  
          * @return the value for the next percentage size.
 88  
          */
 89  
         public double getNextPercentageSize()
 90  
         {
 91  3
             return ( percentageSize / count );
 92  
         }
 93  
 
 94  
         /**
 95  
          * The percentage of the DirStackEntry right now. Based on count, index, percentageOffset, and percentageSize.
 96  
          *
 97  
          * @return the percentage right now.
 98  
          */
 99  
         public int getPercentage()
 100  
         {
 101  4
             double percentageWithinDir = (double) index / (double) count;
 102  4
             return (int) Math.floor( percentageOffset + ( percentageWithinDir * percentageSize ) );
 103  
         }
 104  
 
 105  
         public String toString()
 106  
         {
 107  0
             return "DirStackEntry[" + "dir=" + dir.getAbsolutePath() + ",count=" + count + ",index=" + index
 108  
                 + ",percentageOffset=" + percentageOffset + ",percentageSize=" + percentageSize + ",percentage()="
 109  
                 + getPercentage() + ",getNextPercentageOffset()=" + getNextPercentageOffset()
 110  
                 + ",getNextPercentageSize()=" + getNextPercentageSize() + "]";
 111  
         }
 112  
     }
 113  
 
 114  
     private File baseDir;
 115  
 
 116  
     private int baseDirOffset;
 117  
 
 118  
     private Stack<DirectoryWalker.DirStackEntry> dirStack;
 119  
 
 120  
     private List<String> excludes;
 121  
 
 122  
     private List<String> includes;
 123  
 
 124  1
     private boolean isCaseSensitive = true;
 125  
 
 126  
     private List<DirectoryWalkListener> listeners;
 127  
 
 128  1
     private boolean debugEnabled = false;
 129  
 
 130  
     public DirectoryWalker()
 131  1
     {
 132  1
         includes = new ArrayList<String>();
 133  1
         excludes = new ArrayList<String>();
 134  1
         listeners = new ArrayList<DirectoryWalkListener>();
 135  1
     }
 136  
 
 137  
     public void addDirectoryWalkListener( DirectoryWalkListener listener )
 138  
     {
 139  1
         listeners.add( listener );
 140  1
     }
 141  
 
 142  
     public void addExclude( String exclude )
 143  
     {
 144  41
         excludes.add( fixPattern( exclude ) );
 145  41
     }
 146  
 
 147  
     public void addInclude( String include )
 148  
     {
 149  1
         includes.add( fixPattern( include ) );
 150  1
     }
 151  
 
 152  
     /**
 153  
      * Add's to the Exclude List the default list of SCM excludes.
 154  
      */
 155  
     public void addSCMExcludes()
 156  
     {
 157  1
         String scmexcludes[] = DirectoryScanner.DEFAULTEXCLUDES;
 158  42
         for ( String scmexclude : scmexcludes )
 159  
         {
 160  41
             addExclude( scmexclude );
 161  
         }
 162  1
     }
 163  
 
 164  
     private void fireStep( File file )
 165  
     {
 166  4
         DirStackEntry dsEntry = dirStack.peek();
 167  4
         int percentage = dsEntry.getPercentage();
 168  4
         for ( Object listener1 : listeners )
 169  
         {
 170  4
             DirectoryWalkListener listener = (DirectoryWalkListener) listener1;
 171  4
             listener.directoryWalkStep( percentage, file );
 172  4
         }
 173  4
     }
 174  
 
 175  
     private void fireWalkFinished()
 176  
     {
 177  1
         for ( DirectoryWalkListener listener1 : listeners )
 178  
         {
 179  1
             listener1.directoryWalkFinished();
 180  1
         }
 181  1
     }
 182  
 
 183  
     private void fireWalkStarting()
 184  
     {
 185  1
         for ( DirectoryWalkListener listener1 : listeners )
 186  
         {
 187  1
             listener1.directoryWalkStarting( baseDir );
 188  1
         }
 189  1
     }
 190  
 
 191  
     private void fireDebugMessage( String message )
 192  
     {
 193  0
         for ( DirectoryWalkListener listener1 : listeners )
 194  
         {
 195  0
             listener1.debug( message );
 196  0
         }
 197  0
     }
 198  
 
 199  
     private String fixPattern( String pattern )
 200  
     {
 201  42
         String cleanPattern = pattern;
 202  
 
 203  42
         if ( File.separatorChar != '/' )
 204  
         {
 205  0
             cleanPattern = cleanPattern.replace( '/', File.separatorChar );
 206  
         }
 207  
 
 208  42
         if ( File.separatorChar != '\\' )
 209  
         {
 210  42
             cleanPattern = cleanPattern.replace( '\\', File.separatorChar );
 211  
         }
 212  
 
 213  42
         return cleanPattern;
 214  
     }
 215  
 
 216  
     public void setDebugMode( boolean debugEnabled )
 217  
     {
 218  0
         this.debugEnabled = debugEnabled;
 219  0
     }
 220  
 
 221  
     /**
 222  
      * @return Returns the baseDir.
 223  
      */
 224  
     public File getBaseDir()
 225  
     {
 226  0
         return baseDir;
 227  
     }
 228  
 
 229  
     /**
 230  
      * @return Returns the excludes.
 231  
      */
 232  
     public List<String> getExcludes()
 233  
     {
 234  0
         return excludes;
 235  
     }
 236  
 
 237  
     /**
 238  
      * @return Returns the includes.
 239  
      */
 240  
     public List<String> getIncludes()
 241  
     {
 242  0
         return includes;
 243  
     }
 244  
 
 245  
     private boolean isExcluded( String name )
 246  
     {
 247  7
         return isMatch( excludes, name );
 248  
     }
 249  
 
 250  
     private boolean isIncluded( String name )
 251  
     {
 252  4
         return isMatch( includes, name );
 253  
     }
 254  
 
 255  
     private boolean isMatch( List<String> patterns, String name )
 256  
     {
 257  11
         for ( String pattern1 : patterns )
 258  
         {
 259  291
             if ( SelectorUtils.matchPath( pattern1, name, isCaseSensitive ) )
 260  
             {
 261  4
                 return true;
 262  
             }
 263  287
         }
 264  
 
 265  7
         return false;
 266  
     }
 267  
 
 268  
     private String relativeToBaseDir( File file )
 269  
     {
 270  7
         return file.getAbsolutePath().substring( baseDirOffset + 1 );
 271  
     }
 272  
 
 273  
     /**
 274  
      * Removes a DirectoryWalkListener.
 275  
      *
 276  
      * @param listener the listener to remove.
 277  
      */
 278  
     public void removeDirectoryWalkListener( DirectoryWalkListener listener )
 279  
     {
 280  0
         listeners.remove( listener );
 281  0
     }
 282  
 
 283  
     /**
 284  
      * Performs a Scan against the provided {@link #setBaseDir(File)}
 285  
      */
 286  
     public void scan()
 287  
     {
 288  1
         if ( baseDir == null )
 289  
         {
 290  0
             throw new IllegalStateException( "Scan Failure.  BaseDir not specified." );
 291  
         }
 292  
 
 293  1
         if ( !baseDir.exists() )
 294  
         {
 295  0
             throw new IllegalStateException( "Scan Failure.  BaseDir does not exist." );
 296  
         }
 297  
 
 298  1
         if ( !baseDir.isDirectory() )
 299  
         {
 300  0
             throw new IllegalStateException( "Scan Failure.  BaseDir is not a directory." );
 301  
         }
 302  
 
 303  1
         if ( includes.isEmpty() )
 304  
         {
 305  
             // default to include all.
 306  1
             addInclude( "**" );
 307  
         }
 308  
 
 309  1
         if ( debugEnabled )
 310  
         {
 311  
             Iterator<String> it;
 312  0
             StringBuilder dbg = new StringBuilder();
 313  0
             dbg.append( "DirectoryWalker Scan" );
 314  0
             dbg.append( "\n  Base Dir: " ).append( baseDir.getAbsolutePath() );
 315  0
             dbg.append( "\n  Includes: " );
 316  0
             it = includes.iterator();
 317  0
             while ( it.hasNext() )
 318  
             {
 319  0
                 String include = it.next();
 320  0
                 dbg.append( "\n    - \"" ).append( include ).append( "\"" );
 321  0
             }
 322  0
             dbg.append( "\n  Excludes: " );
 323  0
             it = excludes.iterator();
 324  0
             while ( it.hasNext() )
 325  
             {
 326  0
                 String exclude = it.next();
 327  0
                 dbg.append( "\n    - \"" ).append( exclude ).append( "\"" );
 328  0
             }
 329  0
             fireDebugMessage( dbg.toString() );
 330  
         }
 331  
 
 332  1
         fireWalkStarting();
 333  1
         dirStack = new Stack();
 334  1
         scanDir( baseDir );
 335  1
         fireWalkFinished();
 336  1
     }
 337  
 
 338  
     private void scanDir( File dir )
 339  
     {
 340  4
         File[] files = dir.listFiles();
 341  
 
 342  4
         if ( files == null )
 343  
         {
 344  0
             return;
 345  
         }
 346  
 
 347  4
         DirectoryWalker.DirStackEntry curStackEntry = new DirectoryWalker.DirStackEntry( dir, files.length );
 348  4
         if ( dirStack.isEmpty() )
 349  
         {
 350  1
             curStackEntry.percentageOffset = 0;
 351  1
             curStackEntry.percentageSize = 100;
 352  
         }
 353  
         else
 354  
         {
 355  3
             DirectoryWalker.DirStackEntry previousStackEntry = (DirectoryWalker.DirStackEntry) dirStack.peek();
 356  3
             curStackEntry.percentageOffset = previousStackEntry.getNextPercentageOffset();
 357  3
             curStackEntry.percentageSize = previousStackEntry.getNextPercentageSize();
 358  
         }
 359  
 
 360  4
         dirStack.push( curStackEntry );
 361  
 
 362  11
         for ( int idx = 0; idx < files.length; idx++ )
 363  
         {
 364  7
             curStackEntry.index = idx;
 365  7
             String name = relativeToBaseDir( files[idx] );
 366  
 
 367  7
             if ( isExcluded( name ) )
 368  
             {
 369  0
                 fireDebugMessage( name + " is excluded." );
 370  0
                 continue;
 371  
             }
 372  
 
 373  7
             if ( files[idx].isDirectory() )
 374  
             {
 375  3
                 scanDir( files[idx] );
 376  
             }
 377  
             else
 378  
             {
 379  4
                 if ( isIncluded( name ) )
 380  
                 {
 381  4
                     fireStep( files[idx] );
 382  
                 }
 383  
             }
 384  
         }
 385  
 
 386  4
         dirStack.pop();
 387  4
     }
 388  
 
 389  
     /**
 390  
      * @param baseDir The baseDir to set.
 391  
      */
 392  
     public void setBaseDir( File baseDir )
 393  
     {
 394  1
         this.baseDir = baseDir;
 395  1
         baseDirOffset = baseDir.getAbsolutePath().length();
 396  1
     }
 397  
 
 398  
     /**
 399  
      * @param entries The excludes to set.
 400  
      */
 401  
     public void setExcludes( List<String> entries )
 402  
     {
 403  0
         excludes.clear();
 404  0
         if ( entries != null )
 405  
         {
 406  0
             for ( String entry : entries )
 407  
             {
 408  0
                 excludes.add( fixPattern( entry ) );
 409  0
             }
 410  
         }
 411  0
     }
 412  
 
 413  
     /**
 414  
      * @param entries The includes to set.
 415  
      */
 416  
     public void setIncludes( List<String> entries )
 417  
     {
 418  0
         includes.clear();
 419  0
         if ( entries != null )
 420  
         {
 421  0
             for ( String entry : entries )
 422  
             {
 423  0
                 includes.add( fixPattern( entry ) );
 424  0
             }
 425  
         }
 426  0
     }
 427  
 
 428  
 }