diff options
Diffstat (limited to 'src/main/org/apache/tools/ant')
23 files changed, 4324 insertions, 443 deletions
diff --git a/src/main/org/apache/tools/ant/DirectoryScanner.java b/src/main/org/apache/tools/ant/DirectoryScanner.java index d06c5081a..12b46560e 100644 --- a/src/main/org/apache/tools/ant/DirectoryScanner.java +++ b/src/main/org/apache/tools/ant/DirectoryScanner.java @@ -58,29 +58,37 @@ import java.io.File; import java.util.Vector; import java.util.StringTokenizer; +import org.apache.tools.ant.types.selectors.SelectorScanner; +import org.apache.tools.ant.types.selectors.FileSelector; +import org.apache.tools.ant.types.selectors.SelectorUtils; + /** * Class for scanning a directory for files/directories which match 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. + * These criteria consist of selectors and patterns which have been specified. + * With the selectors you can select which files you want to have included. + * Files which are not selected are excluded. With patterns you can include + * or exclude files based on their filename. * <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 directories. Each file/directory is matched against a set of selectors, + * including special support for matching against filenames with include and * and exclude patterns. Only files/directories which match at least one - * pattern of the include pattern list, and don't match any pattern of the - * exclude pattern list will be placed in the list of files/directories found. + * pattern of the include pattern list or other file selector, and don't match + * any pattern of the exclude pattern list or fail to match against a required + * selector 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. + * supplied, an empty list is used, such that nothing will be excluded. When + * no selectors are supplied, none are applied. * <p> - * The pattern matching is done as follows: + * The filename 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). - * For example, "abc/def/ghi/xyz.java" is split up in the segments "abc", + * For example, "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> @@ -136,11 +144,12 @@ import java.util.StringTokenizer; * This will scan a directory called test for .class files, but excludes all * files in all proper subdirectories of a directory called "modules" * - * @author Arnout J. Kuiper + * @author Arnout J. Kuiper * <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a> * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> */ -public class DirectoryScanner implements FileScanner { +public class DirectoryScanner implements FileScanner, SelectorScanner { /** * Patterns which should be excluded by default. @@ -170,36 +179,53 @@ public class DirectoryScanner implements FileScanner { /** The patterns for the files to be excluded. */ protected String[] excludes; - /** The files which matched at least one include and no excludes. */ + /** Selectors that will filter which files are in our candidate list. */ + protected FileSelector[] selectors = null; + + /** The files which matched at least one include and no excludes + * and were selected. + */ protected Vector filesIncluded; - /** The files which did not match any includes. */ + /** The files which did not match any includes or selectors. */ protected Vector filesNotIncluded; - /** - * The files which matched at least one include and at least + /** + * The files which matched at least one include and at least * one exclude. */ protected Vector filesExcluded; - /** The directories which matched at least one include and no excludes. */ + /** The directories which matched at least one include and no excludes + * and were selected. + */ protected Vector dirsIncluded; /** The directories which were found and did not match any includes. */ protected Vector dirsNotIncluded; - /** - * The directories which matched at least one include and at least one + /** + * The directories which matched at least one include and at least one * exclude. */ protected Vector dirsExcluded; + /** The files which matched at least one include and no excludes and + * which a selector discarded. + */ + protected Vector filesDeselected; + + /** The directories which matched at least one include and no excludes + * but which a selector discarded. + */ + protected Vector dirsDeselected; + /** Whether or not our results were built by a slow scan. */ protected boolean haveSlowResults = false; - /** - * Whether or not the file system should be treated as a case sensitive - * one. + /** + * Whether or not the file system should be treated as a case sensitive + * one. */ protected boolean isCaseSensitive = true; @@ -213,241 +239,87 @@ public class DirectoryScanner implements FileScanner { } /** - * Tests whether or not a given path matches the start of a given + * Tests whether or not a given path matches the start of a given * 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. For example, <code>pattern=**\a</code> + * can live with false positives. For example, <code>pattern=**\a</code> * and <code>str=b</code> will yield <code>true</code>. * - * @param pattern The pattern to match against. Must not be + * @param pattern The pattern to match against. Must not be * <code>null</code>. - * @param str The path to match, as a String. Must not be + * @param str The path to match, as a String. Must not be * <code>null</code>. - * - * @return whether or not a given path matches the start of a given + * + * @return whether or not a given path matches the start of a given * pattern up to the first "**". */ protected static boolean matchPatternStart(String pattern, String str) { - return matchPatternStart(pattern, str, true); + return SelectorUtils.matchPatternStart(pattern, str); } /** - * Tests whether or not a given path matches the start of a given + * Tests whether or not a given path matches the start of a given * 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. For example, <code>pattern=**\a</code> + * can live with false positives. For example, <code>pattern=**\a</code> * and <code>str=b</code> will yield <code>true</code>. * - * @param pattern The pattern to match against. Must not be + * @param pattern The pattern to match against. Must not be * <code>null</code>. - * @param str The path to match, as a String. Must not be + * @param str The path to match, as a String. Must not be * <code>null</code>. - * @param isCaseSensitive Whether or not matching should be performed + * @param isCaseSensitive Whether or not matching should be performed * case sensitively. - * - * @return whether or not a given path matches the start of a given + * + * @return whether or not a given path matches the start of a given * pattern up to the first "**". */ protected static boolean matchPatternStart(String pattern, String str, 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; - } - - Vector patDirs = tokenizePath (pattern); - Vector strDirs = tokenizePath (str); - - 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.elementAt(patIdxStart); - if (patDir.equals("**")) { - break; - } - if (!match(patDir, (String) strDirs.elementAt(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; - } + return SelectorUtils.matchPatternStart(pattern, str, isCaseSensitive); } /** * Tests whether or not a given path matches a given pattern. * - * @param pattern The pattern to match against. Must not be + * @param pattern The pattern to match against. Must not be * <code>null</code>. - * @param str The path to match, as a String. Must not be + * @param str The path to match, as a String. Must not be * <code>null</code>. * - * @return <code>true</code> if the pattern matches against the string, + * @return <code>true</code> if the pattern matches against the string, * or <code>false</code> otherwise. */ protected static boolean matchPath(String pattern, String str) { - return matchPath(pattern, str, true); + return SelectorUtils.matchPath(pattern, str); } /** * Tests whether or not a given path matches a given pattern. * - * @param pattern The pattern to match against. Must not be + * @param pattern The pattern to match against. Must not be * <code>null</code>. - * @param str The path to match, as a String. Must not be + * @param str The path to match, as a String. Must not be * <code>null</code>. - * @param isCaseSensitive Whether or not matching should be performed + * @param isCaseSensitive Whether or not matching should be performed * case sensitively. * - * @return <code>true</code> if the pattern matches against the string, + * @return <code>true</code> if the pattern matches against the string, * or <code>false</code> otherwise. */ - protected static boolean matchPath(String pattern, String str, + protected static boolean matchPath(String pattern, String str, 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; - } - - Vector patDirs = tokenizePath (pattern); - Vector strDirs = tokenizePath (str); - - 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.elementAt(patIdxStart); - if (patDir.equals("**")) { - break; - } - if (!match(patDir, (String) strDirs.elementAt(strIdxStart), isCaseSensitive)) { - return false; - } - patIdxStart++; - strIdxStart++; - } - if (strIdxStart > strIdxEnd) { - // String is exhausted - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (!patDirs.elementAt(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.elementAt(patIdxEnd); - if (patDir.equals("**")) { - break; - } - if (!match(patDir, (String) strDirs.elementAt(strIdxEnd), isCaseSensitive)) { - return false; - } - patIdxEnd--; - strIdxEnd--; - } - if (strIdxStart > strIdxEnd) { - // String is exhausted - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (!patDirs.elementAt(i).equals("**")) { - return false; - } - } - return true; - } - - while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { - int patIdxTmp = -1; - for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { - if (patDirs.elementAt(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.elementAt(patIdxStart + j + 1); - String subStr - = (String) strDirs.elementAt(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.elementAt(i).equals("**")) { - return false; - } - } - - return true; + return SelectorUtils.matchPath(pattern, str, isCaseSensitive); } /** - * Tests whether or not a string matches against a pattern. + * Tests whether or not a string matches against a pattern. * The pattern may contain two special characters:<br> * '*' means zero or more characters<br> * '?' means one and only one character - * - * @param pattern The pattern to match against. + * + * @param pattern The pattern to match against. * Must not be <code>null</code>. * @param str The string which must be matched against the pattern. * Must not be <code>null</code>. @@ -456,211 +328,62 @@ strLoop: * or <code>false</code> otherwise. */ public static boolean match(String pattern, String str) { - return match(pattern, str, true); + return SelectorUtils.match(pattern, str); } /** - * Tests whether or not a string matches against a pattern. + * Tests whether or not a string matches against a pattern. * The pattern may contain two special characters:<br> * '*' means zero or more characters<br> * '?' means one and only one character - * - * @param pattern The pattern to match against. + * + * @param pattern The pattern to match against. * Must not be <code>null</code>. * @param str The string which must be matched against the pattern. * Must not be <code>null</code>. - * @param isCaseSensitive Whether or not matching should be performed + * @param isCaseSensitive Whether or not matching should be performed * case sensitively. * * - * @return <code>true</code> if the string matches against the pattern, + * @return <code>true</code> if the string matches against the pattern, * or <code>false</code> otherwise. */ - protected static boolean match(String pattern, String str, + protected static boolean match(String pattern, String str, 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; + return SelectorUtils.match(pattern, str, isCaseSensitive); } /** * Breaks a path up into a Vector of path elements, tokenizing on * <code>File.separator</code>. - * + * * @param path Path to tokenize. Must not be <code>null</code>. - * + * * @return a Vector of path elements from the tokenized path */ private static Vector tokenizePath (String path) { - Vector ret = new Vector(); - StringTokenizer st = new StringTokenizer(path, File.separator); - while (st.hasMoreTokens()) { - ret.addElement(st.nextToken()); - } - return ret; + return SelectorUtils.tokenizePath(path); } - + /** * Sets the base directory to be scanned. This is the directory which 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 base directory to scan. + * @param basedir The base directory to scan. * Must not be <code>null</code>. */ public void setBasedir(String basedir) { - setBasedir(new File(basedir.replace('/', File.separatorChar).replace('\\', File.separatorChar))); + setBasedir(new File(basedir.replace('/', File.separatorChar).replace( + '\\', File.separatorChar))); } /** - * Sets the base directory to be scanned. This is the directory which is + * Sets the base directory to be scanned. This is the directory which is * scanned recursively. * - * @param basedir The base directory for scanning. + * @param basedir The base directory for scanning. * Should not be <code>null</code>. */ public void setBasedir(File basedir) { @@ -668,7 +391,7 @@ strLoop: } /** - * Returns the base directory to be scanned. + * Returns the base directory to be scanned. * This is the directory which is scanned recursively. * * @return the base directory to be scanned @@ -680,7 +403,7 @@ strLoop: /** * Sets whether or not the file system should be regarded as case sensitive. * - * @param isCaseSensitive whether or not the file system should be + * @param isCaseSensitive whether or not the file system should be * regarded as a case sensitive one */ public void setCaseSensitive(boolean isCaseSensitive) { @@ -688,16 +411,16 @@ strLoop: } /** - * Sets the list of include patterns to use. All '/' and '\' characters - * are replaced by <code>File.separatorChar</code>, so the separator used + * Sets the list 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 A list of include patterns. - * May be <code>null</code>, indicating that all files + * May be <code>null</code>, indicating that all files * should be included. If a non-<code>null</code> - * list is given, all elements must be + * list is given, all elements must be * non-<code>null</code>. */ public void setIncludes(String[] includes) { @@ -707,7 +430,8 @@ strLoop: this.includes = new String[includes.length]; for (int i = 0; i < includes.length; i++) { String pattern; - pattern = includes[i].replace('/', File.separatorChar).replace('\\', File.separatorChar); + pattern = includes[i].replace('/', File.separatorChar).replace( + '\\', File.separatorChar); if (pattern.endsWith(File.separator)) { pattern += "**"; } @@ -716,16 +440,17 @@ strLoop: } } + /** - * Sets the list of exclude patterns to use. All '/' and '\' characters - * are replaced by <code>File.separatorChar</code>, so the separator used + * Sets the list 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 A list of exclude patterns. - * May be <code>null</code>, indicating that no files - * should be excluded. If a non-<code>null</code> list is + * @param excludes A list of exclude patterns. + * May be <code>null</code>, indicating that no files + * should be excluded. If a non-<code>null</code> list is * given, all elements must be non-<code>null</code>. */ public void setExcludes(String[] excludes) { @@ -735,7 +460,8 @@ strLoop: this.excludes = new String[excludes.length]; for (int i = 0; i < excludes.length; i++) { String pattern; - pattern = excludes[i].replace('/', File.separatorChar).replace('\\', File.separatorChar); + pattern = excludes[i].replace('/', File.separatorChar).replace( + '\\', File.separatorChar); if (pattern.endsWith(File.separator)) { pattern += "**"; } @@ -744,11 +470,22 @@ strLoop: } } + + /** + * Sets the selectors that will select the filelist. + * + * @param selectors specifies the selectors to be invoked on a scan + */ + public void setSelectors(FileSelector[] selectors) { + this.selectors = selectors; + } + + /** * Returns whether or not the scanner has included all the files or * directories it has come across so far. * - * @return <code>true</code> if all files and directories which have + * @return <code>true</code> if all files and directories which have * been found so far have been included. */ public boolean isEverythingIncluded() { @@ -757,9 +494,10 @@ strLoop: /** * Scans the base directory for files which match at least one include - * pattern and don't match any exclude patterns. + * pattern and don't match any exclude patterns. If there are selectors + * then the files must pass muster there, as well. * - * @exception IllegalStateException if the base directory was set + * @exception IllegalStateException if the base directory was set * incorrectly (i.e. if it is <code>null</code>, doesn't exist, * or isn't a directory). */ @@ -788,13 +526,19 @@ strLoop: filesIncluded = new Vector(); filesNotIncluded = new Vector(); filesExcluded = new Vector(); + filesDeselected = new Vector(); dirsIncluded = new Vector(); dirsNotIncluded = new Vector(); dirsExcluded = new Vector(); + dirsDeselected = new Vector(); if (isIncluded("")) { if (!isExcluded("")) { - dirsIncluded.addElement(""); + if (isSelected("",basedir)) { + dirsIncluded.addElement(""); + } else { + dirsDeselected.addElement(""); + } } else { dirsExcluded.addElement(""); } @@ -806,8 +550,8 @@ strLoop: /** * Top level invocation for a slow scan. A slow scan builds up a full - * list of excluded/included files/directories, whereas a fast scan - * will only have full results for included files, as it ignores + * list of excluded/included files/directories, whereas a fast scan + * will only have full results for included files, as it ignores * directories which can't possibly hold any included files/directories. * <p> * Returns immediately if a slow scan has already been completed. @@ -843,12 +587,12 @@ strLoop: /** * Scans the given directory 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. + * matching of includes, excludes, and the selectors. When a directory + * is found, it is scanned recursively. * * @param dir The directory to scan. Must not be <code>null</code>. - * @param vpath The path relative to the base directory (needed to - * prevent problems with an absolute path when using + * @param vpath The path relative to the base directory (needed to + * prevent problems with an absolute path when using * dir). Must not be <code>null</code>. * @param fast Whether or not this call is part of a fast scan. * @@ -881,10 +625,19 @@ strLoop: if (file.isDirectory()) { if (isIncluded(name)) { if (!isExcluded(name)) { - dirsIncluded.addElement(name); - if (fast) { - scandir(file, name + File.separator, fast); + if (isSelected(name,file)) { + dirsIncluded.addElement(name); + if (fast) { + scandir(file, name + File.separator, fast); + } + } else { + everythingIncluded = false; + dirsDeselected.addElement(name); + if (fast && couldHoldIncluded(name)) { + scandir(file, name + File.separator, fast); + } } + } else { everythingIncluded = false; dirsExcluded.addElement(name); @@ -905,7 +658,12 @@ strLoop: } else if (file.isFile()) { if (isIncluded(name)) { if (!isExcluded(name)) { - filesIncluded.addElement(name); + if (isSelected(name,file)) { + filesIncluded.addElement(name); + } else { + everythingIncluded = false; + filesDeselected.addElement(name); + } } else { everythingIncluded = false; filesExcluded.addElement(name); @@ -919,7 +677,7 @@ strLoop: } /** - * Tests whether or not a name matches against at least one include + * Tests whether or not a name matches against at least one include * pattern. * * @param name The name to match. Must not be <code>null</code>. @@ -936,11 +694,11 @@ strLoop: } /** - * Tests whether or not a name matches the start of at least one include + * Tests whether or not a name matches the start of at least one include * pattern. * * @param name The name to match. Must not be <code>null</code>. - * @return <code>true</code> when the name matches against the start of at + * @return <code>true</code> when the name matches against the start of at * least one include pattern, or <code>false</code> otherwise. */ protected boolean couldHoldIncluded(String name) { @@ -953,7 +711,7 @@ strLoop: } /** - * Tests whether or not a name matches against at least one exclude + * Tests whether or not a name matches against at least one exclude * pattern. * * @param name The name to match. Must not be <code>null</code>. @@ -970,7 +728,26 @@ strLoop: } /** - * Returns the names of the files which matched at least one of the + * Tests whether a name should be selected. + * + * @param name the filename to check for selecting + * @param file the java.io.File object for this filename + * @return <code>false</code> when the selectors says that the file + * should not be selected, <code>true</code> otherwise. + */ + protected boolean isSelected(String name, File file) { + if (selectors != null) { + for (int i = 0; i < selectors.length; i++) { + if ((selectors[i].isSelected(basedir, name, file)) == false) { + return false; + } + } + } + return true; + } + + /** + * Returns the names of the files which matched at least one of the * include patterns and none of the exclude patterns. * The names are relative to the base directory. * @@ -981,19 +758,19 @@ strLoop: int count = filesIncluded.size(); String[] files = new String[count]; for (int i = 0; i < count; i++) { - files[i] = (String) filesIncluded.elementAt(i); + files[i] = (String)filesIncluded.elementAt(i); } return files; } /** - * Returns the names of the files which matched none of the include + * Returns the names of the files which matched none of the include * patterns. The names are relative to the base directory. This involves * performing a slow scan if one has not already been completed. * - * @return the names of the files which matched none of the include + * @return the names of the files which matched none of the include * patterns. - * + * * @see #slowScan */ public String[] getNotIncludedFiles() { @@ -1001,20 +778,20 @@ strLoop: int count = filesNotIncluded.size(); String[] files = new String[count]; for (int i = 0; i < count; i++) { - files[i] = (String) filesNotIncluded.elementAt(i); + files[i] = (String)filesNotIncluded.elementAt(i); } return files; } /** - * Returns the names of the files which matched at least one of the + * Returns the names of the files which matched at least one of the * include patterns and at least one of the exclude patterns. * The names are relative to the base directory. This involves * performing a slow scan if one has not already been completed. * - * @return the names of the files which matched at least one of the + * @return the names of the files which matched at least one of the * include patterns and at at least one of the exclude patterns. - * + * * @see #slowScan */ public String[] getExcludedFiles() { @@ -1022,13 +799,32 @@ strLoop: int count = filesExcluded.size(); String[] files = new String[count]; for (int i = 0; i < count; i++) { - files[i] = (String) filesExcluded.elementAt(i); + files[i] = (String)filesExcluded.elementAt(i); + } + return files; + } + + /** + * Returns the names of the files which were selected. The names + * are relative to the base directory. This involves performing + * a slow scan if one has not already been completed. + * + * @return the names of the files which were selected. + * + * @see #slowScan + */ + public String[] getDeselectedFiles() { + slowScan(); + int count = filesDeselected.size(); + String[] files = new String[count]; + for (int i = 0; i < count; i++) { + files[i] = (String)filesDeselected.elementAt(i); } return files; } /** - * Returns the names of the directories which matched at least one of the + * Returns the names of the directories which matched at least one of the * include patterns and none of the exclude patterns. * The names are relative to the base directory. * @@ -1039,7 +835,7 @@ strLoop: int count = dirsIncluded.size(); String[] directories = new String[count]; for (int i = 0; i < count; i++) { - directories[i] = (String) dirsIncluded.elementAt(i); + directories[i] = (String)dirsIncluded.elementAt(i); } return directories; } @@ -1051,7 +847,7 @@ strLoop: * * @return the names of the directories which matched none of the include * patterns. - * + * * @see #slowScan */ public String[] getNotIncludedDirectories() { @@ -1059,20 +855,20 @@ strLoop: int count = dirsNotIncluded.size(); String[] directories = new String[count]; for (int i = 0; i < count; i++) { - directories[i] = (String) dirsNotIncluded.elementAt(i); + directories[i] = (String)dirsNotIncluded.elementAt(i); } return directories; } /** - * Returns the names of the directories which matched at least one of the + * Returns the names of the directories which matched at least one of the * include patterns and at least one of the exclude patterns. * The names are relative to the base directory. This involves * performing a slow scan if one has not already been completed. - * - * @return the names of the directories which matched at least one of the + * + * @return the names of the directories which matched at least one of the * include patterns and at least one of the exclude patterns. - * + * * @see #slowScan */ public String[] getExcludedDirectories() { @@ -1080,7 +876,26 @@ strLoop: int count = dirsExcluded.size(); String[] directories = new String[count]; for (int i = 0; i < count; i++) { - directories[i] = (String) dirsExcluded.elementAt(i); + directories[i] = (String)dirsExcluded.elementAt(i); + } + return directories; + } + + /** + * Returns the names of the directories which were selected. The names + * are relative to the base directory. This involves performing a + * slow scan if one has not already been completed. + * + * @return the names of the directories which were selected. + * + * @see #slowScan + */ + public String[] getDeselectedDirectories() { + slowScan(); + int count = dirsDeselected.size(); + String[] directories = new String[count]; + for (int i = 0; i < count; i++) { + directories[i] = (String)dirsDeselected.elementAt(i); } return directories; } @@ -1096,7 +911,8 @@ strLoop: System.arraycopy(excludes, 0, newExcludes, 0, excludesLength); } for (int i = 0; i < DEFAULTEXCLUDES.length; i++) { - newExcludes[i + excludesLength] = DEFAULTEXCLUDES[i].replace('/', File.separatorChar).replace('\\', File.separatorChar); + newExcludes[i + excludesLength] = DEFAULTEXCLUDES[i].replace('/', + File.separatorChar).replace('\\', File.separatorChar); } excludes = newExcludes; } diff --git a/src/main/org/apache/tools/ant/types/AbstractFileSet.java b/src/main/org/apache/tools/ant/types/AbstractFileSet.java index 6e457d056..00b4a4bb6 100644 --- a/src/main/org/apache/tools/ant/types/AbstractFileSet.java +++ b/src/main/org/apache/tools/ant/types/AbstractFileSet.java @@ -57,6 +57,7 @@ import org.apache.tools.ant.BuildException; import org.apache.tools.ant.FileScanner; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.selectors.*; import java.io.File; import java.util.Stack; @@ -70,23 +71,26 @@ import java.util.Enumeration; * * <p>Common base class for DirSet and FileSet.</p> * - * @author <a href="mailto:ajkuiper@wxs.nl">Arnout J. Kuiper</a> + * @author <a href="mailto:ajkuiper@wxs.nl">Arnout J. Kuiper</a> * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a> * @author <a href="mailto:rubys@us.ibm.com">Sam Ruby</a> * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a> * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> */ -public abstract class AbstractFileSet extends DataType implements Cloneable { - +public abstract class AbstractFileSet extends DataType implements Cloneable, + SelectorContainer { + private PatternSet defaultPatterns = new PatternSet(); private Vector additionalPatterns = new Vector(); + private Vector selectors = new Vector(); private File dir; private boolean useDefaultExcludes = true; private boolean isCaseSensitive = true; - + public AbstractFileSet() { super(); } @@ -104,7 +108,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { * Makes this instance in effect a reference to another instance. * * <p>You must not set another attribute or nest elements inside - * this element if you make it a reference.</p> + * this element if you make it a reference.</p> */ public void setRefid(Reference r) throws BuildException { if (dir != null || defaultPatterns.hasPatterns()) { @@ -158,7 +162,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { } return defaultPatterns.createInclude(); } - + /** * add a name entry on the include files list */ @@ -168,7 +172,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { } return defaultPatterns.createIncludesFile(); } - + /** * add a name entry on the exclude list */ @@ -188,7 +192,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { } return defaultPatterns.createExcludesFile(); } - + /** * Appends <code>includes</code> to the current list of include * patterns. @@ -224,7 +228,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { /** * Sets the name of the file containing the includes patterns. * - * @param incl The file to fetch the include patterns from. + * @param incl The file to fetch the include patterns from. */ public void setIncludesfile(File incl) throws BuildException { if (isReference()) { @@ -237,7 +241,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { /** * Sets the name of the file containing the includes patterns. * - * @param excl The file to fetch the exclude patterns from. + * @param excl The file to fetch the exclude patterns from. */ public void setExcludesfile(File excl) throws BuildException { if (isReference()) { @@ -250,7 +254,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { /** * Sets whether default exclusions should be used or not. * - * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions + * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions * should be used, "false"|"off"|"no" when they * shouldn't be used. */ @@ -272,8 +276,8 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { this.isCaseSensitive = isCaseSensitive; } - - + + /** * sets the name used for this datatype instance. */ @@ -290,14 +294,14 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { } } } - + String classname = getClass().getName(); - + int dotIndex = classname.lastIndexOf("."); if (dotIndex == -1) { return classname; } - return classname.substring(dotIndex + 1); + return classname.substring(dotIndex + 1); } /** @@ -326,12 +330,12 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { ds.scan(); return ds; } - + public void setupDirectoryScanner(FileScanner ds, Project p) { if (ds == null) { throw new IllegalArgumentException("ds cannot be null"); } - + ds.setBasedir(dir); final int count = additionalPatterns.size(); @@ -340,11 +344,16 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { defaultPatterns.append((PatternSet) o, p); } - p.log(getDataTypeName() + ": Setup scanner in dir " + dir + + p.log(getDataTypeName() + ": Setup scanner in dir " + dir + " with " + defaultPatterns, Project.MSG_DEBUG); - + ds.setIncludes(defaultPatterns.getIncludePatterns(p)); ds.setExcludes(defaultPatterns.getExcludePatterns(p)); + if (ds instanceof SelectorScanner) { + SelectorScanner ss = (SelectorScanner)ds; + ss.setSelectors(getSelectors(p)); + } + if (useDefaultExcludes) { ds.addDefaultExcludes(); } @@ -353,7 +362,7 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { /** * Performs the check for circular references and returns the - * referenced FileSet. + * referenced FileSet. */ protected AbstractFileSet getRef(Project p) { if (!checked) { @@ -361,10 +370,10 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { stk.push(this); dieOnCircularReference(stk, p); } - + Object o = ref.getReferencedObject(p); if (!getClass().isAssignableFrom(o.getClass())) { - String msg = ref.getRefId() + " doesn\'t denote a " + String msg = ref.getRefId() + " doesn\'t denote a " + getDataTypeName(); throw new BuildException(msg); } else { @@ -372,4 +381,153 @@ public abstract class AbstractFileSet extends DataType implements Cloneable { } } + // SelectorContainer methods + + /** + * Indicates whether there are any selectors here. + * + * @return whether any selectors are in this container + */ + public boolean hasSelectors() { + return !(selectors.isEmpty()); + } + + /** + * Gives the count of the number of selectors in this container + * + * @return the number of selectors in this container + */ + public int selectorCount() { + return selectors.size(); + } + + /** + * Returns the set of selectors as an array. + * + * @return an array of selectors in this container + */ + public FileSelector[] getSelectors(Project p) { + if (isReference()) { + return getRef(p).getSelectors(p); + } else { + FileSelector[] result = new FileSelector[selectors.size()]; + selectors.copyInto(result); + return result; + } + } + + /** + * Returns an enumerator for accessing the set of selectors. + * + * @return an enumerator that goes through each of the selectors + */ + public Enumeration selectorElements() { + return selectors.elements(); + } + + /** + * Add a new selector into this container. + * + * @param selector the new selector to add + */ + public void appendSelector(FileSelector selector) { + if (isReference()) { + throw noChildrenAllowed(); + } + selectors.addElement(selector); + } + + /* Methods below all implement the static selectors */ + + /** + * add an "And" selector entry on the selector list + */ + public void addAnd(AndSelector selector) { + appendSelector(selector); + } + + /** + * add an "Or" selector entry on the selector list + */ + public void addOr(OrSelector selector) { + appendSelector(selector); + } + + /** + * add a "Not" selector entry on the selector list + */ + public void addNot(NotSelector selector) { + appendSelector(selector); + } + + /** + * add a "None" selector entry on the selector list + */ + public void addNone(NoneSelector selector) { + appendSelector(selector); + } + + /** + * add a majority selector entry on the selector list + */ + public void addMajority(MajoritySelector selector) { + appendSelector(selector); + } + + /** + * add a selector date entry on the selector list + */ + public void addDateselect(DateSelector selector) { + appendSelector(selector); + } + + /** + * add a selector size entry on the selector list + */ + public void addSizeselect(SizeSelector selector) { + appendSelector(selector); + } + + /** + * add a selector filename entry on the selector list + */ + public void addFilenameselect(FilenameSelector selector) { + appendSelector(selector); + } + + /** + * add an extended selector entry on the selector list + */ + public void addExtendSelect(ExtendSelector selector) { + appendSelector(selector); + } + + /** + * add a contains selector entry on the selector list + */ + public void addContainsSelect(ContainsSelector selector) { + appendSelector(selector); + } + + /** + * add a present selector entry on the selector list + */ + public void addPresentSelect(PresentSelector selector) { + appendSelector(selector); + } + + /** + * add a depth selector entry on the selector list + */ + public void addDepthSelect(DepthSelector selector) { + appendSelector(selector); + } + + /** + * add a depends selector entry on the selector list + */ + public void addDependSelect(DependSelector selector) { + appendSelector(selector); + } + } diff --git a/src/main/org/apache/tools/ant/types/selectors/AndSelector.java b/src/main/org/apache/tools/ant/types/selectors/AndSelector.java new file mode 100644 index 000000000..51345571e --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/AndSelector.java @@ -0,0 +1,111 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.util.Enumeration; + +/** + * This selector has a collection of other selectors, all of which have to + * select a file in order for this selector to select it. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class AndSelector extends BaseSelectorContainer { + + /** + * Default constructor. + */ + public AndSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + if (hasSelectors()) { + buf.append("{andselect: "); + buf.append(super.toString()); + buf.append("}"); + } + return buf.toString(); + } + + /** + * Returns true (the file is selected) only if all other selectors + * agree that the file should be selected. + * + * @param basedir the base directory the scan is being done from + * @param filename the name of the file to check + * @param file a java.io.File object for the filename that the selector + * can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + validate(); + Enumeration e = selectorElements(); + boolean result; + + while(e.hasMoreElements()) { + result = ((FileSelector)e.nextElement()).isSelected(basedir, + filename,file); + if (!result) { + return false; + } + } + return true; + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java b/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java new file mode 100644 index 000000000..73095f8d3 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/BaseExtendSelector.java @@ -0,0 +1,121 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.DataType; +import org.apache.tools.ant.types.Parameter; + + +/** + * Convenience base class for all selectors accessed through ExtendSelector. + * It provides support for gathering the parameters together as well as for + * assigning an error message and throwing a build exception if an error is + * detected. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public abstract class BaseExtendSelector extends BaseSelector implements + ExtendFileSelector { + + /** The passed in parameter array. */ + protected Parameter[] parameters = null; + + /** + * Default constructor. + */ + public BaseExtendSelector() { + } + + /** + * Set all the Parameters for this dynamic selector, collected by + * the ExtendSelector class. + * + * @param parameters the complete set of parameters for this selector + */ + public void setParameters(Parameter[] parameters) { + this.parameters = parameters; + } + + /** + * Allows access to the parameters gathered and set within the + * <extendselect> tag. + * + * @return the set of parameters defined for this selector + */ + protected Parameter[] getParameters() { + return parameters; + } + + /** + * Method that each selector will implement to create their + * selection behaviour. If there is a problem with the setup + * of a selector, it can throw a BuildException to indicate + * the problem. + * + * @param basedir A java.io.File object for the base directory + * @param filename The name of the file to check + * @param file A File object for this filename + * @return whether the file should be selected or not + */ + public abstract boolean isSelected(File basedir, String filename, + File file) + throws BuildException; + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java b/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java new file mode 100644 index 000000000..b1e0a0f3f --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/BaseSelector.java @@ -0,0 +1,143 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.DataType; + +/** + * A convenience base class that you can subclass Selectors from. It + * provides some helpful common behaviour. Note that there is no need + * for Selectors to inherit from this class, it is only necessary that + * they implement FileSelector. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public abstract class BaseSelector extends DataType implements FileSelector { + + private String errmsg = null; + + + /** + * Do nothing constructor. + */ + public BaseSelector() { + } + + /** + * Allows all selectors to indicate a setup error. Note that only + * the first error message is recorded. + * + * @param msg The error message any BuildException should throw. + */ + public void setError(String msg) { + if (errmsg == null) { + errmsg = msg; + } + } + + /** + * Returns any error messages that have been set. + * + * @return the error condition + */ + public String getError() { + return errmsg; + } + + + /** + * <p>Subclasses can override this method to provide checking of their + * state. So long as they call validate() from isSelected(), this will + * be called automatically (unless they override validate()).</p> + * <p>Implementations should check for incorrect settings and call + * setError() as necessary.</p> + */ + public void verifySettings() { + } + + + + /** + * Subclasses can use this to throw the requisite exception + * in isSelected() in the case of an error condition. + */ + public void validate() { + verifySettings(); + if (getError() != null) { + throw new BuildException(errmsg); + } + } + + /** + * Method that each selector will implement to create their + * selection behaviour. If there is a problem with the setup + * of a selector, it can throw a BuildException to indicate + * the problem. + * + * @param basedir A java.io.File object for the base directory + * @param filename The name of the file to check + * @param file A File object for this filename + * @return whether the file should be selected or not + */ + public abstract boolean isSelected(File basedir, String filename, + File file); + +} + + diff --git a/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java new file mode 100644 index 000000000..ac3a97f6c --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/BaseSelectorContainer.java @@ -0,0 +1,312 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Reference; + +import java.io.File; +import java.util.Enumeration; +import java.util.Stack; +import java.util.Vector; + +/** + * This is the base class for selectors that can contain other selectors. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public abstract class BaseSelectorContainer extends BaseSelector + implements SelectorContainer { + + private Vector selectorsList = new Vector(); + + /** + * Default constructor. + */ + public BaseSelectorContainer() { + } + + /** + * Indicates whether there are any selectors here. + */ + public boolean hasSelectors() { + return !(selectorsList.isEmpty()); + } + + /** + * Gives the count of the number of selectors in this container + */ + public int selectorCount() { + return selectorsList.size(); + } + + /** + * Returns the set of selectors as an array. + */ + public FileSelector[] getSelectors(Project p) { + if (isReference()) { + return getRef(p).getSelectors(p); + } else { + FileSelector[] result = new FileSelector[selectorsList.size()]; + selectorsList.copyInto(result); + return result; + } + } + + /** + * Returns an enumerator for accessing the set of selectors. + */ + public Enumeration selectorElements() { + return selectorsList.elements(); + } + + /** + * Performs the check for circular references and returns the + * referenced SelectorContainer. + */ + private SelectorContainer getRef(Project p) { + if (!checked) { + Stack stk = new Stack(); + stk.push(this); + dieOnCircularReference(stk, p); + } + + Object o = ref.getReferencedObject(p); + if (!(o instanceof SelectorContainer)) { + throw new BuildException(ref.getRefId() + + " doesn\'t denote a selector type"); + } else { + return (SelectorContainer) o; + } + } + + /** + * Convert the Selectors within this container to a string. This will + * just be a helper class for the subclasses that put their own name + * around the contents listed here. + * + * @return comma separated list of Selectors contained in this one + */ + public String toString() { + StringBuffer buf = new StringBuffer(); + Enumeration e = selectorElements(); + if (e.hasMoreElements()) { + while(e.hasMoreElements()) { + buf.append(e.nextElement().toString()); + if (e.hasMoreElements()) { + buf.append(", "); + } + } + } + + return buf.toString(); + } + + /** + * Add a new selector into this container. + * + * @param selector the new selector to add + * @return the selector that was added + */ + public void appendSelector(FileSelector selector) { + if (isReference()) { + throw noChildrenAllowed(); + } + selectorsList.addElement(selector); + } + + /** + * <p>This implementation validates the container by calling + * verifySettings() and then validates each contained selector + * provided that the selector implements the validate interface. + * </p> + * <p>Ordinarily, this will validate all the elements of a selector + * container even if the isSelected() method of some elements is + * never called. This has two effects:</p> + * <ul> + * <li>Validation will often occur twice. + * <li>Since it is not required that selectors derive from + * BaseSelector, there could be selectors in the container whose + * error conditions are not detected if their isSelected() call + * is never made. + * </ul> + */ + public void validate() { + verifySettings(); + String errmsg = getError(); + if (errmsg != null) { + throw new BuildException(errmsg); + } + Enumeration e = selectorElements(); + while(e.hasMoreElements()) { + Object o = e.nextElement(); + if (o instanceof BaseSelector) { + ((BaseSelector)o).validate(); + } + } + } + + + /** + * Method that each selector will implement to create their selection + * behaviour. This is what makes SelectorContainer abstract. + * + * @param basedir the base directory the scan is being done from + * @param filename the name of the file to check + * @param file a java.io.File object for the filename that the selector + * can use + * @return whether the file should be selected or not + */ + public abstract boolean isSelected(File basedir, String filename, + File file); + + + /* Methods below all implement the static selectors */ + + /** + * add an "And" selector entry on the selector list + */ + public void addAnd(AndSelector selector) { + appendSelector(selector); + } + + /** + * add an "Or" selector entry on the selector list + */ + public void addOr(OrSelector selector) { + appendSelector(selector); + } + + /** + * add a "Not" selector entry on the selector list + */ + public void addNot(NotSelector selector) { + appendSelector(selector); + } + + /** + * add a "None" selector entry on the selector list + */ + public void addNone(NoneSelector selector) { + appendSelector(selector); + } + + /** + * add a majority selector entry on the selector list + */ + public void addMajority(MajoritySelector selector) { + appendSelector(selector); + } + + /** + * add a selector date entry on the selector list + */ + public void addDateselect(DateSelector selector) { + appendSelector(selector); + } + + /** + * add a selector size entry on the selector list + */ + public void addSizeselect(SizeSelector selector) { + appendSelector(selector); + } + + /** + * add a selector filename entry on the selector list + */ + public void addFilenameselect(FilenameSelector selector) { + appendSelector(selector); + } + + /** + * add an extended selector entry on the selector list + */ + public void addExtendSelect(ExtendSelector selector) { + appendSelector(selector); + } + + /** + * add a contains selector entry on the selector list + */ + public void addContainsSelect(ContainsSelector selector) { + appendSelector(selector); + } + + /** + * add a present selector entry on the selector list + */ + public void addPresentSelect(PresentSelector selector) { + appendSelector(selector); + } + + /** + * add a depth selector entry on the selector list + */ + public void addDepthSelect(DepthSelector selector) { + appendSelector(selector); + } + + /** + * add a depends selector entry on the selector list + */ + public void addDependSelect(DependSelector selector) { + appendSelector(selector); + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java b/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java new file mode 100644 index 000000000..e7b505b44 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/ContainsSelector.java @@ -0,0 +1,197 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.io.BufferedReader; +import java.io.InputStreamReader; +import java.io.FileInputStream; +import java.io.IOException; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Parameter; +import org.apache.tools.ant.BuildException; + +/** + * Selector that filters files based on whether they contain a + * particular string. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class ContainsSelector extends BaseExtendSelector { + + private String contains = null; + private boolean casesensitive = true; + public final static String CONTAINS_KEY = "contains"; + public final static String CASE_KEY = "casesensitive"; + + + public ContainsSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer("{containsselector contains: "); + buf.append(contains); + buf.append(" casesensitive: "); + if (casesensitive) { + buf.append("true"); + } else { + buf.append("false"); + } + buf.append("}"); + return buf.toString(); + } + + /** + * The string to search for within a file. + * + * @param contains the string that a file must contain to be selected. + */ + public void setContains(String contains) { + this.contains = contains; + } + + /** + * Whether to ignore case in the string being searched. + * + * @param casesensitive whether to pay attention to case sensitivity + */ + public void setCasesensitive(boolean casesensitive) { + this.casesensitive = casesensitive; + } + + /** + * When using this as a dynamic selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param parameters the complete set of parameters for this selector + */ + public void setParameters(Parameter[] parameters) { + super.setParameters(parameters); + if (parameters != null) { + for (int i = 0; i < parameters.length; i++) { + String paramname = parameters[i].getName(); + if (CONTAINS_KEY.equalsIgnoreCase(paramname)) { + setContains(parameters[i].getValue()); + } + else if (CASE_KEY.equalsIgnoreCase(paramname)) { + setCasesensitive(Project.toBoolean( + parameters[i].getValue())); + } + else { + setError("Invalid parameter " + paramname); + } + } + } + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the pattern attribute has been set. + * + */ + public void verifySettings() { + if (contains == null) { + setError("The contains attribute is required"); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object the selector can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + + // throw BuildException on error + validate(); + + if (file.isDirectory()) { + return true; + } + + BufferedReader in = null; + try { + in = new BufferedReader(new InputStreamReader( + new FileInputStream(file))); + String teststr = in.readLine(); + while (teststr != null) { + if (teststr.indexOf(contains) > -1) { + return true; + } + teststr = in.readLine(); + } + return false; + } + catch (IOException ioe) { + throw new BuildException("Could not read file " + filename); + } + finally { + try { + in.close(); + } + catch (Exception e) { + throw new BuildException("Could not close file " + filename); + } + } + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/DateSelector.java b/src/main/org/apache/tools/ant/types/selectors/DateSelector.java new file mode 100644 index 000000000..d72e45893 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/DateSelector.java @@ -0,0 +1,250 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.Locale; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.ant.types.Parameter; + +/** + * Selector that chooses files based on their last modified date. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class DateSelector extends BaseExtendSelector { + + private long millis = -1; + private String dateTime = null; + private boolean includeDirs = false; + private int cmp = 0; + public final static String MILLIS_KEY = "millis"; + public final static String DATETIME_KEY = "datetime"; + public final static String CHECKDIRS_KEY = "checkdirs"; + public final static String WHEN_KEY = "when"; + + public DateSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer("{dateselector date: "); + buf.append(dateTime); + buf.append("compare: "); + if (cmp == 0) { + buf.append("before"); + } + else if (cmp == 1) { + buf.append("after"); + } else { + buf.append("equal"); + } + buf.append("}"); + return buf.toString(); + } + + /** + * For users that prefer to express time in milliseconds since 1970 + * + * @param millis the time to compare file's last modified date to, + * expressed in milliseconds + */ + public void setMillis(long millis) { + this.millis = millis; + } + + /** + * Sets the date. The user must supply it in MM/DD/YYYY HH:MM AM_PM + * format + * + * @param dateTime a string in MM/DD/YYYY HH:MM AM_PM format + */ + public void setDatetime(String dateTime) { + this.dateTime = dateTime; + if (dateTime != null) { + DateFormat df = DateFormat.getDateTimeInstance( + DateFormat.SHORT, + DateFormat.SHORT, + Locale.US); + try { + setMillis(df.parse(dateTime).getTime()); + if (millis < 0) { + setError("Date of " + dateTime + + " results in negative milliseconds value relative" + + " to epoch (January 1, 1970, 00:00:00 GMT)."); + } + } catch (ParseException pe) { + setError("Date of " + dateTime + + " Cannot be parsed correctly. It should be in" + + " MM/DD/YYYY HH:MM AM_PM format."); + } + } + } + + /** + * Should we be checking dates on directories? + * + * @param includeDirs whether to check the timestamp on directories + */ + public void setCheckdirs(boolean includeDirs) { + this.includeDirs = includeDirs; + } + + /** + * Sets the type of comparison to be done on the file's last modified + * date. + * + * @param cmp The comparison to perform, an EnumeratedAttribute + */ + public void setWhen(TimeComparisons cmp) { + this.cmp = cmp.getIndex(); + } + + /** + * When using this as a dynamic selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param parameters the complete set of parameters for this selector + */ + public void setParameters(Parameter[] parameters) { + super.setParameters(parameters); + if (parameters != null) { + for (int i = 0; i < parameters.length; i++) { + String paramname = parameters[i].getName(); + if (MILLIS_KEY.equalsIgnoreCase(paramname)) { + try { + setMillis(new Long(parameters[i].getValue() + ).longValue()); + } catch (NumberFormatException nfe) { + setError("Invalid millisecond setting " + + parameters[i].getValue()); + } + } + else if (DATETIME_KEY.equalsIgnoreCase(paramname)) { + setDatetime(parameters[i].getValue()); + } + else if (CHECKDIRS_KEY.equalsIgnoreCase(paramname)) { + setCheckdirs(Project.toBoolean(parameters[i].getValue())); + } + else if (WHEN_KEY.equalsIgnoreCase(paramname)) { + TimeComparisons cmp = new TimeComparisons(); + cmp.setValue(parameters[i].getValue()); + setWhen(cmp); + } + else { + setError("Invalid parameter " + paramname); + } + } + } + } + + /** + * This is a consistency check to ensure the selector's required + * values have been set. + */ + public void verifySettings() { + if (dateTime == null && millis < 0) { + setError("You must provide a datetime or the number of " + + "milliseconds."); + } + else if (millis < 0) { + setError("Date of " + dateTime + + " results in negative milliseconds" + + " value relative to epoch (January 1, 1970, 00:00:00 GMT)."); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object the selector can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + validate(); + if (file.isDirectory() && (includeDirs == false)) { + return true; + } + if (cmp == 0) { + return (file.lastModified() < millis); + } + else if (cmp == 1) { + return (file.lastModified() > millis); + } + else { + return (file.lastModified() == millis); + } + } + + /** + * Enumerated attribute with the values for time comparison. + * <p> + */ + public static class TimeComparisons extends EnumeratedAttribute { + public String[] getValues() { + return new String[] {"before", "after", "equal"}; + } + } + +} + + diff --git a/src/main/org/apache/tools/ant/types/selectors/DependSelector.java b/src/main/org/apache/tools/ant/types/selectors/DependSelector.java new file mode 100644 index 000000000..ceefdd7f9 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/DependSelector.java @@ -0,0 +1,186 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Mapper; +import org.apache.tools.ant.util.IdentityMapper; +import org.apache.tools.ant.util.FileNameMapper; +import org.apache.tools.ant.BuildException; + +/** + * Selector that filters files based on whether they are newer than + * a matching file in another directory tree. It can contain a mapper + * element, so isn't available as an ExtendSelector (since those + * parameters can't hold other elements). + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class DependSelector extends BaseSelector { + + private String targetdir = null; + private File targetbase = null; + private Mapper mapperElement = null; + private FileNameMapper map = null; + private int granularity = 0; + + public DependSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer("{dependselector targetdir: "); + buf.append(targetdir); + buf.append(" granularity: "); + buf.append(granularity); + if (map != null) { + buf.append(" mapper: "); + buf.append(map.toString()); + } + else if (mapperElement != null) { + buf.append(" mapper: "); + buf.append(mapperElement.toString()); + } + buf.append("}"); + return buf.toString(); + } + + /** + * The name of the file or directory which is checked for out-of-date + * files. + * + * @param targetdir the directory to scan looking for files. + */ + public void setTargetdir(String targetdir) { + this.targetdir = SelectorUtils.fixPath(targetdir); + targetbase = new File(this.targetdir); + } + + /** + * Sets the number of milliseconds leeway we will give before we consider + * a file out of date. + */ + public void setGranularity(int granularity) { + this.granularity = granularity; + } + + /** + * Defines the FileNameMapper to use (nested mapper element). + */ + public Mapper createMapper() throws BuildException { + if (mapperElement != null) { + throw new BuildException("Cannot define more than one mapper"); + } + mapperElement = new Mapper(project); + return mapperElement; + } + + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the dest attribute has been set and we have a mapper. + */ + public void verifySettings() { + if (targetdir == null) { + setError("The targetdir attribute is required."); + } + if (mapperElement == null) { + map = new IdentityMapper(); + } + else { + map = mapperElement.getImplementation(); + } + if (map == null) { + setError("Could not set <mapper> element."); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object the selector can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + + // throw BuildException on error + validate(); + + // Get File object for the target directory + File target = targetbase; + if (target == null) { + target = new File(basedir,targetdir); + } + + // Determine file whose out-of-dateness is to be checked + String[] destfiles = map.mapFileName(filename); + // Sanity check + if (destfiles.length != 1 || destfiles[0] == null) { + throw new BuildException("Invalid destination file results for " + + targetdir + " with filename " + filename); + } + String destname = destfiles[0]; + File destfile = new File(target,destname); + + return SelectorUtils.isOutOfDate(file, destfile, granularity); + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java b/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java new file mode 100644 index 000000000..1b2002216 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/DepthSelector.java @@ -0,0 +1,209 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.util.StringTokenizer; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Parameter; +import org.apache.tools.ant.BuildException; + +/** + * Selector that filters files based on the how deep in the directory + * tree they are. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class DepthSelector extends BaseExtendSelector { + + public int min = -1; + public int max = -1; + public final static String MIN_KEY = "min"; + public final static String MAX_KEY = "max"; + + public DepthSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer("{depthselector min: "); + buf.append(min); + buf.append(" max: "); + buf.append(max); + buf.append("}"); + return buf.toString(); + } + + /** + * The minimum depth below the basedir before a file is selected. + * + * @param min minimum directory levels below basedir to go + */ + public void setMin(int min) { + this.min = min; + } + + /** + * The minimum depth below the basedir before a file is selected. + * + * @param min maximum directory levels below basedir to go + */ + public void setMax(int max) { + this.max = max; + } + + /** + * When using this as a dynamic selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param parameters the complete set of parameters for this selector + */ + public void setParameters(Parameter[] parameters) { + super.setParameters(parameters); + if (parameters != null) { + for (int i = 0; i < parameters.length; i++) { + String paramname = parameters[i].getName(); + if (MIN_KEY.equalsIgnoreCase(paramname)) { + try { + setMin(Integer.parseInt(parameters[i].getValue())); + } + catch (NumberFormatException nfe1) { + setError("Invalid minimum value " + + parameters[i].getValue()); + } + } + else if (MAX_KEY.equalsIgnoreCase(paramname)) { + try { + setMax(Integer.parseInt(parameters[i].getValue())); + } + catch (NumberFormatException nfe1) { + setError("Invalid maximum value " + + parameters[i].getValue()); + } + } + else { + setError("Invalid parameter " + paramname); + } + } + } + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the max depth is not lower than the min depth. + */ + public void verifySettings() { + if (min < 0 && max < 0) { + setError("You must set at least one of the min or the " + + "max levels."); + } + if (max < min) { + setError("The maximum depth is lower than the minimum."); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. Most of the work + * for this selector is offloaded into SelectorUtils, a static class + * that provides the same services for both FilenameSelector and + * DirectoryScanner. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object the selector can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + + // throw BuildException on error + validate(); + + int depth = -1; + // If you felt daring, you could cache the basedir absolute path + String abs_base = basedir.getAbsolutePath(); + String abs_file = file.getAbsolutePath(); + StringTokenizer tok_base = new StringTokenizer(abs_base, File.separator); + StringTokenizer tok_file = new StringTokenizer(abs_file, File.separator); + while (tok_file.hasMoreTokens()) { + String filetoken = tok_file.nextToken(); + if (tok_base.hasMoreTokens()) { + String basetoken = tok_base.nextToken(); + // Sanity check. Ditch it if you want faster performance + if (!basetoken.equals(filetoken)) { + throw new BuildException("File " + filename + + " does not appear within " + abs_base + "directory"); + } + } + else { + depth += 1; + if (max > -1 && depth > max) { + return false; + } + } + } + if (tok_base.hasMoreTokens()) { + throw new BuildException("File " + filename + + " is outside of " + abs_base + "directory tree"); + } + if (min > -1 && depth < min) { + return false; + } + return true; + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java b/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java new file mode 100644 index 000000000..25d968c9b --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/ExtendFileSelector.java @@ -0,0 +1,78 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; + +import org.apache.tools.ant.types.Parameterizable; + +/** + * This is the interface to be used by all dynamic selectors, those that are + * called through the <extendselect> tag. It is the amalgamation of two + * interfaces, the FileSelector and the Paramterizable interface. Note that + * you will almost certainly want the default behaviour for handling + * Parameters, so you probably want to use the BaseExtendSelector class + * as the base class for your dynamic selector rather than implementing + * this interface from scratch. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public interface ExtendFileSelector extends FileSelector, Parameterizable { + + // No further methods necessary. This is just an amalgamation of two other + // interfaces. +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java b/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java new file mode 100644 index 000000000..9925fe971 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/ExtendSelector.java @@ -0,0 +1,213 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.DataType; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Parameter; +import org.apache.tools.ant.types.Reference; + +/** + * Selector that selects files by forwarding the request on to other classes. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class ExtendSelector extends BaseSelector { + + private String classname = null; + private ExtendFileSelector dynselector = null; + private Vector paramVec = new Vector(); + private Path classpath = null; + + /** + * Default constructor. + */ + public ExtendSelector() { + } + + /** + * Sets the classname of the dynamic selector. + * + * @param classname is the class which implements this selector + */ + public void setClassname(String classname) { + this.classname = classname; + } + + /** + * Instantiates the identified dynamic selector class. + */ + public void selectorCreate() { + if (classname != null && classname.length() > 0) { + try { + dynselector = (ExtendFileSelector) + Class.forName(classname).newInstance(); + } + catch (ClassNotFoundException cnfexcept) { + setError("Selector " + classname + + " not initialized, no such class"); + } + catch (InstantiationException iexcept) { + setError("Selector " + classname + + " not initialized, could not create class"); + } + catch (IllegalAccessException iaexcept) { + setError("Selector " + classname + + " not initialized, class not accessible"); + } + } else { + setError("There is no classname specified"); + } + } + + /** + * Create new parameters to pass to dynamic selector. + * + * @param p The new Parameter object + */ + public void addParam(Parameter p) { + paramVec.addElement(p); + } + + + /** + * Set the classpath to load the classname specified using an attribute. + */ + public final void setClasspath(Path classpath) { + if (isReference()) { + throw tooManyAttributes(); + } + if (this.classpath == null) { + this.classpath = classpath; + } else { + this.classpath.append(classpath); + } + } + + /** + * Specify the classpath to use to load the Selector (nested element). + */ + public final Path createClasspath() { + if (isReference()) { + throw noChildrenAllowed(); + } + if (this.classpath == null) { + this.classpath = new Path(getProject()); + } + return this.classpath.createPath(); + } + + /** + * Get the classpath + */ + public final Path getClasspath() { + return classpath; + } + + /** + * Set the classpath to use for loading a dynamic selector by using + * a reference. + */ + public void setClasspathref(Reference r) { + if (isReference()) { + throw tooManyAttributes(); + } + createClasspath().setRefid(r); + } + + /** + * These are errors specific to ExtendSelector only. If there are + * errors in the dynamic selector, it should throw a BuildException + * when isSelected() is called. + */ + public void verifySettings() { + if (classname == null || classname.length() < 1) { + setError("The classname attribute is required"); + } + else if (dynselector == null) { + setError("Internal Error: The dynamic selector is not set"); + } + } + + + /** + * Allows the dynamic selector to choose whether to select a file. This + * is also where the Parameters are passed to the dynamic selector, + * since we know we must have them all by now. And since we must know + * both classpath and classname, creating the class is deferred to here + * as well. + */ + public boolean isSelected(File basedir, String filename, File file) + throws BuildException { + if (dynselector == null) { + selectorCreate(); + } + validate(); + if (paramVec.size() > 0) { + Parameter[] paramArray = new Parameter[paramVec.size()]; + paramVec.copyInto(paramArray); + // We know that dynselector must be non-null if no error message + dynselector.setParameters(paramArray); + } + return dynselector.isSelected(basedir,filename,file); + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/FileSelector.java b/src/main/org/apache/tools/ant/types/selectors/FileSelector.java new file mode 100644 index 000000000..f877ff7bc --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/FileSelector.java @@ -0,0 +1,85 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; + +import org.apache.tools.ant.BuildException; + +/** + * This is the interface to be used by all selectors. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public interface FileSelector { + + /** + * Method that each selector will implement to create their + * selection behaviour. If there is a problem with the setup + * of a selector, it can throw a BuildException to indicate + * the problem. + * + * @param basedir A java.io.File object for the base directory + * @param filename The name of the file to check + * @param file A File object for this filename + * @return whether the file should be selected or not + * @exception BuildException if the selector was not configured correctly + */ + public boolean isSelected(File basedir, String filename, File file) + throws BuildException; + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java b/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java new file mode 100644 index 000000000..1706790bb --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/FilenameSelector.java @@ -0,0 +1,195 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Parameter; + +/** + * Selector that filters files based on the filename. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class FilenameSelector extends BaseExtendSelector { + + private String pattern = null; + private boolean casesensitive = true; + private boolean negated = false; + public final static String NAME_KEY = "name"; + public final static String CASE_KEY = "casesensitive"; + public final static String NEGATE_KEY = "negate"; + + public FilenameSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer("{filenameselector name: "); + buf.append(pattern); + buf.append(" negate: "); + if (negated) { + buf.append("true"); + } else { + buf.append("false"); + } + buf.append(" casesensitive: "); + if (casesensitive) { + buf.append("true"); + } else { + buf.append("false"); + } + buf.append("}"); + return buf.toString(); + } + + /** + * The name of the file, or the pattern for the name, that + * should be used for selection. + * + * @param pattern the file pattern that any filename must match + * against in order to be selected. + */ + public void setName(String pattern) { + pattern = pattern.replace('/',File.separatorChar).replace('\\', + File.separatorChar); + if (pattern.endsWith(File.separator)) { + pattern += "**"; + } + this.pattern = pattern; + } + + /** + * Whether to ignore case when checking filenames. + * + * @param casesensitive whether to pay attention to case sensitivity + */ + public void setCasesensitive(boolean casesensitive) { + this.casesensitive = casesensitive; + } + + /** + * You can optionally reverse the selection of this selector, + * thereby emulating an <exclude> tag, by setting the attribute + * negate to true. This is identical to surrounding the selector + * with <not></not>. + * + * @param negated whether to negate this selection + */ + public void setNegate(boolean negated) { + this.negated = negated; + } + + /** + * When using this as a dynamic selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param parameters the complete set of parameters for this selector + */ + public void setParameters(Parameter[] parameters) { + super.setParameters(parameters); + if (parameters != null) { + for (int i = 0; i < parameters.length; i++) { + String paramname = parameters[i].getName(); + if (NAME_KEY.equalsIgnoreCase(paramname)) { + setName(parameters[i].getValue()); + } + else if (CASE_KEY.equalsIgnoreCase(paramname)) { + setCasesensitive(Project.toBoolean( + parameters[i].getValue())); + } + else if (NEGATE_KEY.equalsIgnoreCase(paramname)) { + setNegate(Project.toBoolean(parameters[i].getValue())); + } + else { + setError("Invalid parameter " + paramname); + } + } + } + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the name attribute has been set. + * + */ + public void verifySettings() { + if (pattern == null) { + setError("The name attribute is required"); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. Most of the work + * for this selector is offloaded into SelectorUtils, a static class + * that provides the same services for both FilenameSelector and + * DirectoryScanner. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object the selector can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + validate(); + + return SelectorUtils.matchPath(pattern,filename, + casesensitive); + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java b/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java new file mode 100644 index 000000000..1d4364406 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/MajoritySelector.java @@ -0,0 +1,135 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.util.Enumeration; + +/** + * This selector is here just to shake up your thinking a bit. Don't get + * too caught up in boolean, there are other ways you can evaluate a + * collection of selectors. This one takes a vote of the selectors it + * contains, and majority wins. You could also have an "all-but-one" + * selector, a "weighted-average" selector, and so on. These are left + * as exercises for the reader (as are the usecases where this would + * be necessary). + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class MajoritySelector extends BaseSelectorContainer { + + private boolean allowtie = true; + + /** + * Default constructor. + */ + public MajoritySelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + if (hasSelectors()) { + buf.append("{majorityselect: "); + buf.append(super.toString()); + buf.append("}"); + } + return buf.toString(); + } + + public void setAllowtie(boolean tiebreaker) { + allowtie = tiebreaker; + } + + /** + * Returns true (the file is selected) if most of the other selectors + * agree. In case of a tie, go by the allowtie setting. That defaults + * to true, meaning in case of a tie, the file is selected. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object for the filename that the selector + * can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + validate(); + int yesvotes = 0; + int novotes = 0; + Enumeration e = selectorElements(); + boolean result; + + while(e.hasMoreElements()) { + result = ((FileSelector)e.nextElement()).isSelected(basedir, + filename,file); + if (result) { + yesvotes = yesvotes + 1; + } + else { + novotes = novotes + 1; + } + } + if (yesvotes > novotes) + { + return true; + } + else if (novotes > yesvotes) { + return false; + } + // At this point, we know we have a tie. + return allowtie; + } +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java b/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java new file mode 100644 index 000000000..a07c76fb3 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/NoneSelector.java @@ -0,0 +1,112 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.util.Enumeration; + +/** + * This selector has a collection of other selectors. All of those selectors + * must refuse to select a file before the file is considered selected by + * this selector. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class NoneSelector extends BaseSelectorContainer { + + /** + * Default constructor. + */ + public NoneSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + if (hasSelectors()) { + buf.append("{noneselect: "); + buf.append(super.toString()); + buf.append("}"); + } + return buf.toString(); + } + + /** + * Returns true (the file is selected) only if all other selectors + * agree that the file should not be selected. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object for the filename that the selector + * can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + validate(); + Enumeration e = selectorElements(); + boolean result; + + while(e.hasMoreElements()) { + result = ((FileSelector)e.nextElement()).isSelected(basedir, + filename,file); + if (result) { + return false; + } + } + return true; + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/NotSelector.java b/src/main/org/apache/tools/ant/types/selectors/NotSelector.java new file mode 100644 index 000000000..7a16930e0 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/NotSelector.java @@ -0,0 +1,99 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.util.Enumeration; + +/** + * This selector has one other selectors whose meaning it inverts. It + * actually relies on NoneSelector for its implementation of the + * isSelected() method, but it adds a check to ensure there is only one + * other selector contained within. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class NotSelector extends NoneSelector { + + /** + * Default constructor. + */ + public NotSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + if (hasSelectors()) { + buf.append("{notselect: "); + buf.append(super.toString()); + buf.append("}"); + } + return buf.toString(); + } + + /** + * Makes sure that there is only one entry, sets an error message if + * not. + */ + public void verifySettings() { + if (selectorCount() != 1) { + setError("One and only one selector is allowed within the " + + "<not> tag"); + } + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/OrSelector.java b/src/main/org/apache/tools/ant/types/selectors/OrSelector.java new file mode 100644 index 000000000..324a33d55 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/OrSelector.java @@ -0,0 +1,112 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.util.Enumeration; + +/** + * This selector has a collection of other selectors, any of which have to + * select a file in order for this selector to select it. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class OrSelector extends BaseSelectorContainer { + + /** + * Default constructor. + */ + public OrSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer(); + if (hasSelectors()) { + buf.append("{orselect: "); + buf.append(super.toString()); + buf.append("}"); + } + return buf.toString(); + } + + /** + * Returns true (the file is selected) if any of the other selectors + * agree that the file should be selected. + * + * @param basedir the base directory the scan is being done from + * @param filename the name of the file to check + * @param file a java.io.File object for the filename that the selector + * can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + validate(); + Enumeration e = selectorElements(); + boolean result; + + // First, check that all elements are correctly configured + while(e.hasMoreElements()) { + result = ((FileSelector)e.nextElement()).isSelected(basedir, + filename,file); + if (result) { + return true; + } + } + return false; + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java b/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java new file mode 100644 index 000000000..9efab0f0a --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/PresentSelector.java @@ -0,0 +1,208 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.Mapper; +import org.apache.tools.ant.util.IdentityMapper; +import org.apache.tools.ant.util.FileNameMapper; +import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.ant.BuildException; + +/** + * Selector that filters files based on whether they appear in another + * directory tree. It can contain a mapper element, so isn't available + * as an ExtendSelector (since those parameters can't hold other + * elements). + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class PresentSelector extends BaseSelector { + + private String targetdir = null; + private File targetbase = null; + private Mapper mapperElement = null; + private FileNameMapper map = null; + private boolean destmustexist = true; + + public PresentSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer("{presentselector targetdir: "); + buf.append(targetdir); + buf.append(" present: "); + if (destmustexist) { + buf.append("both"); + } else { + buf.append("srconly"); + } + if (map != null) { + buf.append(map.toString()); + } + else if (mapperElement != null) { + buf.append(mapperElement.toString()); + } + buf.append("}"); + return buf.toString(); + } + + /** + * The name of the file or directory which is checked for matching + * files. + * + * @param targetdir the directory to scan looking for matching files. + */ + public void setTargetdir(String targetdir) { + this.targetdir = SelectorUtils.fixPath(targetdir); + targetbase = new File(this.targetdir); + } + + /** + * Defines the FileNameMapper to use (nested mapper element). + */ + public Mapper createMapper() throws BuildException { + if (mapperElement != null) { + throw new BuildException("Cannot define more than one mapper"); + } + mapperElement = new Mapper(project); + return mapperElement; + } + + + /** + * This sets whether to select a file if its dest file is present. + * It could be a <code>negate</code> boolean, but by doing things + * this way, we get some documentation on how the system works. + * A user looking at the documentation should clearly understand + * that the ONLY files whose presence is being tested are those + * that already exist in the source directory, hence the lack of + * a <code>destonly</code> option. + * + * @param fp An attribute set to either <code>srconly</code or + * <code>both</code>. + */ + public void setPresent(FilePresence fp) { + if (fp.getIndex() == 0) { + destmustexist = false; + } + } + + /** + * Checks to make sure all settings are kosher. In this case, it + * means that the targetdir attribute has been set and we have a mapper. + */ + public void verifySettings() { + if (targetdir == null) { + setError("The targetdir attribute is required."); + } + if (mapperElement == null) { + map = new IdentityMapper(); + } + else { + map = mapperElement.getImplementation(); + } + if (map == null) { + setError("Could not set <mapper> element."); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir the base directory the scan is being done from + * @param filename is the name of the file to check + * @param file is a java.io.File object the selector can use + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + + // throw BuildException on error + validate(); + + // Get File object for the target directory + File target = targetbase; + if (target == null) { + target = new File(basedir,targetdir); + } + + // Determine file whose existence is to be checked + String[] destfiles = map.mapFileName(filename); + // Sanity check + if (destfiles.length != 1 || destfiles[0] == null) { + throw new BuildException("Invalid destination file results for " + + targetdir + " with filename " + filename); + } + String destname = destfiles[0]; + File destfile = new File(target,destname); + return destfile.exists() == destmustexist; + } + + /** + * Enumerated attribute with the values for indicating where a file's + * presence is allowed and required. + */ + public static class FilePresence extends EnumeratedAttribute { + public String[] getValues() { + return new String[] {"srconly", "both"}; + } + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java b/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java new file mode 100644 index 000000000..819e88fa9 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/SelectorContainer.java @@ -0,0 +1,178 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import org.apache.tools.ant.Project; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.types.Reference; + +import java.io.File; +import java.util.Enumeration; +import java.util.Stack; +import java.util.Vector; + +/** + * This is the base class for selectors that can contain other selectors. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public interface SelectorContainer { + + /** + * Indicates whether there are any selectors here. + * + * @return whether any selectors are in this container + */ + public boolean hasSelectors(); + + /** + * Gives the count of the number of selectors in this container + * + * @return the number of selectors in this container + */ + public int selectorCount(); + + /** + * Returns the set of selectors as an array. + * + * @return an array of selectors in this container + */ + public FileSelector[] getSelectors(Project p); + + /** + * Returns an enumerator for accessing the set of selectors. + * + * @return an enumerator that goes through each of the selectors + */ + public Enumeration selectorElements(); + + /** + * Add a new selector into this container. + * + * @param selector the new selector to add + * @return the selector that was added + */ + public void appendSelector(FileSelector selector); + + /* Methods below all implement the static selectors */ + + /** + * add an "And" selector entry on the selector list + */ + public void addAnd(AndSelector selector); + + /** + * add an "Or" selector entry on the selector list + */ + public void addOr(OrSelector selector); + + /** + * add a "Not" selector entry on the selector list + */ + public void addNot(NotSelector selector); + + /** + * add a "None" selector entry on the selector list + */ + public void addNone(NoneSelector selector); + + /** + * add a majority selector entry on the selector list + */ + public void addMajority(MajoritySelector selector); + + /** + * add a selector date entry on the selector list + */ + public void addDateselect(DateSelector selector); + + /** + * add a selector size entry on the selector list + */ + public void addSizeselect(SizeSelector selector); + + /** + * add a selector filename entry on the selector list + */ + public void addFilenameselect(FilenameSelector selector); + + /** + * add an extended selector entry on the selector list + */ + public void addExtendSelect(ExtendSelector selector); + + /** + * add a contains selector entry on the selector list + */ + public void addContainsSelect(ContainsSelector selector); + + /** + * add a present selector entry on the selector list + */ + public void addPresentSelect(PresentSelector selector); + + /** + * add a depth selector entry on the selector list + */ + public void addDepthSelect(DepthSelector selector); + + /** + * add a depends selector entry on the selector list + */ + public void addDependSelect(DependSelector selector); + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java b/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java new file mode 100644 index 000000000..7d6786ed2 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/SelectorScanner.java @@ -0,0 +1,86 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ +package org.apache.tools.ant.types.selectors; + +/** + * An interface used to describe the actions required by any type of + * directory scanner that supports Selecters. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public interface SelectorScanner { + /** + * Sets the selectors the scanner should use. + * + * @param selectors the list of selectors + */ + void setSelectors(FileSelector[] selectors); + + /** + * Directories which were selected out of a scan. + * + * @param selectors list selector objects + */ + public String[] getDeselectedDirectories(); + + /** + * Files which were selected out of a scan. + * + * @param selectors list selector objects + */ + public String[] getDeselectedFiles(); + + +} diff --git a/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java b/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java new file mode 100644 index 000000000..5c678fb26 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/SelectorUtils.java @@ -0,0 +1,564 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.tools.ant.BuildException; + +/** + * <p>This is a utility class used by selectors and DirectoryScanner. The + * functionality more properly belongs just to selectors, but unfortunately + * DirectoryScanner exposed these as protected methods. Thus we have to + * support any subclasses of DirectoryScanner that may access these methods. + * </p> + * <p>This is a Singleton.</p> + * + * @author Arnout J. Kuiper + * <a href="mailto:ajkuiper@wxs.nl">ajkuiper@wxs.nl</a> + * @author <a href="mailto:umagesh@rediffmail.com">Magesh Umasankar</a> + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public final class SelectorUtils { + + private static SelectorUtils instance = new SelectorUtils(); + + /** + * Private Constructor + */ + private SelectorUtils() { + } + + /** + * Retrieves the instance of the Singleton. + */ + public static SelectorUtils getInstance() { + return instance; + } + + /** + * Tests whether or not a given path matches the start of a given + * 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. For example, <code>pattern=**\a</code> + * and <code>str=b</code> will yield <code>true</code>. + * + * @param pattern The pattern to match against. Must not be + * <code>null</code>. + * @param str The path to match, as a String. Must not be + * <code>null</code>. + * + * @return whether or not a given path matches the start of a given + * pattern up to the first "**". + */ + public static boolean matchPatternStart(String pattern, String str) { + return matchPatternStart(pattern, str, true); + } + /** + * Tests whether or not a given path matches the start of a given + * 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. For example, <code>pattern=**\a</code> + * and <code>str=b</code> will yield <code>true</code>. + * + * @param pattern The pattern to match against. Must not be + * <code>null</code>. + * @param str The path to match, as a String. Must not be + * <code>null</code>. + * @param isCaseSensitive Whether or not matching should be performed + * case sensitively. + * + * @return whether or not a given path matches the start of a given + * pattern up to the first "**". + */ + public static boolean matchPatternStart(String pattern, String str, + 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; + } + + Vector patDirs = tokenizePath (pattern); + Vector strDirs = tokenizePath (str); + + 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.elementAt(patIdxStart); + if (patDir.equals("**")) { + break; + } + if (!match(patDir,(String)strDirs.elementAt(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; + } + } + + /** + * Tests whether or not a given path matches a given pattern. + * + * @param pattern The pattern to match against. Must not be + * <code>null</code>. + * @param str The path to match, as a String. Must not be + * <code>null</code>. + * + * @return <code>true</code> if the pattern matches against the string, + * or <code>false</code> otherwise. + */ + public static boolean matchPath(String pattern, String str) { + return matchPath(pattern, str, true); + } + + /** + * Tests whether or not a given path matches a given pattern. + * + * @param pattern The pattern to match against. Must not be + * <code>null</code>. + * @param str The path to match, as a String. Must not be + * <code>null</code>. + * @param isCaseSensitive Whether or not matching should be performed + * case sensitively. + * + * @return <code>true</code> if the pattern matches against the string, + * or <code>false</code> otherwise. + */ + public static boolean matchPath(String pattern, String str, + 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; + } + + Vector patDirs = tokenizePath (pattern); + Vector strDirs = tokenizePath (str); + + 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.elementAt(patIdxStart); + if (patDir.equals("**")) { + break; + } + if (!match(patDir,(String)strDirs.elementAt(strIdxStart), + isCaseSensitive)) { + return false; + } + patIdxStart++; + strIdxStart++; + } + if (strIdxStart > strIdxEnd) { + // String is exhausted + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!patDirs.elementAt(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.elementAt(patIdxEnd); + if (patDir.equals("**")) { + break; + } + if (!match(patDir,(String)strDirs.elementAt(strIdxEnd), + isCaseSensitive)) { + return false; + } + patIdxEnd--; + strIdxEnd--; + } + if (strIdxStart > strIdxEnd) { + // String is exhausted + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (!patDirs.elementAt(i).equals("**")) { + return false; + } + } + return true; + } + + while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { + int patIdxTmp = -1; + for (int i = patIdxStart+1; i <= patIdxEnd; i++) { + if (patDirs.elementAt(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.elementAt(patIdxStart+j+1); + String subStr = (String)strDirs.elementAt(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.elementAt(i).equals("**")) { + return false; + } + } + + return true; + } + + /** + * Tests whether or not a string matches against a pattern. + * The pattern may contain two special characters:<br> + * '*' means zero or more characters<br> + * '?' means one and only one character + * + * @param pattern The pattern to match against. + * Must not be <code>null</code>. + * @param str The string which must be matched against the pattern. + * Must not be <code>null</code>. + * + * @return <code>true</code> if the string matches against the pattern, + * or <code>false</code> otherwise. + */ + public static boolean match(String pattern, String str) { + return match(pattern, str, true); + } + + /** + * Tests whether or not a string matches against a pattern. + * The pattern may contain two special characters:<br> + * '*' means zero or more characters<br> + * '?' means one and only one character + * + * @param pattern The pattern to match against. + * Must not be <code>null</code>. + * @param str The string which must be matched against the pattern. + * Must not be <code>null</code>. + * @param isCaseSensitive Whether or not matching should be performed + * case sensitively. + * + * + * @return <code>true</code> if the string matches against the pattern, + * or <code>false</code> otherwise. + */ + public static boolean match(String pattern, String str, + 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; + } + + /** + * Breaks a path up into a Vector of path elements, tokenizing on + * <code>File.separator</code>. + * + * @param path Path to tokenize. Must not be <code>null</code>. + * + * @return a Vector of path elements from the tokenized path + */ + public static Vector tokenizePath (String path) { + Vector ret = new Vector(); + StringTokenizer st = new StringTokenizer(path,File.separator); + while (st.hasMoreTokens()) { + ret.addElement(st.nextToken()); + } + return ret; + } + + /** + * Helper method which corrects paths to use forward slashes. + * + * @param pattern the path pattern which needs correcting + * @return corrected pattern + */ + public static String fixPath(String pattern) { + return pattern.replace('/',File.separatorChar).replace('\\', + File.separatorChar); + } + + /** + * Returns dependency information on these two files. If src has been + * modified later than target, it returns true. If target doesn't exist, + * it likewise returns true. Otherwise, target is newer than src and + * is not out of date, thus the method returns false. It also returns + * false if the src file doesn't even exist, since how could the + * target then be out of date. + * + * @param src the original file + * @param target the file being compared against + * @param granularity the amount in seconds of slack we will give in + * determining out of dateness + * @return whether the target is out of date + */ + public static boolean isOutOfDate(File src, File target, int granularity) { + if (!src.exists()) { + return false; + } + if (!target.exists()) { + return true; + } + if ((src.lastModified() - granularity) > target.lastModified()) { + return true; + } + return false; + } + +} + diff --git a/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java b/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java new file mode 100644 index 000000000..3ed87a44b --- /dev/null +++ b/src/main/org/apache/tools/ant/types/selectors/SizeSelector.java @@ -0,0 +1,313 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2002 The Apache Software Foundation. All rights + * reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. The end-user documentation included with the redistribution, if + * any, must include the following acknowlegement: + * "This product includes software developed by the + * Apache Software Foundation (http://www.apache.org/)." + * Alternately, this acknowlegement may appear in the software itself, + * if and wherever such third-party acknowlegements normally appear. + * + * 4. The names "The Jakarta Project", "Ant", and "Apache Software + * Foundation" must not be used to endorse or promote products derived + * from this software without prior written permission. For written + * permission, please contact apache@apache.org. + * + * 5. Products derived from this software may not be called "Apache" + * nor may "Apache" appear in their names without prior written + * permission of the Apache Group. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * <http://www.apache.org/>. + */ + +package org.apache.tools.ant.types.selectors; + +import java.io.File; + +import org.apache.tools.ant.types.EnumeratedAttribute; +import org.apache.tools.ant.types.Parameter; +import org.apache.tools.ant.BuildException; + +/** + * Selector that filters files based on their size. + * + * @author <a href="mailto:bruce@callenish.com">Bruce Atherton</a> + * @since 1.5 + */ +public class SizeSelector extends BaseExtendSelector { + + private long size = -1; + private long multiplier = 1; + private long sizelimit = -1; + private int cmp = 0; + public final static String SIZE_KEY = "millis"; + public final static String UNITS_KEY = "datetime"; + public final static String WHEN_KEY = "when"; + + public SizeSelector() { + } + + public String toString() { + StringBuffer buf = new StringBuffer("{sizeselector size: "); + buf.append(sizelimit); + buf.append("compare: "); + if (cmp == 0) { + buf.append("less"); + } + else if (cmp == 1) { + buf.append("more"); + } else { + buf.append("equal"); + } + buf.append("}"); + return buf.toString(); + } + + /** + * A size selector needs to know what size to base its selecting on. + * This will be further modified by the multiplier to get an + * actual size limit. + * + * @param size the size to select against expressed in units + */ + public void setSize(long size) { + this.size = size; + if ((multiplier != 0) && (size > -1)) { + sizelimit = size * multiplier; + } + } + + /** + * Sets the units to use for the comparison. This is a little + * complicated because common usage has created standards that + * play havoc with capitalization rules. Thus, some people will + * use "K" for indicating 1000's, when the SI standard calls for + * "k". Others have tried to introduce "K" as a multiple of 1024, + * but that falls down when you reach "M", since "m" is already + * defined as 0.001. + * <p> + * To get around this complexity, a number of standards bodies + * have proposed the 2^10 standard, and at least one has adopted + * it. But we are still left with a populace that isn't clear on + * how capitalization should work. + * <p> + * We therefore ignore capitalization as much as possible. + * Completely mixed case is not possible, but all upper and lower + * forms are accepted for all long and short forms. Since we have + * no need to work with the 0.001 case, this practice works here. + * <p> + * This function translates all the long and short forms that a + * unit prefix can occur in and translates them into a single + * multiplier. + * + * @param units The units to compare the size to, using an + * EnumeratedAttribute + */ + public void setUnits(ByteUnits units) { + int i = units.getIndex(); + multiplier = 0; + if ((i > -1) && (i < 4)) { + multiplier = 1000; + } + else if ((i > 3) && (i < 9)) { + multiplier = 1024; + } + else if ((i > 8) && (i < 13)) { + multiplier = 1000000; + } + else if ((i > 12) && (i < 18)) { + multiplier = 1048576; + } + else if ((i > 17) && (i < 22)) { + multiplier = 1000000000L; + } + else if ((i > 21) && (i < 27)) { + multiplier = 1073741824L; + } + else if ((i > 26) && (i < 31)) { + multiplier = 1000000000000L; + } + else if ((i > 30) && (i < 36)) { + multiplier = 1099511627776L; + } + if ((multiplier > 0) && (size > -1)) { + sizelimit = size * multiplier; + } + } + + /** + * This specifies when the file should be selected, whether it be + * when the file matches a particular size, when it is smaller, + * or whether it is larger. + * + * @param cmp The comparison to perform, an EnumeratedAttribute + */ + public void setWhen(SizeComparisons cmp) { + this.cmp = cmp.getIndex(); + } + + /** + * When using this as a dynamic selector, this method will be called. + * It translates each parameter into the appropriate setXXX() call. + * + * @param parameters the complete set of parameters for this selector + */ + public void setParameters(Parameter[] parameters) { + super.setParameters(parameters); + if (parameters != null) { + for (int i = 0; i < parameters.length; i++) { + String paramname = parameters[i].getName(); + if (SIZE_KEY.equalsIgnoreCase(paramname)) { + try { + setSize(new Long(parameters[i].getValue() + ).longValue()); + } catch (NumberFormatException nfe) { + setError("Invalid size setting " + + parameters[i].getValue()); + } + } + else if (UNITS_KEY.equalsIgnoreCase(paramname)) { + ByteUnits units = new ByteUnits(); + units.setValue(parameters[i].getValue()); + setUnits(units); + } + else if (WHEN_KEY.equalsIgnoreCase(paramname)) { + SizeComparisons cmp = new SizeComparisons(); + cmp.setValue(parameters[i].getValue()); + setWhen(cmp); + } + else { + setError("Invalid parameter " + paramname); + } + } + } + } + + /** + * <p>Checks to make sure all settings are kosher. In this case, it + * means that the size attribute has been set (to a positive value), + * that the multiplier has a valid setting, and that the size limit + * is valid. Since the latter is a calculated value, this can only + * fail due to a programming error. + * </p> + * <p>If a problem is detected, the setError() method is called. + * </p> + */ + public void verifySettings() { + if (size < 0) { + setError("The size attribute is required, and must be positive"); + } + else if (multiplier < 1) { + setError("Invalid Units supplied, must be K,Ki,M,Mi,G,Gi,T,or Ti"); + } + else if (sizelimit < 0) { + setError("Internal error: Code is not setting sizelimit correctly"); + } + } + + /** + * The heart of the matter. This is where the selector gets to decide + * on the inclusion of a file in a particular fileset. + * + * @param basedir A java.io.File object for the base directory + * @param filename The name of the file to check + * @param file A File object for this filename + * @return whether the file should be selected or not + */ + public boolean isSelected(File basedir, String filename, File file) { + + // throw BuildException on error + validate(); + + // Directory size never selected for + if (file.isDirectory()) { + return true; + } + if (cmp == 0) { + return (file.length() < sizelimit); + } + else if (cmp == 1) { + return (file.length() > sizelimit); + } + else { + return (file.length() == sizelimit); + } + } + + + + /** + * Enumerated attribute with the values for units. + * <p> + * This treats the standard SI units as representing powers of ten, + * as they should. If you want the powers of 2 that approximate + * the SI units, use the first two characters followed by a + * <code>bi</code>. So 1024 (2^10) becomes <code>kibi</code>, + * 1048576 (2^20) becomes <code>mebi</code>, 1073741824 (2^30) + * becomes <code>gibi</code>, and so on. The symbols are also + * accepted, and these are the first letter capitalized followed + * by an <code>i</code>. <code>Ki</code>, <code>Mi</code>, + * <code>Gi</code>, and so on. Capitalization variations on these + * are also accepted. + * <p> + * This binary prefix system is approved by the IEC and appears on + * its way for approval by other agencies, but it is not an SI + * standard. It disambiguates things for us, though. + */ + public static class ByteUnits extends EnumeratedAttribute { + public String[] getValues() { + return new String[] {"K", "k", "kilo", "KILO", + "Ki", "KI", "ki", "kibi", "KIBI", + "M", "m", "mega", "MEGA", + "Mi", "MI", "mi", "mebi", "MEBI", + "G", "g", "giga", "GIGA", + "Gi", "GI", "gi", "gibi", "GIBI", + "T", "t", "tera", "TERA", + /* You wish! */ "Ti", "TI", "ti", "tebi", "TEBI" + }; + } + } + + /** + * Enumerated attribute with the values for size comparison. + */ + public static class SizeComparisons extends EnumeratedAttribute { + public String[] getValues() { + return new String[] {"less", "more", "equal"}; + } + } + +} + |