From 362903a2bd195f64f594d4b3f333900d67a3c7bc Mon Sep 17 00:00:00 2001 From: Conor MacNeill Date: Wed, 23 May 2001 13:42:32 +0000 Subject: [PATCH] Lots of mutant changes git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269043 13f79535-47bb-0310-9956-ffa450edef68 --- proposal/mutant/build.xml | 3 +- .../ant/component/core/FileConverter.java | 5 +- .../apache/ant/component/core/Property.java | 7 +- .../ant/component/core/URLConverter.java | 11 +- .../org/apache/ant/component/core/antlib.xml | 1 + .../core/execution/AbstractAspectHandler.java | 3 + .../ant/core/execution/AspectHandler.java | 1 + .../ant/core/execution/ExecutionFrame.java | 16 +- .../ant/core/types/AbstractScanner.java | 580 ++++++++++++++++++ .../org/apache/ant/core/types/DataType.java | 4 + .../ant/core/types/DirectoryScanner.java | 266 ++++++++ .../org/apache/ant/core/types/FileSet.java | 319 ++++++++++ .../apache/ant/core/types/FileSetScanner.java | 115 ++++ .../org/apache/ant/core/types/PatternSet.java | 41 +- 14 files changed, 1335 insertions(+), 37 deletions(-) create mode 100644 proposal/mutant/src/main/org/apache/ant/core/types/AbstractScanner.java create mode 100644 proposal/mutant/src/main/org/apache/ant/core/types/DirectoryScanner.java create mode 100644 proposal/mutant/src/main/org/apache/ant/core/types/FileSet.java create mode 100644 proposal/mutant/src/main/org/apache/ant/core/types/FileSetScanner.java diff --git a/proposal/mutant/build.xml b/proposal/mutant/build.xml index 5e5790b8f..b10c42af4 100644 --- a/proposal/mutant/build.xml +++ b/proposal/mutant/build.xml @@ -12,7 +12,8 @@ + destdir="${build.classes}" closure="yes" + cache="${build.dir}/depcache"/> + diff --git a/proposal/mutant/src/main/org/apache/ant/core/execution/AbstractAspectHandler.java b/proposal/mutant/src/main/org/apache/ant/core/execution/AbstractAspectHandler.java index 6fcc1e2b0..bd7f903aa 100644 --- a/proposal/mutant/src/main/org/apache/ant/core/execution/AbstractAspectHandler.java +++ b/proposal/mutant/src/main/org/apache/ant/core/execution/AbstractAspectHandler.java @@ -74,6 +74,9 @@ public abstract class AbstractAspectHandler implements AspectHandler { return aspectContext; } + public void beforeConfigElement(Object element) throws ExecutionException { +} + public void afterConfigElement(Object element) throws ExecutionException { } } diff --git a/proposal/mutant/src/main/org/apache/ant/core/execution/AspectHandler.java b/proposal/mutant/src/main/org/apache/ant/core/execution/AspectHandler.java index 4acf85352..5a586dc8b 100644 --- a/proposal/mutant/src/main/org/apache/ant/core/execution/AspectHandler.java +++ b/proposal/mutant/src/main/org/apache/ant/core/execution/AspectHandler.java @@ -69,6 +69,7 @@ public interface AspectHandler { void setAspectContext(ExecutionContext context); + void beforeConfigElement(Object element) throws ExecutionException ; void afterConfigElement(Object element) throws ExecutionException ; } diff --git a/proposal/mutant/src/main/org/apache/ant/core/execution/ExecutionFrame.java b/proposal/mutant/src/main/org/apache/ant/core/execution/ExecutionFrame.java index ffb28aca4..1844df69d 100644 --- a/proposal/mutant/src/main/org/apache/ant/core/execution/ExecutionFrame.java +++ b/proposal/mutant/src/main/org/apache/ant/core/execution/ExecutionFrame.java @@ -543,8 +543,6 @@ public class ExecutionFrame { task = new TaskAdapter(taskType, element); } - ExecutionContext context = new ExecutionContext(this, eventSupport, model); - task.setTaskContext(context); configureElement(element, model); return task; @@ -611,10 +609,21 @@ public class ExecutionFrame { */ private void configureElement(Object element, TaskElement model) throws ExecutionException, ConfigException { - + + if (element instanceof Task) { + Task task = (Task)element; + ExecutionContext context = new ExecutionContext(this, eventSupport, model); + task.setTaskContext(context); + } try { ClassIntrospector introspector = getIntrospector(element.getClass()); + List aspects = getActiveAspects(model); + for (Iterator i = aspects.iterator(); i.hasNext(); ) { + AspectHandler aspectHandler = (AspectHandler)i.next(); + aspectHandler.beforeConfigElement(element); + } + // start by setting the attributes of this element for (Iterator i = model.getAttributeNames(); i.hasNext();) { String attributeName = (String)i.next(); @@ -644,7 +653,6 @@ public class ExecutionFrame { configureElement(nestedElement, nestedElementModel); } } - List aspects = getActiveAspects(model); for (Iterator i = aspects.iterator(); i.hasNext(); ) { AspectHandler aspectHandler = (AspectHandler)i.next(); aspectHandler.afterConfigElement(element); diff --git a/proposal/mutant/src/main/org/apache/ant/core/types/AbstractScanner.java b/proposal/mutant/src/main/org/apache/ant/core/types/AbstractScanner.java new file mode 100644 index 000000000..0c96c798c --- /dev/null +++ b/proposal/mutant/src/main/org/apache/ant/core/types/AbstractScanner.java @@ -0,0 +1,580 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 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 + * . + */ + +package org.apache.ant.core.types; + +import java.io.*; +import java.util.*; +import org.apache.ant.core.execution.*; + +/** + * The abstract FileSetInfo performs all of the name matching and mapping operations + * common to FileSetInfo classes. + */ +public abstract class AbstractScanner implements FileSetScanner { + /** The list of patternSets to process on this directory */ + List patternSets; + + /** Indicator for whether default excludes should be applied. */ + boolean useDefaultExcludes; + + /* + * The patterns for the files that should be included. + */ + private String[] includes; + + /** + * The patterns for the files that should be excluded. + */ + private String[] excludes; + + /** + * Patterns that should be excluded by default. + * + * @see #addDefaultExcludes() + */ + protected final static String[] DEFAULTEXCLUDES = { + "**/*~", + "**/#*#", + "**/.#*", + "**/%*%", + "**/CVS", + "**/CVS/**", + "**/.cvsignore", + "**/SCCS", + "**/SCCS/**" + }; + + public AbstractScanner(List patternSets, + boolean useDefaultExcludes) throws ExecutionException { + this.patternSets = patternSets; + this.useDefaultExcludes = useDefaultExcludes; + + //convert patternsets into excludes + PatternSet combinedSet = new PatternSet(); + for (Iterator i = patternSets.iterator(); i.hasNext(); ) { + PatternSet set = (PatternSet)i.next(); + combinedSet.append(set); + } + + String[] includes = combinedSet.getIncludePatterns(); + if (includes == null) { + // No includes supplied, so set it to 'matches all' + includes = new String[1]; + includes[0] = "**"; + } + String[] excludes = combinedSet.getExcludePatterns(); + if (excludes == null) { + excludes = new String[0]; + } + + setIncludes(includes); + setExcludes(excludes); + if (useDefaultExcludes) { + addDefaultExcludes(); + } + } + + /** + * Sets the set of include patterns to use. All '/' and '\' characters are + * replaced by File.separatorChar. So the separator used need + * not match File.separatorChar. + *

+ * When a pattern ends with a '/' or '\', "**" is appended. + * + * @param includes list of include patterns + */ + protected void setIncludes(String[] includes) { + if (includes == null) { + this.includes = null; + } else { + 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); + if (pattern.endsWith(File.separator)) { + pattern += "**"; + } + this.includes[i] = pattern; + } + } + } + + /** + * Sets the set of exclude patterns to use. All '/' and '\' characters are + * replaced by File.separatorChar. So the separator used need + * not match File.separatorChar. + *

+ * When a pattern ends with a '/' or '\', "**" is appended. + * + * @param excludes list of exclude patterns + */ + protected void setExcludes(String[] excludes) { + if (excludes == null) { + this.excludes = null; + } else { + 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); + if (pattern.endsWith(File.separator)) { + pattern += "**"; + } + this.excludes[i] = pattern; + } + } + } + + /** + * Does the path match the start of this pattern up to the first "**". + + + *

This is not a general purpose test and should only be used if you + * can live with false positives.

+ * + *

pattern=**\\a and str=b will yield true. + * + * @param pattern the (non-null) pattern to match against + * @param str the (non-null) string (path) to match + */ + protected static boolean matchPatternStart(String pattern, String str) { + // 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 = new Vector(); + StringTokenizer st = new StringTokenizer(pattern,File.separator); + while (st.hasMoreTokens()) { + patDirs.addElement(st.nextToken()); + } + + Vector strDirs = new Vector(); + st = new StringTokenizer(str,File.separator); + while (st.hasMoreTokens()) { + strDirs.addElement(st.nextToken()); + } + + int patIdxStart = 0; + int patIdxEnd = patDirs.size()-1; + int strIdxStart = 0; + int strIdxEnd = strDirs.size()-1; + + // up to first '**' + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { + String patDir = (String)patDirs.elementAt(patIdxStart); + if (patDir.equals("**")) { + break; + } + if (!match(patDir,(String)strDirs.elementAt(strIdxStart))) { + 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; + } + } + + /** + * Matches a path against a pattern. + * + * @param pattern the (non-null) pattern to match against + * @param str the (non-null) string (path) to match + * + * @return true when the pattern matches against the string. + * false otherwise. + */ + protected static boolean matchPath(String pattern, String str) { + // 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 = new Vector(); + StringTokenizer st = new StringTokenizer(pattern,File.separator); + while (st.hasMoreTokens()) { + patDirs.addElement(st.nextToken()); + } + + Vector strDirs = new Vector(); + st = new StringTokenizer(str,File.separator); + while (st.hasMoreTokens()) { + strDirs.addElement(st.nextToken()); + } + + int patIdxStart = 0; + int patIdxEnd = patDirs.size()-1; + int strIdxStart = 0; + int strIdxEnd = strDirs.size()-1; + + // up to first '**' + while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) { + String patDir = (String)patDirs.elementAt(patIdxStart); + if (patDir.equals("**")) { + break; + } + if (!match(patDir,(String)strDirs.elementAt(strIdxStart))) { + 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))) { + 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)) { + 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; + } + + + + /** + * Matches a string against a pattern. The pattern contains two special + * characters: + * '*' which means zero or more characters, + * '?' which means one and only one character. + * + * @param pattern the (non-null) pattern to match against + * @param str the (non-null) string that must be matched against the + * pattern + * + * @return true when the string matches against the pattern, + * false otherwise. + */ + protected static boolean match(String pattern, String str) { + 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 != '?' && ch != 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 != '?' && ch != strArr[strIdxStart]) { + return false; + } + 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 != '?' && ch != strArr[strIdxEnd]) { + return false; + } + 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 != '?' && ch != 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; + } + + /** + * Tests whether a name matches against at least one include pattern. + * + * @param name the name to match + * @return true when the name matches against at least one + * include pattern, false otherwise. + */ + protected boolean isIncluded(String name) { + for (int i = 0; i < includes.length; i++) { + if (matchPath(includes[i],name)) { + return true; + } + } + return false; + } + + /** + * Tests whether a name matches the start of at least one include pattern. + * + * @param name the name to match + * @return true when the name matches against at least one + * include pattern, false otherwise. + */ + protected boolean couldHoldIncluded(String name) { + for (int i = 0; i < includes.length; i++) { + if (matchPatternStart(includes[i],name)) { + return true; + } + } + return false; + } + + /** + * Tests whether a name matches against at least one exclude pattern. + * + * @param name the name to match + * @return true when the name matches against at least one + * exclude pattern, false otherwise. + */ + protected boolean isExcluded(String name) { + for (int i = 0; i < excludes.length; i++) { + if (matchPath(excludes[i],name)) { + return true; + } + } + return false; + } + + /** + * Adds the array with default exclusions to the current exclusions set. + * + */ + public void addDefaultExcludes() { + int excludesLength = excludes == null ? 0 : excludes.length; + String[] newExcludes; + newExcludes = new String[excludesLength + DEFAULTEXCLUDES.length]; + if (excludesLength > 0) { + 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); + } + excludes = newExcludes; + } +} diff --git a/proposal/mutant/src/main/org/apache/ant/core/types/DataType.java b/proposal/mutant/src/main/org/apache/ant/core/types/DataType.java index d14a1702f..fc5bbd561 100644 --- a/proposal/mutant/src/main/org/apache/ant/core/types/DataType.java +++ b/proposal/mutant/src/main/org/apache/ant/core/types/DataType.java @@ -67,6 +67,10 @@ public abstract class DataType extends AbstractTask { private Object referencedObject = null; public void execute() throws ExecutionException { + validate(); + } + + protected void validate() throws ExecutionException { } /** diff --git a/proposal/mutant/src/main/org/apache/ant/core/types/DirectoryScanner.java b/proposal/mutant/src/main/org/apache/ant/core/types/DirectoryScanner.java new file mode 100644 index 000000000..365f091f9 --- /dev/null +++ b/proposal/mutant/src/main/org/apache/ant/core/types/DirectoryScanner.java @@ -0,0 +1,266 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 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 + * . + */ + +package org.apache.ant.core.types; + +import java.io.*; +import java.util.*; +import org.apache.ant.core.execution.*; + +/** + * A DirectoryFileset is a fileset where the files come from a directory and + * its subdirectories. + */ +public class DirectoryScanner extends AbstractScanner { + /** The directory which is the root of the search space. */ + File basedir; + + /** + * The files that where found and matched at least one includes, and matched + * no excludes. + */ + protected List filesIncluded; + + /** + * The files that where found and did not match any includes. + */ + protected List filesNotIncluded; + + /** + * The files that where found and matched at least one includes, and also + * matched at least one excludes. + */ + protected List filesExcluded; + + /** + * The directories that where found and matched at least one includes, and + * matched no excludes. + */ + protected List dirsIncluded; + + /** + * The directories that where found and did not match any includes. + */ + protected List dirsNotIncluded; + + /** + * The files that where found and matched at least one includes, and also + * matched at least one excludes. + */ + protected List dirsExcluded; + + /** Map to map filenames to actual File objects */ + private Map filenameMap = null; + + public DirectoryScanner(File basedir, List patternSets, + boolean useDefaultExcludes) throws ExecutionException { + super(patternSets, useDefaultExcludes); + this.basedir = basedir; + } + + public String[] getIncludedFiles() throws ExecutionException { + if (filesIncluded == null) { + scan(); + } + + return (String[])filesIncluded.toArray(new String[0]); + } + + /** + * Scans the base directory for files that match at least one include + * pattern, and don't match any exclude patterns. + * + * @throws ExecutionException when basedir was set incorrecly + */ + public void scan() throws ExecutionException { + if (basedir == null) { + throw new ExecutionException("The directory to scan has not been set"); + } + if (!basedir.exists()) { + throw new ExecutionException("basedir \"" + basedir + + "\" does not exist"); + } + if (!basedir.isDirectory()) { + throw new ExecutionException("basedir \"" + basedir + + "\" is not a directory"); + } + + filesIncluded = new ArrayList(); + filesNotIncluded = new ArrayList(); + filesExcluded = new ArrayList(); + dirsIncluded = new ArrayList(); + dirsNotIncluded = new ArrayList(); + dirsExcluded = new ArrayList(); + filenameMap = new HashMap(); + + String root = ""; + String mappedRoot = mapName(root); + filenameMap.put(mappedRoot, root); + if (isIncluded(root)) { + if (!isExcluded(root)) { + dirsIncluded.add(mappedRoot); + } else { + dirsExcluded.add(mappedRoot); + } + } else { + dirsNotIncluded.add(mappedRoot); + } + scandir(basedir, root, true); + } + + /** + * Scans the passed dir for files and directories. Found files and + * directories are placed in their respective collections, based on the + * matching of includes and excludes. When a directory is found, it is + * scanned recursively. + * + * @param dir the directory to scan + * @param vpath the path relative to the basedir (needed to prevent + * problems with an absolute path when using dir) + * + * @see #filesIncluded + * @see #filesNotIncluded + * @see #filesExcluded + * @see #dirsIncluded + * @see #dirsNotIncluded + * @see #dirsExcluded + */ + protected void scandir(File dir, String vpath, boolean fast) + throws ExecutionException { + String[] newfiles = dir.list(); + + if (newfiles == null) { + /* + * two reasons are mentioned in the API docs for File.list + * (1) dir is not a directory. This is impossible as + * we wouldn't get here in this case. + * (2) an IO error occurred (why doesn't it throw an exception + * then???) + */ + throw new ExecutionException ("IO error scanning directory " + + dir.getAbsolutePath()); + } + + for (int i = 0; i < newfiles.length; i++) { + String name = vpath+newfiles[i]; + String mappedName = mapName(name); + filenameMap.put(mappedName, name); + File file = new File(dir,newfiles[i]); + if (file.isDirectory()) { + if (isIncluded(name)) { + if (!isExcluded(name)) { + dirsIncluded.add(mappedName); + if (fast) { + scandir(file, name+File.separator, fast); + } + } else { + dirsExcluded.add(mappedName); + } + } else { + dirsNotIncluded.add(mappedName); + if (fast && couldHoldIncluded(name)) { + scandir(file, name+File.separator, fast); + } + } + if (!fast) { + scandir(file, name+File.separator, fast); + } + } else if (file.isFile()) { + if (isIncluded(name)) { + if (!isExcluded(name)) { + filesIncluded.add(mappedName); + } else { + filesExcluded.add(mappedName); + } + } else { + filesNotIncluded.add(mappedName); + } + } + } + } + + private String mapName(String rawName) { + return "bozo/" + rawName; + } + + public File getLocalFile(String mappedName) throws ExecutionException { + if (filesIncluded == null) { + scan(); + } + + String realName = (String)filenameMap.get(mappedName); + if (realName == null) { + throw new ExecutionException("\"" + mappedName + "\" was not included in the scan."); + } + + return new File(basedir, realName); + } + + public String toString() { + try { + String[] files = getIncludedFiles(); + StringBuffer sb = new StringBuffer(); + String lsep = System.getProperty("line.separator"); + for (int i = 0; i < files.length; ++i) { + sb.append(files[i]); + sb.append(lsep); + } + + return sb.toString(); + } + catch (ExecutionException e) { + return "Fileset from \"" + basedir + "\""; + } + } +} diff --git a/proposal/mutant/src/main/org/apache/ant/core/types/FileSet.java b/proposal/mutant/src/main/org/apache/ant/core/types/FileSet.java new file mode 100644 index 000000000..018576bce --- /dev/null +++ b/proposal/mutant/src/main/org/apache/ant/core/types/FileSet.java @@ -0,0 +1,319 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 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 + * . + */ + +package org.apache.ant.core.types; + +import java.util.*; +import java.io.*; +import java.net.URL; +import org.apache.ant.core.execution.*; + +/** + * Moved out of MatchingTask to make it a standalone object that could + * be referenced (by scripts for example). + * + * @author Arnout J. Kuiper ajkuiper@wxs.nl + * @author Stefano Mazzocchi stefano@apache.org + * @author Sam Ruby rubys@us.ibm.com + * @author Jon S. Stevens jon@clearink.com + * @author Stefan Bodewig + */ +public class FileSet extends DataType { + private FileSetScanner scanner = null; + + private PatternSet defaultPatterns = new PatternSet(); + private List patternSets = new ArrayList(); + + /** + * The dir attribute is set when you are generating the list of files + * from a directory. + */ + private File dir = null; + + /** The zipfile attribute is used when the source of files is a zip file */ + private URL zipFile = null; + + /** + * The filelist attribute is a file which contains a list of file names. It must be used + * with the base attribute which indicates where the files are stored. + */ + private URL fileList = null; + + /** + * When using the filelist this attribute indicates the base location of the files in + * the list. + */ + private URL fileListBase = null; + + private boolean useDefaultExcludes = true; + + public FileSet() { + patternSets.add(defaultPatterns); + } + + /** + * Makes this instance in effect a reference to another FileSet + * instance. + * + *

You must not set another attribute or nest elements inside + * this element if you make it a reference.

+ */ + public void setRefid(String reference) throws ExecutionException { + if (dir != null || defaultPatterns.hasPatterns()) { + throw tooManyAttributes(); + } + if (!(patternSets.size() == 1)) { + throw noChildrenAllowed(); + } + super.setRefid(reference); + } + + public void setDir(File dir) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + this.dir = dir; + } + + public void setZipFile(URL zipFile) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + this.zipFile = zipFile; + } + + public void setFileList(URL fileList) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + this.fileList = fileList; + } + + public void setFileListBase(URL fileListBase) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + this.fileListBase = fileListBase; + } + + public PatternSet createPatternSet() throws ExecutionException { + if (isReference()) { + throw noChildrenAllowed(); + } + PatternSet patternSet = new PatternSet(); + patternSets.add(patternSet); + return patternSet; + } + + /** + * add a name entry on the include list + */ + public PatternSet.NameEntry createInclude() throws ExecutionException { + if (isReference()) { + throw noChildrenAllowed(); + } + return defaultPatterns.createInclude(); + } + + /** + * add a name entry on the exclude list + */ + public PatternSet.NameEntry createExclude() throws ExecutionException { + if (isReference()) { + throw noChildrenAllowed(); + } + return defaultPatterns.createExclude(); + } + + /** + * Sets the set of include patterns. Patterns may be separated by a comma + * or a space. + * + * @param includes the string containing the include patterns + */ + public void setIncludes(String includes) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + defaultPatterns.setIncludes(includes); + } + + /** + * Sets the set of exclude patterns. Patterns may be separated by a comma + * or a space. + * + * @param excludes the string containing the exclude patterns + */ + public void setExcludes(String excludes) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + defaultPatterns.setExcludes(excludes); + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param incl The file to fetch the include patterns from. + */ + public void setIncludesFile(URL incl) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + defaultPatterns.setIncludesFile(incl); + } + + /** + * Sets the name of the file containing the includes patterns. + * + * @param excl The file to fetch the exclude patterns from. + */ + public void setExcludesFile(URL excl) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + defaultPatterns.setExcludesFile(excl); + } + + /** + * Sets whether default exclusions should be used or not. + * + * @param useDefaultExcludes "true"|"on"|"yes" when default exclusions + * should be used, "false"|"off"|"no" when they + * shouldn't be used. + */ + public void setDefaultExcludes(boolean useDefaultExcludes) throws ExecutionException { + if (isReference()) { + throw tooManyAttributes(); + } + + this.useDefaultExcludes = useDefaultExcludes; + } + + protected FileSet getReferencedFileSet() throws ExecutionException { + Object o = getReferencedObject(); + if (!(o instanceof FileSet)) { + throw new ExecutionException(getReference() + " doesn\'t denote a fileset");; + } else { + return (FileSet) o; + } + } + + public void validate() throws ExecutionException { + if (dir != null) { + // firstly validate that the other attributes are not set + if (zipFile != null || fileList != null || fileListBase != null) { + throw new ExecutionException("The 'dir' attribute may not be combined with any " + + "of the 'zipfile', 'filelist' and 'base' attributes"); + } + } + else if (zipFile != null) { + if (fileList != null || fileListBase != null) { + throw new ExecutionException("The 'zipfile' attribute may not be combined with any " + + "of the 'dir', 'filelist' and 'base' attributes"); + } + } + else if (fileList != null) { + if (fileListBase == null) { + throw new ExecutionException("A 'base' attribute is required when using the 'filelist' " + + "attribute"); + } + } + else { + throw new ExecutionException("You must specify one of the 'dir', 'zipfile', or 'filelist' " + + "attributes"); + } + } + + public FileSetScanner getScanner() throws ExecutionException { + if (isReference()) { + return getReferencedFileSet().getScanner(); + } + + if (scanner != null) { + return scanner; + } + + // need to create the fileset info. For that we are going to need + // to determine which type of FileSetInfo implementation we should use. + if (dir != null) { + scanner = new DirectoryScanner(dir, patternSets, useDefaultExcludes); + } + else if (zipFile != null) { + } + else if (fileList != null) { + } + else { + } + + return scanner; + } + + public String toString() { + try { + return getScanner().toString(); + } + catch (ExecutionException e) { + return "FileSet"; + } + } +} diff --git a/proposal/mutant/src/main/org/apache/ant/core/types/FileSetScanner.java b/proposal/mutant/src/main/org/apache/ant/core/types/FileSetScanner.java new file mode 100644 index 000000000..b8f2d4bef --- /dev/null +++ b/proposal/mutant/src/main/org/apache/ant/core/types/FileSetScanner.java @@ -0,0 +1,115 @@ +/* + * The Apache Software License, Version 1.1 + * + * Copyright (c) 2000 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 + * . + */ + +package org.apache.ant.core.types; + +import java.io.*; +import java.net.URL; +import org.apache.ant.core.execution.*; + +/** + * The FileSetInfo interface defines the result of applying filtering to + * some base collection of files. Filtering involves both file exclusion + * and file name mapping. + * + * FileSetInfo should be lazily evaluated to allow them to be defined before the + * required files have been created. They should be evaluated at first use. + */ +public interface FileSetScanner { + /** + * Get the included files after their file names have been mapped + * + * @return an array of strings, each one is the mapped name of a file. + */ + String[] getIncludedFiles() throws ExecutionException ; +// +// /** +// * Get directories included after their file names have been mapped +// * +// * @return an array of strings, each one is the mapped name of a file. +// */ +// String[] getIncludedDirectories(); +// +// /** +// * Get a file for the content of the named included file. If the content +// * is not stored in the local filesystem, a temporary file is created with the content. +// * Callers should not rely on this file representing the actual location of the underlying +// * data. +// */ +// File getContentFile(String mappedName); +// +// /** +// * Get a URL for the content. The content may be cached on the local system and thus +// * callers should not rely on the location +// * +// */ +// URL getContentURL(String mappedName); +// +// /** +// * Get an input stream to the content of the named entry of the fileset. +// */ +// InputStream getInputStream(String mappedName); +// + /** + * Get a local file. + * + * This method returns a file pointing to the actual local filesystem file from + * which the file content comes. If the file does not exist locally, a null is + * returned. Note that due to name mapping, the actual file name may be different + * from the mapped name. + * + * @return a file representing the mapped file in the local filesystem. + */ + File getLocalFile(String mappedName) throws ExecutionException ; +} diff --git a/proposal/mutant/src/main/org/apache/ant/core/types/PatternSet.java b/proposal/mutant/src/main/org/apache/ant/core/types/PatternSet.java index dc3801205..e20a31f27 100644 --- a/proposal/mutant/src/main/org/apache/ant/core/types/PatternSet.java +++ b/proposal/mutant/src/main/org/apache/ant/core/types/PatternSet.java @@ -69,6 +69,7 @@ import java.net.URL; * @author Stefan Bodewig */ public class PatternSet extends DataType { + private boolean filesRead = false; private List includeList = new ArrayList(); private List excludeList = new ArrayList(); @@ -115,10 +116,6 @@ public class PatternSet extends DataType { // } } - - public PatternSet() { - } - /** * Makes this instance in effect a reference to another PatternSet * instance. @@ -203,7 +200,7 @@ public class PatternSet extends DataType { * * @param incl The file to fetch the include patterns from. */ - public void setIncludesfile(URL includeFile) throws ExecutionException { + public void setIncludesFile(URL includeFile) throws ExecutionException { if (isReference()) { throw tooManyAttributes(); } @@ -220,7 +217,7 @@ public class PatternSet extends DataType { * * @param excludeFile The file to fetch the exclude patterns from. */ - public void setExcludesfile(URL excludeFile) throws ExecutionException { + public void setExcludesFile(URL excludeFile) throws ExecutionException { if (isReference()) { throw tooManyAttributes(); } @@ -316,14 +313,14 @@ public class PatternSet extends DataType { } } -// /** -// * helper for FileSet. -// */ -// boolean hasPatterns() { -// return incl != null || excl != null -// || includeList.size() > 0 || excludeList.size() > 0; -// } -// + /** + * helper for FileSet. + */ + boolean hasPatterns() { + return includeFile != null || excludeFile != null + || includeList.size() > 0 || excludeList.size() > 0; + } + /** * Performs the check for circular references and returns the * referenced PatternSet. @@ -363,14 +360,14 @@ public class PatternSet extends DataType { * Read includefile ot excludefile if not already done so. */ private void readFiles() throws ExecutionException { - if (includeFile != null) { - readPatterns(includeFile, includeList); - includeFile = null; - } - if (excludeFile != null) { - readPatterns(excludeFile, excludeList); - excludeFile = null; + if (!filesRead) { + filesRead = true; + if (includeFile != null) { + readPatterns(includeFile, includeList); + } + if (excludeFile != null) { + readPatterns(excludeFile, excludeList); + } } } - }