Coverage Report - org.apache.maven.shared.utils.io.DirectoryWalker
 
Classes in this File Line Coverage Branch Coverage Complexity
DirectoryWalker
94%
84/89
78%
30/38
2.091
DirectoryWalker$DirStackEntry
88%
8/9
N/A
2.091
 
 1  
 package org.apache.maven.shared.utils.io;
 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 java.io.File;
 23  
 import java.util.ArrayList;
 24  
 import java.util.List;
 25  
 import java.util.Stack;
 26  
 
 27  
 /**
 28  
  * DirectoryWalker
 29  
  * 
 30  
  * @version $Id$
 31  
  */
 32  
 class DirectoryWalker
 33  
 {
 34  
     /**
 35  
      * DirStackEntry is an Item on the {@link DirectoryWalker#dirStack}
 36  
      */
 37  
     static class DirStackEntry
 38  
     {
 39  
         /**
 40  
          * Count of files in the directory.
 41  
          */
 42  
         public final int count;
 43  
 
 44  
         /**
 45  
          * Current Directory.
 46  
          */
 47  
         public final File dir;
 48  
 
 49  
         /**
 50  
          * Index (or offset) within the directory count.
 51  
          */
 52  
         public int index;
 53  
 
 54  
         /**
 55  
          * Offset for percentage calculations. Based on parent DirStackEntry.
 56  
          */
 57  
         public double percentageOffset;
 58  
 
 59  
         /**
 60  
          * Size of percentage space to work with.
 61  
          */
 62  
         public double percentageSize;
 63  
 
 64  
         /**
 65  
          * Create a DirStackEntry.
 66  
          * 
 67  
          * @param d the directory to track
 68  
          * @param length the length of entries in the directory.
 69  
          */
 70  
         public DirStackEntry( File d, int length )
 71  4
         {
 72  4
             dir = d;
 73  4
             count = length;
 74  4
         }
 75  
 
 76  
         /**
 77  
          * Calculate the next percentage offset. Used by the next DirStackEntry.
 78  
          * 
 79  
          * @return the value for the next percentage offset.
 80  
          */
 81  
         public double getNextPercentageOffset()
 82  
         {
 83  3
             return percentageOffset + ( index * ( percentageSize / count ) );
 84  
         }
 85  
 
 86  
         /**
 87  
          * Calculate the next percentage size. Used by the next DirStackEntry.
 88  
          * 
 89  
          * @return the value for the next percentage size.
 90  
          */
 91  
         public double getNextPercentageSize()
 92  
         {
 93  3
             return ( percentageSize / count );
 94  
         }
 95  
 
 96  
         /**
 97  
          * The percentage of the DirStackEntry right now. Based on count, index, percentageOffset, and percentageSize.
 98  
          * 
 99  
          * @return the percentage right now.
 100  
          */
 101  
         public int getPercentage()
 102  
         {
 103  4
             double percentageWithinDir = (double) index / (double) count;
 104  4
             return (int) Math.floor( percentageOffset + ( percentageWithinDir * percentageSize ) );
 105  
         }
 106  
 
 107  
         public String toString()
 108  
         {
 109  0
             return "DirStackEntry[" + "dir=" + dir.getAbsolutePath() + ",count=" + count + ",index=" + index
 110  
                 + ",percentageOffset=" + percentageOffset + ",percentageSize=" + percentageSize + ",percentage()="
 111  
                 + getPercentage() + ",getNextPercentageOffset()=" + getNextPercentageOffset()
 112  
                 + ",getNextPercentageSize()=" + getNextPercentageSize() + "]";
 113  
         }
 114  
     }
 115  
 
 116  
     private File baseDir;
 117  
 
 118  
     private int baseDirOffset;
 119  
 
 120  
     private Stack<DirStackEntry> dirStack;
 121  
 
 122  
     private final List<String> excludes;
 123  
 
 124  
     private final List<String> includes;
 125  
 
 126  
     private final List<DirectoryWalkListener> listeners;
 127  
 
 128  
     public DirectoryWalker()
 129  1
     {
 130  1
         this.includes = new ArrayList<String>();
 131  1
         this.excludes = new ArrayList<String>();
 132  1
         this.listeners = new ArrayList<DirectoryWalkListener>();
 133  1
     }
 134  
 
 135  
     public void addDirectoryWalkListener( DirectoryWalkListener listener )
 136  
     {
 137  1
         this.listeners.add( listener );
 138  1
     }
 139  
 
 140  
     void addExclude( String exclude )
 141  
     {
 142  37
         this.excludes.add( fixPattern( exclude ) );
 143  37
     }
 144  
 
 145  
     void addInclude( String include )
 146  
     {
 147  1
         this.includes.add( fixPattern( include ) );
 148  1
     }
 149  
 
 150  
     /**
 151  
      * Add's to the Exclude List the default list of SCM excludes.
 152  
      */
 153  
     public void addSCMExcludes()
 154  
     {
 155  1
         String scmexcludes[] = DirectoryScanner.DEFAULTEXCLUDES;
 156  38
         for ( String scmexclude : scmexcludes )
 157  
         {
 158  37
             addExclude( scmexclude );
 159  
         }
 160  1
     }
 161  
 
 162  
     private void fireStep( File file )
 163  
     {
 164  4
         DirStackEntry dsEntry = dirStack.peek();
 165  4
         int percentage = dsEntry.getPercentage();
 166  4
         for ( DirectoryWalkListener listener : this.listeners )
 167  
         {
 168  4
             listener.directoryWalkStep( percentage, file );
 169  
         }
 170  4
     }
 171  
 
 172  
     private void fireWalkFinished()
 173  
     {
 174  1
         for ( Object listener1 : this.listeners )
 175  
         {
 176  1
             DirectoryWalkListener listener = (DirectoryWalkListener) listener1;
 177  1
             listener.directoryWalkFinished();
 178  1
         }
 179  1
     }
 180  
 
 181  
     private void fireWalkStarting()
 182  
     {
 183  1
         for ( Object listener1 : this.listeners )
 184  
         {
 185  1
             DirectoryWalkListener listener = (DirectoryWalkListener) listener1;
 186  1
             listener.directoryWalkStarting( this.baseDir );
 187  1
         }
 188  1
     }
 189  
 
 190  
     private void fireDebugMessage( String message )
 191  
     {
 192  4
         for ( Object listener1 : this.listeners )
 193  
         {
 194  4
             DirectoryWalkListener listener = (DirectoryWalkListener) listener1;
 195  4
             listener.debug( message );
 196  4
         }
 197  4
     }
 198  
 
 199  
     private String fixPattern( String pattern )
 200  
     {
 201  38
         String cleanPattern = pattern;
 202  
 
 203  38
         if ( File.separatorChar != '/' )
 204  
         {
 205  0
             cleanPattern = cleanPattern.replace( '/', File.separatorChar );
 206  
         }
 207  
 
 208  38
         if ( File.separatorChar != '\\' )
 209  
         {
 210  38
             cleanPattern = cleanPattern.replace( '\\', File.separatorChar );
 211  
         }
 212  
 
 213  38
         return cleanPattern;
 214  
     }
 215  
 
 216  
     private boolean isExcluded( String name )
 217  
     {
 218  11
         return isMatch( this.excludes, name );
 219  
     }
 220  
 
 221  
     private boolean isIncluded( String name )
 222  
     {
 223  4
         return isMatch( this.includes, name );
 224  
     }
 225  
 
 226  
     private boolean isMatch( List<String> patterns, String name )
 227  
     {
 228  15
         for ( String pattern : patterns )
 229  
         {
 230  319
             boolean caseSensitive = true;
 231  319
             if ( SelectorUtils.matchPath( pattern, name, caseSensitive ) )
 232  
             {
 233  8
                 return true;
 234  
             }
 235  311
         }
 236  
 
 237  7
         return false;
 238  
     }
 239  
 
 240  
     private String relativeToBaseDir( File file )
 241  
     {
 242  11
         return file.getAbsolutePath().substring( baseDirOffset + 1 );
 243  
     }
 244  
 
 245  
     /**
 246  
      * Performs a Scan against the provided {@link #setBaseDir(File)}
 247  
      */
 248  
     public void scan()
 249  
     {
 250  1
         if ( baseDir == null )
 251  
         {
 252  0
             throw new IllegalStateException( "Scan Failure.  BaseDir not specified." );
 253  
         }
 254  
 
 255  1
         if ( !baseDir.exists() )
 256  
         {
 257  0
             throw new IllegalStateException( "Scan Failure.  BaseDir does not exist." );
 258  
         }
 259  
 
 260  1
         if ( !baseDir.isDirectory() )
 261  
         {
 262  0
             throw new IllegalStateException( "Scan Failure.  BaseDir is not a directory." );
 263  
         }
 264  
 
 265  1
         if ( this.includes.isEmpty() )
 266  
         {
 267  
             // default to include all.
 268  1
             addInclude( "**" );
 269  
         }
 270  
 
 271  1
         fireWalkStarting();
 272  1
         dirStack = new Stack<DirStackEntry>();
 273  1
         scanDir( this.baseDir );
 274  1
         fireWalkFinished();
 275  1
     }
 276  
 
 277  
     private void scanDir( File dir )
 278  
     {
 279  4
         File files[] = dir.listFiles();
 280  
 
 281  4
         if ( files == null )
 282  
         {
 283  0
             return;
 284  
         }
 285  
 
 286  4
         DirStackEntry curStackEntry = new DirStackEntry( dir, files.length );
 287  4
         if ( dirStack.isEmpty() )
 288  
         {
 289  1
             curStackEntry.percentageOffset = 0;
 290  1
             curStackEntry.percentageSize = 100;
 291  
         }
 292  
         else
 293  
         {
 294  3
             DirStackEntry previousStackEntry = dirStack.peek();
 295  3
             curStackEntry.percentageOffset = previousStackEntry.getNextPercentageOffset();
 296  3
             curStackEntry.percentageSize = previousStackEntry.getNextPercentageSize();
 297  
         }
 298  
 
 299  4
         dirStack.push( curStackEntry );
 300  
 
 301  15
         for ( int idx = 0; idx < files.length; idx++ )
 302  
         {
 303  11
             curStackEntry.index = idx;
 304  11
             String name = relativeToBaseDir( files[idx] );
 305  
 
 306  11
             if ( isExcluded( name ) )
 307  
             {
 308  4
                 fireDebugMessage( name + " is excluded." );
 309  4
                 continue;
 310  
             }
 311  
 
 312  7
             if ( files[idx].isDirectory() )
 313  
             {
 314  3
                 scanDir( files[idx] );
 315  
             }
 316  
             else
 317  
             {
 318  4
                 if ( isIncluded( name ) )
 319  
                 {
 320  4
                     fireStep( files[idx] );
 321  
                 }
 322  
             }
 323  
         }
 324  
 
 325  4
         dirStack.pop();
 326  4
     }
 327  
 
 328  
     /**
 329  
      * @param baseDir The baseDir to set.
 330  
      */
 331  
     public void setBaseDir( File baseDir )
 332  
     {
 333  1
         this.baseDir = baseDir;
 334  1
         this.baseDirOffset = baseDir.getAbsolutePath().length();
 335  1
     }
 336  
 
 337  
 }