Clover coverage report - Ant Coverage
Coverage timestamp: Tue Apr 8 2003 20:43:55 EST
file stats: LOC: 963   Methods: 33
NCLOC: 370   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
DirectoryScanner.java 72.4% 67.6% 66.7% 69%
 1   
 /*
 2   
  * The Apache Software License, Version 1.1
 3   
  *
 4   
  * Copyright (c) 2000-2003 The Apache Software Foundation.  All rights
 5   
  * reserved.
 6   
  *
 7   
  * Redistribution and use in source and binary forms, with or without
 8   
  * modification, are permitted provided that the following conditions
 9   
  * are met:
 10   
  *
 11   
  * 1. Redistributions of source code must retain the above copyright
 12   
  *    notice, this list of conditions and the following disclaimer.
 13   
  *
 14   
  * 2. Redistributions in binary form must reproduce the above copyright
 15   
  *    notice, this list of conditions and the following disclaimer in
 16   
  *    the documentation and/or other materials provided with the
 17   
  *    distribution.
 18   
  *
 19   
  * 3. The end-user documentation included with the redistribution, if
 20   
  *    any, must include the following acknowlegement:
 21   
  *       "This product includes software developed by the
 22   
  *        Apache Software Foundation (http://www.apache.org/)."
 23   
  *    Alternately, this acknowlegement may appear in the software itself,
 24   
  *    if and wherever such third-party acknowlegements normally appear.
 25   
  *
 26   
  * 4. The names "Ant" and "Apache Software
 27   
  *    Foundation" must not be used to endorse or promote products derived
 28   
  *    from this software without prior written permission. For written
 29   
  *    permission, please contact apache@apache.org.
 30   
  *
 31   
  * 5. Products derived from this software may not be called "Apache"
 32   
  *    nor may "Apache" appear in their names without prior written
 33   
  *    permission of the Apache Group.
 34   
  *
 35   
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 36   
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 37   
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 38   
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 39   
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 40   
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 41   
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 42   
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 43   
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 44   
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 45   
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 46   
  * SUCH DAMAGE.
 47   
  * ====================================================================
 48   
  *
 49   
  * This software consists of voluntary contributions made by many
 50   
  * individuals on behalf of the Apache Software Foundation.  For more
 51   
  * information on the Apache Software Foundation, please see
 52   
  * <http://www.apache.org/>.
 53   
  */
 54   
 
 55   
 package org.apache.tools.ant;
 56   
 
 57   
 import java.io.File;
 58   
 import java.io.IOException;
 59   
 import java.util.Vector;
 60   
 import org.apache.tools.ant.types.Resource;
 61   
 import org.apache.tools.ant.types.ResourceFactory;
 62   
 import org.apache.tools.ant.types.selectors.FileSelector;
 63   
 import org.apache.tools.ant.types.selectors.SelectorScanner;
 64   
 import org.apache.tools.ant.types.selectors.SelectorUtils;
 65   
 import org.apache.tools.ant.util.FileUtils;
 66   
 
 67   
 /**
 68   
  * Class for scanning a directory for files/directories which match certain
 69   
  * criteria.
 70   
  * <p>
 71   
  * These criteria consist of selectors and patterns which have been specified.
 72   
  * With the selectors you can select which files you want to have included.
 73   
  * Files which are not selected are excluded. With patterns you can include
 74   
  * or exclude files based on their filename.
 75   
  * <p>
 76   
  * The idea is simple. A given directory is recursively scanned for all files
 77   
  * and directories. Each file/directory is matched against a set of selectors,
 78   
  * including special support for matching against filenames with include and
 79   
  * and exclude patterns. Only files/directories which match at least one
 80   
  * pattern of the include pattern list or other file selector, and don't match
 81   
  * any pattern of the exclude pattern list or fail to match against a required
 82   
  * selector will be placed in the list of files/directories found.
 83   
  * <p>
 84   
  * When no list of include patterns is supplied, "**" will be used, which
 85   
  * means that everything will be matched. When no list of exclude patterns is
 86   
  * supplied, an empty list is used, such that nothing will be excluded. When
 87   
  * no selectors are supplied, none are applied.
 88   
  * <p>
 89   
  * The filename pattern matching is done as follows:
 90   
  * The name to be matched is split up in path segments. A path segment is the
 91   
  * name of a directory or file, which is bounded by
 92   
  * <code>File.separator</code> ('/' under UNIX, '\' under Windows).
 93   
  * For example, "abc/def/ghi/xyz.java" is split up in the segments "abc",
 94   
  * "def","ghi" and "xyz.java".
 95   
  * The same is done for the pattern against which should be matched.
 96   
  * <p>
 97   
  * The segments of the name and the pattern are then matched against each
 98   
  * other. When '**' is used for a path segment in the pattern, it matches
 99   
  * zero or more path segments of the name.
 100   
  * <p>
 101   
  * There is a special case regarding the use of <code>File.separator</code>s
 102   
  * at the beginning of the pattern and the string to match:<br>
 103   
  * When a pattern starts with a <code>File.separator</code>, the string
 104   
  * to match must also start with a <code>File.separator</code>.
 105   
  * When a pattern does not start with a <code>File.separator</code>, the
 106   
  * string to match may not start with a <code>File.separator</code>.
 107   
  * When one of these rules is not obeyed, the string will not
 108   
  * match.
 109   
  * <p>
 110   
  * When a name path segment is matched against a pattern path segment, the
 111   
  * following special characters can be used:<br>
 112   
  * '*' matches zero or more characters<br>
 113   
  * '?' matches one character.
 114   
  * <p>
 115   
  * Examples:
 116   
  * <p>
 117   
  * "**\*.class" matches all .class files/dirs in a directory tree.
 118   
  * <p>
 119   
  * "test\a??.java" matches all files/dirs which start with an 'a', then two
 120   
  * more characters and then ".java", in a directory called test.
 121   
  * <p>
 122   
  * "**" matches everything in a directory tree.
 123   
  * <p>
 124   
  * "**\test\**\XYZ*" matches all files/dirs which start with "XYZ" and where
 125   
  * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123").
 126   
  * <p>
 127   
  * Case sensitivity may be turned off if necessary. By default, it is
 128   
  * turned on.
 129   
  * <p>
 130   
  * Example of usage:
 131   
  * <pre>
 132   
  *   String[] includes = {"**\\*.class"};
 133   
  *   String[] excludes = {"modules\\*\\**"};
 134   
  *   ds.setIncludes(includes);
 135   
  *   ds.setExcludes(excludes);
 136   
  *   ds.setBasedir(new File("test"));
 137   
  *   ds.setCaseSensitive(true);
 138   
  *   ds.scan();
 139   
  *
 140   
  *   System.out.println("FILES:");
 141   
  *   String[] files = ds.getIncludedFiles();
 142   
  *   for (int i = 0; i < files.length; i++) {
 143   
  *     System.out.println(files[i]);
 144   
  *   }
 145   
  * </pre>
 146   
  * This will scan a directory called test for .class files, but excludes all
 147   
  * files in all proper subdirectories of a directory called "modules"
 148   
  *
 149   
  * @author Arnout J. Kuiper
 150   
  * <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
 151   
  * @author Magesh Umasankar
 152   
  * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a>
 153   
  * @author <a href="mailto:levylambert@tiscali-dsl.de">Antoine Levy-Lambert</a>
 154   
  */
 155   
 public class DirectoryScanner implements FileScanner, SelectorScanner, ResourceFactory {
 156   
 
 157   
     /**
 158   
      * Patterns which should be excluded by default.
 159   
      *
 160   
      * @see #addDefaultExcludes()
 161   
      */
 162   
     protected static final String[] DEFAULTEXCLUDES = {
 163   
         // Miscellaneous typical temporary files
 164   
         "**/*~",
 165   
         "**/#*#",
 166   
         "**/.#*",
 167   
         "**/%*%",
 168   
         "**/._*",
 169   
 
 170   
         // CVS
 171   
         "**/CVS",
 172   
         "**/CVS/**",
 173   
         "**/.cvsignore",
 174   
 
 175   
         // SCCS
 176   
         "**/SCCS",
 177   
         "**/SCCS/**",
 178   
 
 179   
         // Visual SourceSafe
 180   
         "**/vssver.scc",
 181   
 
 182   
         // Subversion
 183   
         "**/.svn",
 184   
         "**/.svn/**",
 185   
 
 186   
         // Mac
 187   
         "**/.DS_Store"
 188   
     };
 189   
 
 190   
     /** The base directory to be scanned. */
 191   
     protected File basedir;
 192   
 
 193   
     /** The patterns for the files to be included. */
 194   
     protected String[] includes;
 195   
 
 196   
     /** The patterns for the files to be excluded. */
 197   
     protected String[] excludes;
 198   
 
 199   
     /** Selectors that will filter which files are in our candidate list. */
 200   
     protected FileSelector[] selectors = null;
 201   
 
 202   
     /** The files which matched at least one include and no excludes
 203   
      *  and were selected.
 204   
      */
 205   
     protected Vector filesIncluded;
 206   
 
 207   
     /** The files which did not match any includes or selectors. */
 208   
     protected Vector filesNotIncluded;
 209   
 
 210   
     /**
 211   
      * The files which matched at least one include and at least
 212   
      * one exclude.
 213   
      */
 214   
     protected Vector filesExcluded;
 215   
 
 216   
     /** The directories which matched at least one include and no excludes
 217   
      *  and were selected.
 218   
      */
 219   
     protected Vector dirsIncluded;
 220   
 
 221   
     /** The directories which were found and did not match any includes. */
 222   
     protected Vector dirsNotIncluded;
 223   
 
 224   
     /**
 225   
      * The directories which matched at least one include and at least one
 226   
      * exclude.
 227   
      */
 228   
     protected Vector dirsExcluded;
 229   
 
 230   
     /** The files which matched at least one include and no excludes and
 231   
      *  which a selector discarded.
 232   
      */
 233   
     protected Vector filesDeselected;
 234   
 
 235   
     /** The directories which matched at least one include and no excludes
 236   
      *  but which a selector discarded.
 237   
      */
 238   
     protected Vector dirsDeselected;
 239   
 
 240   
     /** Whether or not our results were built by a slow scan. */
 241   
     protected boolean haveSlowResults = false;
 242   
 
 243   
     /**
 244   
      * Whether or not the file system should be treated as a case sensitive
 245   
      * one.
 246   
      */
 247   
     protected boolean isCaseSensitive = true;
 248   
 
 249   
     /**
 250   
      * Whether or not symbolic links should be followed.
 251   
      *
 252   
      * @since Ant 1.5
 253   
      */
 254   
     private boolean followSymlinks = true;
 255   
 
 256   
     /** Helper. */
 257   
     private static final FileUtils fileUtils = FileUtils.newFileUtils();
 258   
 
 259   
     /** Whether or not everything tested so far has been included. */
 260   
     protected boolean everythingIncluded = true;
 261   
 
 262   
     /**
 263   
      * Sole constructor.
 264   
      */
 265  429
     public DirectoryScanner() {
 266   
     }
 267   
 
 268   
     /**
 269   
      * Tests whether or not a given path matches the start of a given
 270   
      * pattern up to the first "**".
 271   
      * <p>
 272   
      * This is not a general purpose test and should only be used if you
 273   
      * can live with false positives. For example, <code>pattern=**\a</code>
 274   
      * and <code>str=b</code> will yield <code>true</code>.
 275   
      *
 276   
      * @param pattern The pattern to match against. Must not be
 277   
      *                <code>null</code>.
 278   
      * @param str     The path to match, as a String. Must not be
 279   
      *                <code>null</code>.
 280   
      *
 281   
      * @return whether or not a given path matches the start of a given
 282   
      * pattern up to the first "**".
 283   
      */
 284  0
     protected static boolean matchPatternStart(String pattern, String str) {
 285  0
         return SelectorUtils.matchPatternStart(pattern, str);
 286   
     }
 287   
     /**
 288   
      * Tests whether or not a given path matches the start of a given
 289   
      * pattern up to the first "**".
 290   
      * <p>
 291   
      * This is not a general purpose test and should only be used if you
 292   
      * can live with false positives. For example, <code>pattern=**\a</code>
 293   
      * and <code>str=b</code> will yield <code>true</code>.
 294   
      *
 295   
      * @param pattern The pattern to match against. Must not be
 296   
      *                <code>null</code>.
 297   
      * @param str     The path to match, as a String. Must not be
 298   
      *                <code>null</code>.
 299   
      * @param isCaseSensitive Whether or not matching should be performed
 300   
      *                        case sensitively.
 301   
      *
 302   
      * @return whether or not a given path matches the start of a given
 303   
      * pattern up to the first "**".
 304   
      */
 305  4912
     protected static boolean matchPatternStart(String pattern, String str,
 306   
                                                boolean isCaseSensitive) {
 307  4912
         return SelectorUtils.matchPatternStart(pattern, str, isCaseSensitive);
 308   
     }
 309   
 
 310   
     /**
 311   
      * Tests whether or not a given path matches a given pattern.
 312   
      *
 313   
      * @param pattern The pattern to match against. Must not be
 314   
      *                <code>null</code>.
 315   
      * @param str     The path to match, as a String. Must not be
 316   
      *                <code>null</code>.
 317   
      *
 318   
      * @return <code>true</code> if the pattern matches against the string,
 319   
      *         or <code>false</code> otherwise.
 320   
      */
 321  0
     protected static boolean matchPath(String pattern, String str) {
 322  0
         return SelectorUtils.matchPath(pattern, str);
 323   
     }
 324   
 
 325   
     /**
 326   
      * Tests whether or not a given path matches a given pattern.
 327   
      *
 328   
      * @param pattern The pattern to match against. Must not be
 329   
      *                <code>null</code>.
 330   
      * @param str     The path to match, as a String. Must not be
 331   
      *                <code>null</code>.
 332   
      * @param isCaseSensitive Whether or not matching should be performed
 333   
      *                        case sensitively.
 334   
      *
 335   
      * @return <code>true</code> if the pattern matches against the string,
 336   
      *         or <code>false</code> otherwise.
 337   
      */
 338  137031
     protected static boolean matchPath(String pattern, String str,
 339   
                                        boolean isCaseSensitive) {
 340  137031
         return SelectorUtils.matchPath(pattern, str, isCaseSensitive);
 341   
     }
 342   
 
 343   
     /**
 344   
      * Tests whether or not a string matches against a pattern.
 345   
      * The pattern may contain two special characters:<br>
 346   
      * '*' means zero or more characters<br>
 347   
      * '?' means one and only one character
 348   
      *
 349   
      * @param pattern The pattern to match against.
 350   
      *                Must not be <code>null</code>.
 351   
      * @param str     The string which must be matched against the pattern.
 352   
      *                Must not be <code>null</code>.
 353   
      *
 354   
      * @return <code>true</code> if the string matches against the pattern,
 355   
      *         or <code>false</code> otherwise.
 356   
      */
 357  25
     public static boolean match(String pattern, String str) {
 358  25
         return SelectorUtils.match(pattern, str);
 359   
     }
 360   
 
 361   
     /**
 362   
      * Tests whether or not a string matches against a pattern.
 363   
      * The pattern may contain two special characters:<br>
 364   
      * '*' means zero or more characters<br>
 365   
      * '?' means one and only one character
 366   
      *
 367   
      * @param pattern The pattern to match against.
 368   
      *                Must not be <code>null</code>.
 369   
      * @param str     The string which must be matched against the pattern.
 370   
      *                Must not be <code>null</code>.
 371   
      * @param isCaseSensitive Whether or not matching should be performed
 372   
      *                        case sensitively.
 373   
      *
 374   
      *
 375   
      * @return <code>true</code> if the string matches against the pattern,
 376   
      *         or <code>false</code> otherwise.
 377   
      */
 378  0
     protected static boolean match(String pattern, String str,
 379   
                                    boolean isCaseSensitive) {
 380  0
         return SelectorUtils.match(pattern, str, isCaseSensitive);
 381   
     }
 382   
 
 383   
     /**
 384   
      * Sets the base directory to be scanned. This is the directory which is
 385   
      * scanned recursively. All '/' and '\' characters are replaced by
 386   
      * <code>File.separatorChar</code>, so the separator used need not match
 387   
      * <code>File.separatorChar</code>.
 388   
      *
 389   
      * @param basedir The base directory to scan.
 390   
      *                Must not be <code>null</code>.
 391   
      */
 392  0
     public void setBasedir(String basedir) {
 393  0
         setBasedir(new File(basedir.replace('/', File.separatorChar).replace(
 394   
                 '\\', File.separatorChar)));
 395   
     }
 396   
 
 397   
     /**
 398   
      * Sets the base directory to be scanned. This is the directory which is
 399   
      * scanned recursively.
 400   
      *
 401   
      * @param basedir The base directory for scanning.
 402   
      *                Should not be <code>null</code>.
 403   
      */
 404  401
     public void setBasedir(File basedir) {
 405  401
         this.basedir = basedir;
 406   
     }
 407   
 
 408   
     /**
 409   
      * Returns the base directory to be scanned.
 410   
      * This is the directory which is scanned recursively.
 411   
      *
 412   
      * @return the base directory to be scanned
 413   
      */
 414  4
     public File getBasedir() {
 415  4
         return basedir;
 416   
     }
 417   
 
 418   
     /**
 419   
      * Sets whether or not the file system should be regarded as case sensitive.
 420   
      *
 421   
      * @param isCaseSensitive whether or not the file system should be
 422   
      *                        regarded as a case sensitive one
 423   
      */
 424  397
     public void setCaseSensitive(boolean isCaseSensitive) {
 425  397
         this.isCaseSensitive = isCaseSensitive;
 426   
     }
 427   
 
 428   
     /**
 429   
      * Sets whether or not symbolic links should be followed.
 430   
      *
 431   
      * @param followSymlinks whether or not symbolic links should be followed
 432   
      */
 433  384
     public void setFollowSymlinks(boolean followSymlinks) {
 434  384
         this.followSymlinks = followSymlinks;
 435   
     }
 436   
 
 437   
     /**
 438   
      * Sets the list of include patterns to use. All '/' and '\' characters
 439   
      * are replaced by <code>File.separatorChar</code>, so the separator used
 440   
      * need not match <code>File.separatorChar</code>.
 441   
      * <p>
 442   
      * When a pattern ends with a '/' or '\', "**" is appended.
 443   
      *
 444   
      * @param includes A list of include patterns.
 445   
      *                 May be <code>null</code>, indicating that all files
 446   
      *                 should be included. If a non-<code>null</code>
 447   
      *                 list is given, all elements must be
 448   
      * non-<code>null</code>.
 449   
      */
 450  397
     public void setIncludes(String[] includes) {
 451  397
         if (includes == null) {
 452  89
             this.includes = null;
 453   
         } else {
 454  308
             this.includes = new String[includes.length];
 455  308
             for (int i = 0; i < includes.length; i++) {
 456  312
                 String pattern;
 457  312
                 pattern = includes[i].replace('/', File.separatorChar).replace(
 458   
                         '\\', File.separatorChar);
 459  312
                 if (pattern.endsWith(File.separator)) {
 460  0
                     pattern += "**";
 461   
                 }
 462  312
                 this.includes[i] = pattern;
 463   
             }
 464   
         }
 465   
     }
 466   
 
 467   
 
 468   
     /**
 469   
      * Sets the list of exclude patterns to use. All '/' and '\' characters
 470   
      * are replaced by <code>File.separatorChar</code>, so the separator used
 471   
      * need not match <code>File.separatorChar</code>.
 472   
      * <p>
 473   
      * When a pattern ends with a '/' or '\', "**" is appended.
 474   
      *
 475   
      * @param excludes A list of exclude patterns.
 476   
      *                 May be <code>null</code>, indicating that no files
 477   
      *                 should be excluded. If a non-<code>null</code> list is
 478   
      *                 given, all elements must be non-<code>null</code>.
 479   
      */
 480  401
     public void setExcludes(String[] excludes) {
 481  401
         if (excludes == null) {
 482  379
             this.excludes = null;
 483   
         } else {
 484  22
             this.excludes = new String[excludes.length];
 485  22
             for (int i = 0; i < excludes.length; i++) {
 486  99
                 String pattern;
 487  99
                 pattern = excludes[i].replace('/', File.separatorChar).replace(
 488   
                         '\\', File.separatorChar);
 489  99
                 if (pattern.endsWith(File.separator)) {
 490  0
                     pattern += "**";
 491   
                 }
 492  99
                 this.excludes[i] = pattern;
 493   
             }
 494   
         }
 495   
     }
 496   
 
 497   
 
 498   
     /**
 499   
      * Sets the selectors that will select the filelist.
 500   
      *
 501   
      * @param selectors specifies the selectors to be invoked on a scan
 502   
      */
 503  397
     public void setSelectors(FileSelector[] selectors) {
 504  397
         this.selectors = selectors;
 505   
     }
 506   
 
 507   
 
 508   
     /**
 509   
      * Returns whether or not the scanner has included all the files or
 510   
      * directories it has come across so far.
 511   
      *
 512   
      * @return <code>true</code> if all files and directories which have
 513   
      *         been found so far have been included.
 514   
      */
 515  25
     public boolean isEverythingIncluded() {
 516  25
         return everythingIncluded;
 517   
     }
 518   
 
 519   
     /**
 520   
      * Scans the base directory for files which match at least one include
 521   
      * pattern and don't match any exclude patterns. If there are selectors
 522   
      * then the files must pass muster there, as well.
 523   
      *
 524   
      * @exception IllegalStateException if the base directory was set
 525   
      *            incorrectly (i.e. if it is <code>null</code>, doesn't exist,
 526   
      *            or isn't a directory).
 527   
      */
 528  390
     public void scan() throws IllegalStateException {
 529  390
         if (basedir == null) {
 530  0
             throw new IllegalStateException("No basedir set");
 531   
         }
 532  390
         if (!basedir.exists()) {
 533  0
             throw new IllegalStateException("basedir " + basedir
 534   
                                             + " does not exist");
 535   
         }
 536  390
         if (!basedir.isDirectory()) {
 537  0
             throw new IllegalStateException("basedir " + basedir
 538   
                                             + " is not a directory");
 539   
         }
 540   
 
 541  390
         if (includes == null) {
 542   
             // No includes supplied, so set it to 'matches all'
 543  79
             includes = new String[1];
 544  79
             includes[0] = "**";
 545   
         }
 546  390
         if (excludes == null) {
 547  0
             excludes = new String[0];
 548   
         }
 549   
 
 550  390
         filesIncluded    = new Vector();
 551  390
         filesNotIncluded = new Vector();
 552  390
         filesExcluded    = new Vector();
 553  390
         filesDeselected  = new Vector();
 554  390
         dirsIncluded     = new Vector();
 555  390
         dirsNotIncluded  = new Vector();
 556  390
         dirsExcluded     = new Vector();
 557  390
         dirsDeselected   = new Vector();
 558   
 
 559  390
         if (isIncluded("")) {
 560  83
             if (!isExcluded("")) {
 561  83
                 if (isSelected("",basedir)) {
 562  83
                     dirsIncluded.addElement("");
 563   
                 } else {
 564  0
                     dirsDeselected.addElement("");
 565   
                 }
 566   
             } else {
 567  0
                 dirsExcluded.addElement("");
 568   
             }
 569   
         } else {
 570  307
             dirsNotIncluded.addElement("");
 571   
         }
 572  390
         scandir(basedir, "", true);
 573   
     }
 574   
 
 575   
     /**
 576   
      * Top level invocation for a slow scan. A slow scan builds up a full
 577   
      * list of excluded/included files/directories, whereas a fast scan
 578   
      * will only have full results for included files, as it ignores
 579   
      * directories which can't possibly hold any included files/directories.
 580   
      * <p>
 581   
      * Returns immediately if a slow scan has already been completed.
 582   
      */
 583  0
     protected void slowScan() {
 584  0
         if (haveSlowResults) {
 585  0
             return;
 586   
         }
 587   
 
 588  0
         String[] excl = new String[dirsExcluded.size()];
 589  0
         dirsExcluded.copyInto(excl);
 590   
 
 591  0
         String[] notIncl = new String[dirsNotIncluded.size()];
 592  0
         dirsNotIncluded.copyInto(notIncl);
 593   
 
 594  0
         for (int i = 0; i < excl.length; i++) {
 595  0
             if (!couldHoldIncluded(excl[i])) {
 596  0
                 scandir(new File(basedir, excl[i]),
 597   
                         excl[i] + File.separator, false);
 598   
             }
 599   
         }
 600   
 
 601  0
         for (int i = 0; i < notIncl.length; i++) {
 602  0
             if (!couldHoldIncluded(notIncl[i])) {
 603  0
                 scandir(new File(basedir, notIncl[i]),
 604   
                         notIncl[i] + File.separator, false);
 605   
             }
 606   
         }
 607   
 
 608  0
         haveSlowResults  = true;
 609   
     }
 610   
 
 611   
     /**
 612   
      * Scans the given directory for files and directories. Found files and
 613   
      * directories are placed in their respective collections, based on the
 614   
      * matching of includes, excludes, and the selectors.  When a directory
 615   
      * is found, it is scanned recursively.
 616   
      *
 617   
      * @param dir   The directory to scan. Must not be <code>null</code>.
 618   
      * @param vpath The path relative to the base directory (needed to
 619   
      *              prevent problems with an absolute path when using
 620   
      *              dir). Must not be <code>null</code>.
 621   
      * @param fast  Whether or not this call is part of a fast scan.
 622   
      *
 623   
      * @see #filesIncluded
 624   
      * @see #filesNotIncluded
 625   
      * @see #filesExcluded
 626   
      * @see #dirsIncluded
 627   
      * @see #dirsNotIncluded
 628   
      * @see #dirsExcluded
 629   
      * @see #slowScan
 630   
      */
 631  3311
     protected void scandir(File dir, String vpath, boolean fast) {
 632  3311
         String[] newfiles = dir.list();
 633   
 
 634  3311
         if (newfiles == null) {
 635   
             /*
 636   
              * two reasons are mentioned in the API docs for File.list
 637   
              * (1) dir is not a directory. This is impossible as
 638   
              *     we wouldn't get here in this case.
 639   
              * (2) an IO error occurred (why doesn't it throw an exception
 640   
              *     then???)
 641   
              */
 642  0
             throw new BuildException("IO error scanning directory "
 643   
                                      + dir.getAbsolutePath());
 644   
         }
 645   
 
 646  3311
         if (!followSymlinks) {
 647  133
             Vector noLinks = new Vector();
 648  133
             for (int i = 0; i < newfiles.length; i++) {
 649  991
                 try {
 650  991
                     if (fileUtils.isSymbolicLink(dir, newfiles[i])) {
 651  1
                         String name = vpath + newfiles[i];
 652  1
                         File   file = new File(dir, newfiles[i]);
 653  1
                         if (file.isDirectory()) {
 654  1
                             dirsExcluded.addElement(name);
 655   
                         } else {
 656  0
                             filesExcluded.addElement(name);
 657   
                         }
 658   
                     } else {
 659  990
                         noLinks.addElement(newfiles[i]);
 660   
                     }
 661   
                 } catch (IOException ioe) {
 662  0
                     String msg = "IOException caught while checking "
 663   
                         + "for links, couldn't get cannonical path!";
 664   
                     // will be caught and redirected to Ant's logging system
 665  0
                     System.err.println(msg);
 666  0
                     noLinks.addElement(newfiles[i]);
 667   
                 }
 668   
             }
 669  133
             newfiles = new String[noLinks.size()];
 670  133
             noLinks.copyInto(newfiles);
 671   
         }
 672   
 
 673  3311
         for (int i = 0; i < newfiles.length; i++) {
 674  31911
             String name = vpath + newfiles[i];
 675  31911
             File   file = new File(dir, newfiles[i]);
 676  31911
             if (file.isDirectory()) {
 677  5836
                 if (isIncluded(name)) {
 678  1833
                     if (!isExcluded(name)) {
 679  931
                         if (isSelected(name,file)) {
 680  931
                             dirsIncluded.addElement(name);
 681  931
                             if (fast) {
 682  931
                                 scandir(file, name + File.separator, fast);
 683   
                             }
 684   
                         } else {
 685  0
                             everythingIncluded = false;
 686  0
                             dirsDeselected.addElement(name);
 687  0
                             if (fast && couldHoldIncluded(name)) {
 688  0
                                 scandir(file, name + File.separator, fast);
 689   
                             }
 690   
                         }
 691   
 
 692   
                     } else {
 693  902
                         everythingIncluded = false;
 694  902
                         dirsExcluded.addElement(name);
 695  902
                         if (fast && couldHoldIncluded(name)) {
 696  902
                             scandir(file, name + File.separator, fast);
 697   
                         }
 698   
                     }
 699   
                 } else {
 700  4003
                     everythingIncluded = false;
 701  4003
                     dirsNotIncluded.addElement(name);
 702  4003
                     if (fast && couldHoldIncluded(name)) {
 703  1088
                         scandir(file, name + File.separator, fast);
 704   
                     }
 705   
                 }
 706  5836
                 if (!fast) {
 707  0
                     scandir(file, name + File.separator, fast);
 708   
                 }
 709  26075
             } else if (file.isFile()) {
 710  26075
                 if (isIncluded(name)) {
 711  10370
                     if (!isExcluded(name)) {
 712  5969
                         if (isSelected(name,file)) {
 713  5927
                             filesIncluded.addElement(name);
 714   
                         } else {
 715  42
                             everythingIncluded = false;
 716  42
                             filesDeselected.addElement(name);
 717   
                         }
 718   
                     } else {
 719  4401
                         everythingIncluded = false;
 720  4401
                         filesExcluded.addElement(name);
 721   
                     }
 722   
                 } else {
 723  15705
                     everythingIncluded = false;
 724  15705
                     filesNotIncluded.addElement(name);
 725   
                 }
 726   
             }
 727   
         }
 728   
     }
 729   
 
 730   
     /**
 731   
      * Tests whether or not a name matches against at least one include
 732   
      * pattern.
 733   
      *
 734   
      * @param name The name to match. Must not be <code>null</code>.
 735   
      * @return <code>true</code> when the name matches against at least one
 736   
      *         include pattern, or <code>false</code> otherwise.
 737   
      */
 738  32626
     protected boolean isIncluded(String name) {
 739  32626
         for (int i = 0; i < includes.length; i++) {
 740  34642
             if (matchPath(includes[i], name, isCaseSensitive)) {
 741  12609
                 return true;
 742   
             }
 743   
         }
 744  20017
         return false;
 745   
     }
 746   
 
 747   
     /**
 748   
      * Tests whether or not a name matches the start of at least one include
 749   
      * pattern.
 750   
      *
 751   
      * @param name The name to match. Must not be <code>null</code>.
 752   
      * @return <code>true</code> when the name matches against the start of at
 753   
      *         least one include pattern, or <code>false</code> otherwise.
 754   
      */
 755  4905
     protected boolean couldHoldIncluded(String name) {
 756  4905
         for (int i = 0; i < includes.length; i++) {
 757  4912
             if (matchPatternStart(includes[i], name, isCaseSensitive)) {
 758  1990
                 return true;
 759   
             }
 760   
         }
 761  2915
         return false;
 762   
     }
 763   
 
 764   
     /**
 765   
      * Tests whether or not a name matches against at least one exclude
 766   
      * pattern.
 767   
      *
 768   
      * @param name The name to match. Must not be <code>null</code>.
 769   
      * @return <code>true</code> when the name matches against at least one
 770   
      *         exclude pattern, or <code>false</code> otherwise.
 771   
      */
 772  12609
     protected boolean isExcluded(String name) {
 773  12609
         for (int i = 0; i < excludes.length; i++) {
 774  102389
             if (matchPath(excludes[i], name, isCaseSensitive)) {
 775  5314
                 return true;
 776   
             }
 777   
         }
 778  7295
         return false;
 779   
     }
 780   
 
 781   
     /**
 782   
      * Tests whether a name should be selected.
 783   
      *
 784   
      * @param name the filename to check for selecting
 785   
      * @param file the java.io.File object for this filename
 786   
      * @return <code>false</code> when the selectors says that the file
 787   
      *         should not be selected, <code>true</code> otherwise.
 788   
      */
 789  6983
     protected boolean isSelected(String name, File file) {
 790  6983
         if (selectors != null) {
 791  4926
             for (int i = 0; i < selectors.length; i++) {
 792  1202
                 if ((selectors[i].isSelected(basedir, name, file)) == false) {
 793  42
                     return false;
 794   
                 }
 795   
             }
 796   
         }
 797  6941
         return true;
 798   
     }
 799   
 
 800   
     /**
 801   
      * Returns the names of the files which matched at least one of the
 802   
      * include patterns and none of the exclude patterns.
 803   
      * The names are relative to the base directory.
 804   
      *
 805   
      * @return the names of the files which matched at least one of the
 806   
      *         include patterns and none of the exclude patterns.
 807   
      */
 808  380
     public String[] getIncludedFiles() {
 809  380
         String[] files = new String[filesIncluded.size()];
 810  380
         filesIncluded.copyInto(files);
 811  380
         return files;
 812   
     }
 813   
 
 814   
     /**
 815   
      * Returns the names of the files which matched none of the include
 816   
      * patterns. The names are relative to the base directory. This involves
 817   
      * performing a slow scan if one has not already been completed.
 818   
      *
 819   
      * @return the names of the files which matched none of the include
 820   
      *         patterns.
 821   
      *
 822   
      * @see #slowScan
 823   
      */
 824  0
     public String[] getNotIncludedFiles() {
 825  0
         slowScan();
 826  0
         String[] files = new String[filesNotIncluded.size()];
 827  0
         filesNotIncluded.copyInto(files);
 828  0
         return files;
 829   
     }
 830   
 
 831   
     /**
 832   
      * Returns the names of the files which matched at least one of the
 833   
      * include patterns and at least one of the exclude patterns.
 834   
      * The names are relative to the base directory. This involves
 835   
      * performing a slow scan if one has not already been completed.
 836   
      *
 837   
      * @return the names of the files which matched at least one of the
 838   
      *         include patterns and at at least one of the exclude patterns.
 839   
      *
 840   
      * @see #slowScan
 841   
      */
 842  0
     public String[] getExcludedFiles() {
 843  0
         slowScan();
 844  0
         String[] files = new String[filesExcluded.size()];
 845  0
         filesExcluded.copyInto(files);
 846  0
         return files;
 847   
     }
 848   
 
 849   
     /**
 850   
      * <p>Returns the names of the files which were selected out and
 851   
      * therefore not ultimately included.</p>
 852   
      *
 853   
      * <p>The names are relative to the base directory. This involves
 854   
      * performing a slow scan if one has not already been completed.</p>
 855   
      *
 856   
      * @return the names of the files which were deselected.
 857   
      *
 858   
      * @see #slowScan
 859   
      */
 860  0
     public String[] getDeselectedFiles() {
 861  0
         slowScan();
 862  0
         String[] files = new String[filesDeselected.size()];
 863  0
         filesDeselected.copyInto(files);
 864  0
         return files;
 865   
     }
 866   
 
 867   
     /**
 868   
      * Returns the names of the directories which matched at least one of the
 869   
      * include patterns and none of the exclude patterns.
 870   
      * The names are relative to the base directory.
 871   
      *
 872   
      * @return the names of the directories which matched at least one of the
 873   
      * include patterns and none of the exclude patterns.
 874   
      */
 875  138
     public String[] getIncludedDirectories() {
 876  138
         String[] directories = new String[dirsIncluded.size()];
 877  138
         dirsIncluded.copyInto(directories);
 878  138
         return directories;
 879   
     }
 880   
 
 881   
     /**
 882   
      * Returns the names of the directories which matched none of the include
 883   
      * patterns. The names are relative to the base directory. This involves
 884   
      * performing a slow scan if one has not already been completed.
 885   
      *
 886   
      * @return the names of the directories which matched none of the include
 887   
      * patterns.
 888   
      *
 889   
      * @see #slowScan
 890   
      */
 891  0
     public String[] getNotIncludedDirectories() {
 892  0
         slowScan();
 893  0
         String[] directories = new String[dirsNotIncluded.size()];
 894  0
         dirsNotIncluded.copyInto(directories);
 895  0
         return directories;
 896   
     }
 897   
 
 898   
     /**
 899   
      * Returns the names of the directories which matched at least one of the
 900   
      * include patterns and at least one of the exclude patterns.
 901   
      * The names are relative to the base directory. This involves
 902   
      * performing a slow scan if one has not already been completed.
 903   
      *
 904   
      * @return the names of the directories which matched at least one of the
 905   
      * include patterns and at least one of the exclude patterns.
 906   
      *
 907   
      * @see #slowScan
 908   
      */
 909  0
     public String[] getExcludedDirectories() {
 910  0
         slowScan();
 911  0
         String[] directories = new String[dirsExcluded.size()];
 912  0
         dirsExcluded.copyInto(directories);
 913  0
         return directories;
 914   
     }
 915   
 
 916   
     /**
 917   
      * <p>Returns the names of the directories which were selected out and
 918   
      * therefore not ultimately included.</p>
 919   
      *
 920   
      * <p>The names are relative to the base directory. This involves
 921   
      * performing a slow scan if one has not already been completed.</p>
 922   
      *
 923   
      * @return the names of the directories which were deselected.
 924   
      *
 925   
      * @see #slowScan
 926   
      */
 927  0
     public String[] getDeselectedDirectories() {
 928  0
         slowScan();
 929  0
         String[] directories = new String[dirsDeselected.size()];
 930  0
         dirsDeselected.copyInto(directories);
 931  0
         return directories;
 932   
     }
 933   
 
 934   
     /**
 935   
      * Adds default exclusions to the current exclusions set.
 936   
      */
 937  397
     public void addDefaultExcludes() {
 938  397
         int excludesLength = excludes == null ? 0 : excludes.length;
 939  397
         String[] newExcludes;
 940  397
         newExcludes = new String[excludesLength + DEFAULTEXCLUDES.length];
 941  397
         if (excludesLength > 0) {
 942  18
             System.arraycopy(excludes, 0, newExcludes, 0, excludesLength);
 943   
         }
 944  397
         for (int i = 0; i < DEFAULTEXCLUDES.length; i++) {
 945  5558
             newExcludes[i + excludesLength] = DEFAULTEXCLUDES[i].replace('/',
 946   
                     File.separatorChar).replace('\\', File.separatorChar);
 947   
         }
 948  397
         excludes = newExcludes;
 949   
     }
 950   
 
 951   
     /**
 952   
      * @param name path name of the file relative to the dir attribute.
 953   
      *
 954   
      * @since Ant 1.5.2
 955   
      */
 956  1388
     public Resource getResource(String name) {
 957  1388
         File f = fileUtils.resolveFile(basedir, name);
 958  1388
         return new Resource(name, f.exists(), f.lastModified(), 
 959   
                             f.isDirectory());
 960   
     }
 961   
 
 962   
 }
 963