ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dona...@apache.org
Subject cvs commit: jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/types DirectoryScanner.java FileScanner.java SourceFileScanner.java
Date Sat, 12 Jan 2002 23:49:29 GMT
donaldp     02/01/12 15:49:29

  Added:       proposal/myrmidon/src/main/org/apache/tools/ant/types
                        DirectoryScanner.java FileScanner.java
                        SourceFileScanner.java
  Log:
  Move all the generic scanners into types package
  
  Revision  Changes    Path
  1.1                  jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/types/DirectoryScanner.java
  
  Index: DirectoryScanner.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.tools.ant.types;
  
  import java.io.File;
  import java.util.ArrayList;
  import java.util.StringTokenizer;
  import org.apache.myrmidon.api.TaskException;
  
  /**
   * Class for scanning a directory for files/directories that match a certain
   * criteria. <p>
   *
   * These criteria consist of a set of include and exclude patterns. With these
   * patterns, you can select which files you want to have included, and which
   * files you want to have excluded. <p>
   *
   * The idea is simple. A given directory is recursively scanned for all files
   * and directories. Each file/directory is matched against a set of include and
   * exclude patterns. Only files/directories that match at least one pattern of
   * the include pattern list, and don't match a pattern of the exclude pattern
   * list will be placed in the list of files/directories found. <p>
   *
   * When no list of include patterns is supplied, "**" will be used, which means
   * that everything will be matched. When no list of exclude patterns is
   * supplied, an empty list is used, such that nothing will be excluded. <p>
   *
   * The pattern matching is done as follows: The name to be matched is split up
   * in path segments. A path segment is the name of a directory or file, which is
   * bounded by <code>File.separator</code> ('/' under UNIX, '\' under Windows).
   * E.g. "abc/def/ghi/xyz.java" is split up in the segments "abc", "def", "ghi"
   * and "xyz.java". The same is done for the pattern against which should be
   * matched. <p>
   *
   * Then the segments of the name and the pattern will be matched against each
   * other. When '**' is used for a path segment in the pattern, then it matches
   * zero or more path segments of the name. <p>
   *
   * There are special case regarding the use of <code>File.separator</code>s at
   * the beginningof the pattern and the string to match:<br>
   * When a pattern starts with a <code>File.separator</code>, the string to match
   * must also start with a <code>File.separator</code>. When a pattern does not
   * start with a <code>File.separator</code>, the string to match may not start
   * with a <code>File.separator</code>. When one of these rules is not obeyed,
   * the string will not match. <p>
   *
   * When a name path segment is matched against a pattern path segment, the
   * following special characters can be used: '*' matches zero or more
   * characters, '?' matches one character. <p>
   *
   * Examples: <p>
   *
   * "**\*.class" matches all .class files/dirs in a directory tree. <p>
   *
   * "test\a??.java" matches all files/dirs which start with an 'a', then two more
   * characters and then ".java", in a directory called test. <p>
   *
   * "**" matches everything in a directory tree. <p>
   *
   * "**\test\**\XYZ*" matches all files/dirs that start with "XYZ" and where
   * there is a parent directory called test (e.g. "abc\test\def\ghi\XYZ123"). <p>
   *
   * Case sensitivity may be turned off if necessary. By default, it is turned on.
   * <p>
   *
   * Example of usage: <pre>
   *   String[] includes = {"**\\*.class"};
   *   String[] excludes = {"modules\\*\\**"};
   *   ds.setIncludes(includes);
   *   ds.setExcludes(excludes);
   *   ds.setBasedir(new File("test"));
   *   ds.setCaseSensitive(true);
   *   ds.scan();
   *
   *   System.out.println("FILES:");
   *   String[] files = ds.getIncludedFiles();
   *   for (int i = 0; i < files.length;i++) {
   *     System.out.println(files[i]);
   *   }
   * </pre> This will scan a directory called test for .class files, but excludes
   * all .class files in all directories under a directory called "modules"
   *
   * @author Arnout J. Kuiper <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a>
   * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a>
   */
  public class DirectoryScanner
      implements FileScanner
  {
      /**
       * Patterns that should be excluded by default.
       *
       * @see #addDefaultExcludes()
       */
      private final static String[] DEFAULTEXCLUDES =
          {
              "**/*~",
              "**/#*#",
              "**/.#*",
              "**/%*%",
              "**/CVS",
              "**/CVS/**",
              "**/.cvsignore",
              "**/SCCS",
              "**/SCCS/**",
              "**/vssver.scc"
          };
  
      /**
       * Have the ArrayLists holding our results been built by a slow scan?
       */
      private boolean m_haveSlowResults;
  
      /**
       * Should the file system be treated as a case sensitive one?
       */
      private boolean m_isCaseSensitive = true;
  
      /**
       * Is everything we've seen so far included?
       */
      private boolean m_everythingIncluded = true;
  
      /**
       * The base directory which should be scanned.
       */
      private File m_basedir;
  
      /**
       * The files that where found and matched at least one includes, and also
       * matched at least one excludes.
       */
      private ArrayList m_dirsExcluded;
  
      /**
       * The directories that where found and matched at least one includes, and
       * matched no excludes.
       */
      private ArrayList m_dirsIncluded;
  
      /**
       * The directories that where found and did not match any includes.
       */
      private ArrayList m_dirsNotIncluded;
  
      /**
       * The patterns for the files that should be excluded.
       */
      private String[] m_excludes;
  
      /**
       * The files that where found and matched at least one includes, and also
       * matched at least one excludes.
       */
      private ArrayList m_filesExcluded;
  
      /**
       * The files that where found and matched at least one includes, and matched
       * no excludes.
       */
      private ArrayList m_filesIncluded;
  
      /**
       * The files that where found and did not match any includes.
       */
      private ArrayList m_filesNotIncluded;
  
      /**
       * The patterns for the files that should be included.
       */
      private String[] m_includes;
  
      /**
       * Matches a string against a pattern. The pattern contains two special
       * characters: '*' which means zero or more characters, '?' which means one
       * and only one character.
       *
       * @param pattern the (non-null) pattern to match against
       * @param str the (non-null) string that must be matched against the pattern
       * @return <code>true</code> when the string matches against the pattern,
       *      <code>false</code> otherwise.
       */
      public static boolean match( final String pattern, final String str )
      {
          return match( pattern, str, true );
      }
  
      /**
       * Matches a string against a pattern. The pattern contains two special
       * characters: '*' which means zero or more characters, '?' which means one
       * and only one character.
       *
       * @param pattern the (non-null) pattern to match against
       * @param str the (non-null) string that must be matched against the pattern
       * @param isCaseSensitive Description of Parameter
       * @return <code>true</code> when the string matches against the pattern,
       *      <code>false</code> otherwise.
       */
      protected static boolean match( final String pattern,
                                      final String str,
                                      final boolean isCaseSensitive )
      {
          char[] patArr = pattern.toCharArray();
          char[] strArr = str.toCharArray();
          int patIdxStart = 0;
          int patIdxEnd = patArr.length - 1;
          int strIdxStart = 0;
          int strIdxEnd = strArr.length - 1;
          char ch;
  
          boolean containsStar = false;
          for( int i = 0; i < patArr.length; i++ )
          {
              if( patArr[ i ] == '*' )
              {
                  containsStar = true;
                  break;
              }
          }
  
          if( !containsStar )
          {
              // No '*'s, so we make a shortcut
              if( patIdxEnd != strIdxEnd )
              {
                  return false;// Pattern and string do not have the same size
              }
              for( int i = 0; i <= patIdxEnd; i++ )
              {
                  ch = patArr[ i ];
                  if( ch != '?' )
                  {
                      if( isCaseSensitive && ch != strArr[ i ] )
                      {
                          return false;// Character mismatch
                      }
                      if( !isCaseSensitive && Character.toUpperCase( ch ) !=
                          Character.toUpperCase( strArr[ i ] ) )
                      {
                          return false;// Character mismatch
                      }
                  }
              }
              return true;// String matches against pattern
          }
  
          if( patIdxEnd == 0 )
          {
              return true;// Pattern contains only '*', which matches anything
          }
  
          // Process characters before first star
          while( ( ch = patArr[ patIdxStart ] ) != '*' && strIdxStart <= strIdxEnd )
          {
              if( ch != '?' )
              {
                  if( isCaseSensitive && ch != strArr[ strIdxStart ] )
                  {
                      return false;// Character mismatch
                  }
                  if( !isCaseSensitive && Character.toUpperCase( ch ) !=
                      Character.toUpperCase( strArr[ strIdxStart ] ) )
                  {
                      return false;// Character mismatch
                  }
              }
              patIdxStart++;
              strIdxStart++;
          }
          if( strIdxStart > strIdxEnd )
          {
              // All characters in the string are used. Check if only '*'s are
              // left in the pattern. If so, we succeeded. Otherwise failure.
              for( int i = patIdxStart; i <= patIdxEnd; i++ )
              {
                  if( patArr[ i ] != '*' )
                  {
                      return false;
                  }
              }
              return true;
          }
  
          // Process characters after last star
          while( ( ch = patArr[ patIdxEnd ] ) != '*' && strIdxStart <= strIdxEnd )
          {
              if( ch != '?' )
              {
                  if( isCaseSensitive && ch != strArr[ strIdxEnd ] )
                  {
                      return false;// Character mismatch
                  }
                  if( !isCaseSensitive && Character.toUpperCase( ch ) !=
                      Character.toUpperCase( strArr[ strIdxEnd ] ) )
                  {
                      return false;// Character mismatch
                  }
              }
              patIdxEnd--;
              strIdxEnd--;
          }
          if( strIdxStart > strIdxEnd )
          {
              // All characters in the string are used. Check if only '*'s are
              // left in the pattern. If so, we succeeded. Otherwise failure.
              for( int i = patIdxStart; i <= patIdxEnd; i++ )
              {
                  if( patArr[ i ] != '*' )
                  {
                      return false;
                  }
              }
              return true;
          }
  
          // process pattern between stars. padIdxStart and patIdxEnd point
          // always to a '*'.
          while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
          {
              int patIdxTmp = -1;
              for( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
              {
                  if( patArr[ i ] == '*' )
                  {
                      patIdxTmp = i;
                      break;
                  }
              }
              if( patIdxTmp == patIdxStart + 1 )
              {
                  // Two stars next to each other, skip the first one.
                  patIdxStart++;
                  continue;
              }
              // Find the pattern between padIdxStart & padIdxTmp in str between
              // strIdxStart & strIdxEnd
              int patLength = ( patIdxTmp - patIdxStart - 1 );
              int strLength = ( strIdxEnd - strIdxStart + 1 );
              int foundIdx = -1;
              strLoop :
              for( int i = 0; i <= strLength - patLength; i++ )
              {
                  for( int j = 0; j < patLength; j++ )
                  {
                      ch = patArr[ patIdxStart + j + 1 ];
                      if( ch != '?' )
                      {
                          if( isCaseSensitive && ch != strArr[ strIdxStart + i + j ] )
                          {
                              continue strLoop;
                          }
                          if( !isCaseSensitive && Character.toUpperCase( ch ) !=
                              Character.toUpperCase( strArr[ strIdxStart + i + j ] ) )
                          {
                              continue strLoop;
                          }
                      }
                  }
  
                  foundIdx = strIdxStart + i;
                  break;
              }
  
              if( foundIdx == -1 )
              {
                  return false;
              }
  
              patIdxStart = patIdxTmp;
              strIdxStart = foundIdx + patLength;
          }
  
          // All characters in the string are used. Check if only '*'s are left
          // in the pattern. If so, we succeeded. Otherwise failure.
          for( int i = patIdxStart; i <= patIdxEnd; i++ )
          {
              if( patArr[ i ] != '*' )
              {
                  return false;
              }
          }
          return true;
      }
  
      /**
       * Matches a path against a pattern.
       *
       * @param pattern the (non-null) pattern to match against
       * @param str the (non-null) string (path) to match
       * @return <code>true</code> when the pattern matches against the string.
       *      <code>false</code> otherwise.
       */
      protected static boolean matchPath( final String pattern, final String str )
      {
          return matchPath( pattern, str, true );
      }
  
      /**
       * Matches a path against a pattern.
       *
       * @param pattern the (non-null) pattern to match against
       * @param str the (non-null) string (path) to match
       * @param isCaseSensitive must a case sensitive match be done?
       * @return <code>true</code> when the pattern matches against the string.
       *      <code>false</code> otherwise.
       */
      protected static boolean matchPath( final String pattern,
                                          final String str,
                                          final boolean isCaseSensitive )
      {
          // When str starts with a File.separator, pattern has to start with a
          // File.separator.
          // When pattern starts with a File.separator, str has to start with a
          // File.separator.
          if( str.startsWith( File.separator ) !=
              pattern.startsWith( File.separator ) )
          {
              return false;
          }
  
          ArrayList patDirs = new ArrayList();
          StringTokenizer st = new StringTokenizer( pattern, File.separator );
          while( st.hasMoreTokens() )
          {
              patDirs.add( st.nextToken() );
          }
  
          ArrayList strDirs = new ArrayList();
          st = new StringTokenizer( str, File.separator );
          while( st.hasMoreTokens() )
          {
              strDirs.add( st.nextToken() );
          }
  
          int patIdxStart = 0;
          int patIdxEnd = patDirs.size() - 1;
          int strIdxStart = 0;
          int strIdxEnd = strDirs.size() - 1;
  
          // up to first '**'
          while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
          {
              String patDir = (String)patDirs.get( patIdxStart );
              if( patDir.equals( "**" ) )
              {
                  break;
              }
              if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) )
              {
                  return false;
              }
              patIdxStart++;
              strIdxStart++;
          }
          if( strIdxStart > strIdxEnd )
          {
              // String is exhausted
              for( int i = patIdxStart; i <= patIdxEnd; i++ )
              {
                  if( !patDirs.get( i ).equals( "**" ) )
                  {
                      return false;
                  }
              }
              return true;
          }
          else
          {
              if( patIdxStart > patIdxEnd )
              {
                  // String not exhausted, but pattern is. Failure.
                  return false;
              }
          }
  
          // up to last '**'
          while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
          {
              String patDir = (String)patDirs.get( patIdxEnd );
              if( patDir.equals( "**" ) )
              {
                  break;
              }
              if( !match( patDir, (String)strDirs.get( strIdxEnd ), isCaseSensitive ) )
              {
                  return false;
              }
              patIdxEnd--;
              strIdxEnd--;
          }
          if( strIdxStart > strIdxEnd )
          {
              // String is exhausted
              for( int i = patIdxStart; i <= patIdxEnd; i++ )
              {
                  if( !patDirs.get( i ).equals( "**" ) )
                  {
                      return false;
                  }
              }
              return true;
          }
  
          while( patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd )
          {
              int patIdxTmp = -1;
              for( int i = patIdxStart + 1; i <= patIdxEnd; i++ )
              {
                  if( patDirs.get( i ).equals( "**" ) )
                  {
                      patIdxTmp = i;
                      break;
                  }
              }
              if( patIdxTmp == patIdxStart + 1 )
              {
                  // '**/**' situation, so skip one
                  patIdxStart++;
                  continue;
              }
              // Find the pattern between padIdxStart & padIdxTmp in str between
              // strIdxStart & strIdxEnd
              int patLength = ( patIdxTmp - patIdxStart - 1 );
              int strLength = ( strIdxEnd - strIdxStart + 1 );
              int foundIdx = -1;
              strLoop :
              for( int i = 0; i <= strLength - patLength; i++ )
              {
                  for( int j = 0; j < patLength; j++ )
                  {
                      String subPat = (String)patDirs.get( patIdxStart + j + 1 );
                      String subStr = (String)strDirs.get( strIdxStart + i + j );
                      if( !match( subPat, subStr, isCaseSensitive ) )
                      {
                          continue strLoop;
                      }
                  }
  
                  foundIdx = strIdxStart + i;
                  break;
              }
  
              if( foundIdx == -1 )
              {
                  return false;
              }
  
              patIdxStart = patIdxTmp;
              strIdxStart = foundIdx + patLength;
          }
  
          for( int i = patIdxStart; i <= patIdxEnd; i++ )
          {
              if( !patDirs.get( i ).equals( "**" ) )
              {
                  return false;
              }
          }
  
          return true;
      }
  
      /**
       * Does the path match the start of this pattern up to the first "**". <p>
       *
       * This is not a general purpose test and should only be used if you can
       * live with false positives.</p> <p>
       *
       * <code>pattern=**\\a</code> and <code>str=b</code> will yield true.
       *
       * @param pattern the (non-null) pattern to match against
       * @param str the (non-null) string (path) to match
       * @return Description of the Returned Value
       */
      protected static boolean matchPatternStart( final String pattern, final String str )
      {
          return matchPatternStart( pattern, str, true );
      }
  
      /**
       * Does the path match the start of this pattern up to the first "**". <p>
       *
       * This is not a general purpose test and should only be used if you can
       * live with false positives.</p> <p>
       *
       * <code>pattern=**\\a</code> and <code>str=b</code> will yield true.
       *
       * @param pattern the (non-null) pattern to match against
       * @param str the (non-null) string (path) to match
       * @param isCaseSensitive must matches be case sensitive?
       * @return Description of the Returned Value
       */
      protected static boolean matchPatternStart( final String pattern,
                                                  final String str,
                                                  final boolean isCaseSensitive )
      {
          // When str starts with a File.separator, pattern has to start with a
          // File.separator.
          // When pattern starts with a File.separator, str has to start with a
          // File.separator.
          if( str.startsWith( File.separator ) !=
              pattern.startsWith( File.separator ) )
          {
              return false;
          }
  
          ArrayList patDirs = new ArrayList();
          StringTokenizer st = new StringTokenizer( pattern, File.separator );
          while( st.hasMoreTokens() )
          {
              patDirs.add( st.nextToken() );
          }
  
          ArrayList strDirs = new ArrayList();
          st = new StringTokenizer( str, File.separator );
          while( st.hasMoreTokens() )
          {
              strDirs.add( st.nextToken() );
          }
  
          int patIdxStart = 0;
          int patIdxEnd = patDirs.size() - 1;
          int strIdxStart = 0;
          int strIdxEnd = strDirs.size() - 1;
  
          // up to first '**'
          while( patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd )
          {
              String patDir = (String)patDirs.get( patIdxStart );
              if( patDir.equals( "**" ) )
              {
                  break;
              }
              if( !match( patDir, (String)strDirs.get( strIdxStart ), isCaseSensitive ) )
              {
                  return false;
              }
              patIdxStart++;
              strIdxStart++;
          }
  
          if( strIdxStart > strIdxEnd )
          {
              // String is exhausted
              return true;
          }
          else if( patIdxStart > patIdxEnd )
          {
              // String not exhausted, but pattern is. Failure.
              return false;
          }
          else
          {
              // pattern now holds ** while string is not exhausted
              // this will generate false positives but we can live with that.
              return true;
          }
      }
  
      /**
       * Sets the basedir for scanning. This is the directory that is scanned
       * recursively. All '/' and '\' characters are replaced by <code>File.separatorChar</code>
       * . So the separator used need not match <code>File.separatorChar</code>.
       *
       * @param basedir the (non-null) basedir for scanning
       */
      public void setBasedir( final String basedir )
      {
          setBasedir( new File( basedir.replace( '/', File.separatorChar ).replace( '\\', File.separatorChar ) ) );
      }
  
      /**
       * Sets the basedir for scanning. This is the directory that is scanned
       * recursively.
       *
       * @param basedir the basedir for scanning
       */
      public void setBasedir( final File basedir )
      {
          m_basedir = basedir;
      }
  
      /**
       * Sets the case sensitivity of the file system
       *
       * @param isCaseSensitive The new CaseSensitive value
       */
      public void setCaseSensitive( final boolean isCaseSensitive )
      {
          m_isCaseSensitive = isCaseSensitive;
      }
  
      /**
       * Sets the set of exclude patterns to use. All '/' and '\' characters are
       * replaced by <code>File.separatorChar</code>. So the separator used need
       * not match <code>File.separatorChar</code>. <p>
       *
       * When a pattern ends with a '/' or '\', "**" is appended.
       *
       * @param excludes list of exclude patterns
       */
      public void setExcludes( final String[] excludes )
      {
          if( excludes == null )
          {
              m_excludes = null;
          }
          else
          {
              m_excludes = new String[ excludes.length ];
              for( int i = 0; i < excludes.length; i++ )
              {
                  String pattern;
                  pattern = excludes[ i ].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
                  if( pattern.endsWith( File.separator ) )
                  {
                      pattern += "**";
                  }
                  m_excludes[ i ] = pattern;
              }
          }
      }
  
      /**
       * Sets the set of include patterns to use. All '/' and '\' characters are
       * replaced by <code>File.separatorChar</code>. So the separator used need
       * not match <code>File.separatorChar</code>. <p>
       *
       * When a pattern ends with a '/' or '\', "**" is appended.
       *
       * @param includes list of include patterns
       */
      public void setIncludes( final String[] includes )
      {
          if( includes == null )
          {
              m_includes = null;
          }
          else
          {
              m_includes = new String[ includes.length ];
              for( int i = 0; i < includes.length; i++ )
              {
                  String pattern;
                  pattern = includes[ i ].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
                  if( pattern.endsWith( File.separator ) )
                  {
                      pattern += "**";
                  }
                  m_includes[ i ] = pattern;
              }
          }
      }
  
      /**
       * Gets the basedir that is used for scanning. This is the directory that is
       * scanned recursively.
       *
       * @return the basedir that is used for scanning
       */
      public File getBasedir()
      {
          return m_basedir;
      }
  
      /**
       * Get the names of the directories that matched at least one of the include
       * patterns, an matched also at least one of the exclude patterns. The names
       * are relative to the basedir.
       *
       * @return the names of the directories
       */
      public String[] getExcludedDirectories()
          throws TaskException
      {
          slowScan();
          int count = m_dirsExcluded.size();
          String[] directories = new String[ count ];
          for( int i = 0; i < count; i++ )
          {
              directories[ i ] = (String)m_dirsExcluded.get( i );
          }
          return directories;
      }
  
      /**
       * Get the names of the files that matched at least one of the include
       * patterns, an matched also at least one of the exclude patterns. The names
       * are relative to the basedir.
       *
       * @return the names of the files
       */
      public String[] getExcludedFiles()
          throws TaskException
      {
          slowScan();
          int count = m_filesExcluded.size();
          String[] files = new String[ count ];
          for( int i = 0; i < count; i++ )
          {
              files[ i ] = (String)m_filesExcluded.get( i );
          }
          return files;
      }
  
      /**
       * Get the names of the directories that matched at least one of the include
       * patterns, an matched none of the exclude patterns. The names are relative
       * to the basedir.
       *
       * @return the names of the directories
       */
      public String[] getIncludedDirectories()
      {
          int count = m_dirsIncluded.size();
          String[] directories = new String[ count ];
          for( int i = 0; i < count; i++ )
          {
              directories[ i ] = (String)m_dirsIncluded.get( i );
          }
          return directories;
      }
  
      /**
       * Get the names of the files that matched at least one of the include
       * patterns, and matched none of the exclude patterns. The names are
       * relative to the basedir.
       *
       * @return the names of the files
       */
      public String[] getIncludedFiles()
      {
          int count = m_filesIncluded.size();
          String[] files = new String[ count ];
          for( int i = 0; i < count; i++ )
          {
              files[ i ] = (String)m_filesIncluded.get( i );
          }
          return files;
      }
  
      /**
       * Get the names of the directories that matched at none of the include
       * patterns. The names are relative to the basedir.
       *
       * @return the names of the directories
       */
      public String[] getNotIncludedDirectories()
          throws TaskException
      {
          slowScan();
          int count = m_dirsNotIncluded.size();
          String[] directories = new String[ count ];
          for( int i = 0; i < count; i++ )
          {
              directories[ i ] = (String)m_dirsNotIncluded.get( i );
          }
          return directories;
      }
  
      /**
       * Get the names of the files that matched at none of the include patterns.
       * The names are relative to the basedir.
       *
       * @return the names of the files
       */
      public String[] getNotIncludedFiles()
          throws TaskException
      {
          slowScan();
          int count = m_filesNotIncluded.size();
          String[] files = new String[ count ];
          for( int i = 0; i < count; i++ )
          {
              files[ i ] = (String)m_filesNotIncluded.get( i );
          }
          return files;
      }
  
      /**
       * Has the scanner excluded or omitted any files or directories it came
       * accross?
       *
       * @return true if all files and directories that have been found, are
       *      included.
       */
      public boolean isEverythingIncluded()
      {
          return m_everythingIncluded;
      }
  
      /**
       * Adds the array with default exclusions to the current exclusions set.
       */
      public void addDefaultExcludes()
      {
          int excludesLength = m_excludes == null ? 0 : m_excludes.length;
          String[] newExcludes;
          newExcludes = new String[ excludesLength + DEFAULTEXCLUDES.length ];
          if( excludesLength > 0 )
          {
              System.arraycopy( m_excludes, 0, newExcludes, 0, excludesLength );
          }
          for( int i = 0; i < DEFAULTEXCLUDES.length; i++ )
          {
              newExcludes[ i + excludesLength ] = DEFAULTEXCLUDES[ i ].replace( '/', File.separatorChar ).replace( '\\', File.separatorChar );
          }
          m_excludes = newExcludes;
      }
  
      /**
       * Scans the base directory for files that match at least one include
       * pattern, and don't match any exclude patterns.
       *
       */
      public void scan()
          throws TaskException
      {
          if( m_basedir == null )
          {
              throw new IllegalStateException( "No basedir set" );
          }
          if( !m_basedir.exists() )
          {
              throw new IllegalStateException( "basedir " + m_basedir
                                               + " does not exist" );
          }
          if( !m_basedir.isDirectory() )
          {
              throw new IllegalStateException( "basedir " + m_basedir
                                               + " is not a directory" );
          }
  
          if( m_includes == null )
          {
              // No includes supplied, so set it to 'matches all'
              m_includes = new String[ 1 ];
              m_includes[ 0 ] = "**";
          }
          if( m_excludes == null )
          {
              m_excludes = new String[ 0 ];
          }
  
          m_filesIncluded = new ArrayList();
          m_filesNotIncluded = new ArrayList();
          m_filesExcluded = new ArrayList();
          m_dirsIncluded = new ArrayList();
          m_dirsNotIncluded = new ArrayList();
          m_dirsExcluded = new ArrayList();
  
          if( isIncluded( "" ) )
          {
              if( !isExcluded( "" ) )
              {
                  m_dirsIncluded.add( "" );
              }
              else
              {
                  m_dirsExcluded.add( "" );
              }
          }
          else
          {
              m_dirsNotIncluded.add( "" );
          }
          scandir( m_basedir, "", true );
      }
  
      /**
       * Tests whether a name matches against at least one exclude pattern.
       *
       * @param name the name to match
       * @return <code>true</code> when the name matches against at least one
       *      exclude pattern, <code>false</code> otherwise.
       */
      protected boolean isExcluded( String name )
      {
          for( int i = 0; i < m_excludes.length; i++ )
          {
              if( matchPath( m_excludes[ i ], name, m_isCaseSensitive ) )
              {
                  return true;
              }
          }
          return false;
      }
  
      /**
       * Tests whether a name matches against at least one include pattern.
       *
       * @param name the name to match
       * @return <code>true</code> when the name matches against at least one
       *      include pattern, <code>false</code> otherwise.
       */
      protected boolean isIncluded( final String name )
      {
          for( int i = 0; i < m_includes.length; i++ )
          {
              if( matchPath( m_includes[ i ], name, m_isCaseSensitive ) )
              {
                  return true;
              }
          }
          return false;
      }
  
      /**
       * Tests whether a name matches the start of at least one include pattern.
       *
       * @param name the name to match
       * @return <code>true</code> when the name matches against at least one
       *      include pattern, <code>false</code> otherwise.
       */
      protected boolean couldHoldIncluded( final String name )
      {
          for( int i = 0; i < m_includes.length; i++ )
          {
              if( matchPatternStart( m_includes[ i ], name, m_isCaseSensitive ) )
              {
                  return true;
              }
          }
          return false;
      }
  
      /**
       * Scans the passed dir for files and directories. Found files and
       * directories are placed in their respective collections, based on the
       * matching of includes and excludes. When a directory is found, it is
       * scanned recursively.
       *
       * @param dir the directory to scan
       * @param vpath the path relative to the basedir (needed to prevent problems
       *      with an absolute path when using dir)
       * @param fast Description of Parameter
       * @see #filesIncluded
       * @see #filesNotIncluded
       * @see #filesExcluded
       * @see #dirsIncluded
       * @see #dirsNotIncluded
       * @see #dirsExcluded
       */
      protected void scandir( final File dir, final String vpath, final boolean fast )
          throws TaskException
      {
          String[] newfiles = dir.list();
  
          if( newfiles == null )
          {
              /*
               * two reasons are mentioned in the API docs for File.list
               * (1) dir is not a directory. This is impossible as
               * we wouldn't get here in this case.
               * (2) an IO error occurred (why doesn't it throw an exception
               * then???)
               */
              throw new TaskException( "IO error scanning directory "
                                       + dir.getAbsolutePath() );
          }
  
          for( int i = 0; i < newfiles.length; i++ )
          {
              String name = vpath + newfiles[ i ];
              File file = new File( dir, newfiles[ i ] );
              if( file.isDirectory() )
              {
                  if( isIncluded( name ) )
                  {
                      if( !isExcluded( name ) )
                      {
                          m_dirsIncluded.add( name );
                          if( fast )
                          {
                              scandir( file, name + File.separator, fast );
                          }
                      }
                      else
                      {
                          m_everythingIncluded = false;
                          m_dirsExcluded.add( name );
                          if( fast && couldHoldIncluded( name ) )
                          {
                              scandir( file, name + File.separator, fast );
                          }
                      }
                  }
                  else
                  {
                      m_everythingIncluded = false;
                      m_dirsNotIncluded.add( name );
                      if( fast && couldHoldIncluded( name ) )
                      {
                          scandir( file, name + File.separator, fast );
                      }
                  }
                  if( !fast )
                  {
                      scandir( file, name + File.separator, fast );
                  }
              }
              else if( file.isFile() )
              {
                  if( isIncluded( name ) )
                  {
                      if( !isExcluded( name ) )
                      {
                          m_filesIncluded.add( name );
                      }
                      else
                      {
                          m_everythingIncluded = false;
                          m_filesExcluded.add( name );
                      }
                  }
                  else
                  {
                      m_everythingIncluded = false;
                      m_filesNotIncluded.add( name );
                  }
              }
          }
      }
  
      /**
       * Toplevel invocation for the scan. <p>
       *
       * Returns immediately if a slow scan has already been requested.
       */
      protected void slowScan()
          throws TaskException
      {
          if( m_haveSlowResults )
          {
              return;
          }
  
          String[] excl = new String[ m_dirsExcluded.size() ];
          excl = (String[])m_dirsExcluded.toArray( excl );
  
          String[] notIncl = new String[ m_dirsNotIncluded.size() ];
          notIncl = (String[])m_dirsNotIncluded.toArray( notIncl );
  
          for( int i = 0; i < excl.length; i++ )
          {
              if( !couldHoldIncluded( excl[ i ] ) )
              {
                  scandir( new File( m_basedir, excl[ i ] ),
                           excl[ i ] + File.separator, false );
              }
          }
  
          for( int i = 0; i < notIncl.length; i++ )
          {
              if( !couldHoldIncluded( notIncl[ i ] ) )
              {
                  scandir( new File( m_basedir, notIncl[ i ] ),
                           notIncl[ i ] + File.separator, false );
              }
          }
  
          m_haveSlowResults = true;
      }
  
      public static String[] getDEFAULTEXCLUDES()
      {
          return DEFAULTEXCLUDES;
      }
  
      public ArrayList getDirsExcluded()
      {
          return m_dirsExcluded;
      }
  
      public void setDirsExcluded( ArrayList dirsExcluded )
      {
          m_dirsExcluded = dirsExcluded;
      }
  
      public ArrayList getDirsIncluded()
      {
          return m_dirsIncluded;
      }
  
      public void setDirsIncluded( ArrayList dirsIncluded )
      {
          m_dirsIncluded = dirsIncluded;
      }
  
      public ArrayList getDirsNotIncluded()
      {
          return m_dirsNotIncluded;
      }
  
      public void setDirsNotIncluded( ArrayList dirsNotIncluded )
      {
          m_dirsNotIncluded = dirsNotIncluded;
      }
  
      public String[] getExcludes()
      {
          return m_excludes;
      }
  
      public ArrayList getFilesExcluded()
      {
          return m_filesExcluded;
      }
  
      public void setFilesExcluded( ArrayList filesExcluded )
      {
          m_filesExcluded = filesExcluded;
      }
  
      public ArrayList getFilesIncluded()
      {
          return m_filesIncluded;
      }
  
      public void setFilesIncluded( ArrayList filesIncluded )
      {
          m_filesIncluded = filesIncluded;
      }
  
      public ArrayList getFilesNotIncluded()
      {
          return m_filesNotIncluded;
      }
  
      public void setFilesNotIncluded( ArrayList filesNotIncluded )
      {
          m_filesNotIncluded = filesNotIncluded;
      }
  
      public String[] getIncludes()
      {
          return m_includes;
      }
  }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/types/FileScanner.java
  
  Index: FileScanner.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.tools.ant.types;
  
  import java.io.File;
  import org.apache.myrmidon.api.TaskException;
  
  /**
   * An interface used to describe the actions required by any type of directory
   * scanner.
   */
  public interface FileScanner
  {
      /**
       * Adds an array with default exclusions to the current exclusions set.
       */
      void addDefaultExcludes();
  
      /**
       * Gets the basedir that is used for scanning. This is the directory that is
       * scanned recursively.
       *
       * @return the basedir that is used for scanning
       */
      File getBasedir();
  
      /**
       * Get the names of the directories that matched at least one of the include
       * patterns, an matched also at least one of the exclude patterns. The names
       * are relative to the basedir.
       *
       * @return the names of the directories
       */
      String[] getExcludedDirectories() throws TaskException;
  
      /**
       * Get the names of the files that matched at least one of the include
       * patterns, an matched also at least one of the exclude patterns. The names
       * are relative to the basedir.
       *
       * @return the names of the files
       */
      String[] getExcludedFiles() throws TaskException;
  
      /**
       * Get the names of the directories that matched at least one of the include
       * patterns, an matched none of the exclude patterns. The names are relative
       * to the basedir.
       *
       * @return the names of the directories
       */
      String[] getIncludedDirectories();
  
      /**
       * Get the names of the files that matched at least one of the include
       * patterns, an matched none of the exclude patterns. The names are relative
       * to the basedir.
       *
       * @return the names of the files
       */
      String[] getIncludedFiles() throws TaskException;
  
      /**
       * Get the names of the directories that matched at none of the include
       * patterns. The names are relative to the basedir.
       *
       * @return the names of the directories
       */
      String[] getNotIncludedDirectories() throws TaskException;
  
      /**
       * Get the names of the files that matched at none of the include patterns.
       * The names are relative to the basedir.
       *
       * @return the names of the files
       */
      String[] getNotIncludedFiles() throws TaskException;
  
      /**
       * Scans the base directory for files that match at least one include
       * pattern, and don't match any exclude patterns.
       *
       */
      void scan()
          throws TaskException;
  
      /**
       * Sets the basedir for scanning. This is the directory that is scanned
       * recursively.
       *
       * @param basedir the (non-null) basedir for scanning
       */
      void setBasedir( String basedir );
  
      /**
       * Sets the basedir for scanning. This is the directory that is scanned
       * recursively.
       *
       * @param basedir the basedir for scanning
       */
      void setBasedir( File basedir );
  
      /**
       * Sets the set of exclude patterns to use.
       *
       * @param excludes list of exclude patterns
       */
      void setExcludes( String[] excludes );
  
      /**
       * Sets the set of include patterns to use.
       *
       * @param includes list of include patterns
       */
      void setIncludes( String[] includes );
  
      /**
       * Sets the case sensitivity of the file system
       *
       * @param isCaseSensitive The new CaseSensitive value
       */
      void setCaseSensitive( boolean isCaseSensitive );
  }
  
  
  
  1.1                  jakarta-ant/proposal/myrmidon/src/main/org/apache/tools/ant/types/SourceFileScanner.java
  
  Index: SourceFileScanner.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.tools.ant.types;
  
  import java.io.File;
  import java.util.ArrayList;
  import org.apache.aut.nativelib.Os;
  import org.apache.avalon.excalibur.io.FileUtil;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  import org.apache.myrmidon.api.TaskException;
  import org.apache.tools.ant.Task;
  import org.apache.tools.ant.util.FileNameMapper;
  
  /**
   * Utility class that collects the functionality of the various scanDir methods
   * that have been scattered in several tasks before. <p>
   *
   * The only method returns an array of source files. The array is a subset of
   * the files given as a parameter and holds only those that are newer than their
   * corresponding target files.</p>
   *
   * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
   */
  public class SourceFileScanner
      extends AbstractLogEnabled
  {
      private Task m_task;
  
      /**
       * @param task The task we should log messages through
       */
      public SourceFileScanner( Task task )
      {
          this.m_task = task;
      }
  
      /**
       * Restrict the given set of files to those that are newer than their
       * corresponding target files.
       *
       * @param files the original set of files
       * @param srcDir all files are relative to this directory
       * @param destDir target files live here. if null file names returned by the
       *      mapper are assumed to be absolute.
       * @param mapper knows how to construct a target file names from source file
       *      names.
       * @return Description of the Returned Value
       */
      public String[] restrict( String[] files, File srcDir, File destDir,
                                FileNameMapper mapper )
          throws TaskException
      {
  
          long now = ( new java.util.Date() ).getTime();
          StringBuffer targetList = new StringBuffer();
  
          /*
           * If we're on Windows, we have to munge the time up to 2 secs to
           * be able to check file modification times.
           * (Windows has a max resolution of two secs for modification times)
           * Actually this is a feature of the FAT file system, NTFS does
           * not have it, so if we could reliably passively test for an NTFS
           * file systems we could turn this off...
           */
          if( Os.isFamily( "windows" ) )
          {
              now += 2000;
          }
  
          ArrayList v = new ArrayList();
          for( int i = 0; i < files.length; i++ )
          {
  
              String[] targets = mapper.mapFileName( files[ i ] );
              if( targets == null || targets.length == 0 )
              {
                  getLogger().debug( files[ i ] + " skipped - don\'t know how to handle it" );
                  continue;
              }
  
              File src = FileUtil.resolveFile( srcDir, files[ i ] );
  
              if( src.lastModified() > now )
              {
                  final String message = "Warning: " + files[ i ] + " modified in the future.";
                  getLogger().warn( message );
              }
  
              boolean added = false;
              targetList.setLength( 0 );
              for( int j = 0; !added && j < targets.length; j++ )
              {
                  File dest = FileUtil.resolveFile( destDir, targets[ j ] );
  
                  if( !dest.exists() )
                  {
                      getLogger().debug( files[ i ] + " added as " + dest.getAbsolutePath() + " doesn\'t exist." );
                      v.add( files[ i ] );
                      added = true;
                  }
                  else if( src.lastModified() > dest.lastModified() )
                  {
                      getLogger().debug( files[ i ] + " added as " + dest.getAbsolutePath() + " is outdated." );
                      v.add( files[ i ] );
                      added = true;
                  }
                  else
                  {
                      if( targetList.length() > 0 )
                      {
                          targetList.append( ", " );
                      }
                      targetList.append( dest.getAbsolutePath() );
                  }
              }
  
              if( !added )
              {
                  getLogger().debug( files[ i ] + " omitted as " + targetList.toString() + ( targets.length == 1 ? " is" : " are " ) + " up to date." );
              }
  
          }
          final String[] result = new String[ v.size() ];
          return (String[])v.toArray( result );
      }
  
      /**
       * Convinience layer on top of restrict that returns the source files as
       * File objects (containing absolute paths if srcDir is absolute).
       *
       * @param files Description of Parameter
       * @param srcDir Description of Parameter
       * @param destDir Description of Parameter
       * @param mapper Description of Parameter
       * @return Description of the Returned Value
       */
      public File[] restrictAsFiles( String[] files, File srcDir, File destDir,
                                     FileNameMapper mapper )
          throws TaskException
      {
          String[] res = restrict( files, srcDir, destDir, mapper );
          File[] result = new File[ res.length ];
          for( int i = 0; i < res.length; i++ )
          {
              result[ i ] = new File( srcDir, res[ i ] );
          }
          return result;
      }
  }
  
  
  

--
To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message