blob: ad5fb025cd6274a0122301dbc0f6e38315b17c05 [file] [log] [blame]
/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-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;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.ProjectHelper;
import org.apache.tools.ant.BuildException;
import java.io.File;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;
/**
* Named collection of include/exclude tags.
*
* <p>Moved out of MatchingTask to make it a standalone object that
* could be referenced (by scripts for example).
*
*/
public class PatternSet extends DataType {
private Vector includeList = new Vector();
private Vector excludeList = new Vector();
private Vector includesFileList = new Vector();
private Vector excludesFileList = new Vector();
/**
* inner class to hold a selector list. A SelectorEntry
* is made up of the pattern and selection detail.
*/
public static class SelectorEntry {
private String type;
private String value;
private String operation;
public void setType(String t) {
this.type = t;
}
public void setValue(String val) {
this.value = val;
}
public void setOperation(String op) {
this.operation = op;
}
public String getType() {
return type;
}
public String getValue() {
return value;
}
public String getOperation() {
return operation;
}
}
/**
* inner class to hold a name on list. "If" and "Unless" attributes
* may be used to invalidate the entry based on the existence of a
* property (typically set thru the use of the Available task).
*/
public class NameEntry {
private String name;
private String ifCond;
private String unlessCond;
private Vector selectorList = new Vector();
public void setName(String name) {
this.name = name;
}
public void setIf(String cond) {
ifCond = cond;
}
public void setUnless(String cond) {
unlessCond = cond;
}
/**
* Include/Exclude can contain nested selectors
*/
public SelectorEntry createSelector() {
if (isReference()) {
throw noChildrenAllowed();
}
return addSelectorToList(selectorList);
}
/**
* add a selector entry to the given list
*/
private SelectorEntry addSelectorToList(final Vector list) {
final SelectorEntry result = new SelectorEntry();
list.addElement(result);
return result;
}
public String getName() {
return name;
}
public Vector getSelectorList() {
return selectorList;
}
public String evalName(Project p) {
return valid(p) ? name : null;
}
private boolean valid(Project p) {
if (ifCond != null && p.getProperty(ifCond) == null) {
return false;
} else if (unlessCond != null && p.getProperty(unlessCond) != null) {
return false;
}
return true;
}
public String toString() {
StringBuffer buf = new StringBuffer(name);
if ((ifCond != null) || (unlessCond != null)) {
buf.append(":");
String connector = "";
if (ifCond != null) {
buf.append("if->");
buf.append(ifCond);
connector = ";";
}
if (unlessCond != null) {
buf.append(connector);
buf.append("unless->");
buf.append(unlessCond);
}
}
return buf.toString();
}
public void setSelectorList(Vector list) {
this.selectorList = list;
}
}
public PatternSet() {
super();
}
/**
* Makes this instance in effect a reference to another PatternSet
* instance.
*
* <p>You must not set another attribute or nest elements inside
* this element if you make it a reference.</p>
*/
public void setRefid(Reference r) throws BuildException {
if (!includeList.isEmpty() || !excludeList.isEmpty()) {
throw tooManyAttributes();
}
super.setRefid(r);
}
/**
* add a name entry on the include list
*/
public NameEntry createInclude() {
if (isReference()) {
throw noChildrenAllowed();
}
return addPatternToList(includeList);
}
/**
* add a name entry on the include files list
*/
public NameEntry createIncludesFile() {
if (isReference()) {
throw noChildrenAllowed();
}
return addPatternToList(includesFileList);
}
/**
* add a name entry on the exclude list
*/
public NameEntry createExclude() {
if (isReference()) {
throw noChildrenAllowed();
}
return addPatternToList(excludeList);
}
/**
* add a name entry on the exclude files list
*/
public NameEntry createExcludesFile() {
if (isReference()) {
throw noChildrenAllowed();
}
return addPatternToList(excludesFileList);
}
/**
* 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) {
if (isReference()) {
throw tooManyAttributes();
}
if (includes != null && includes.length() > 0) {
StringTokenizer tok = new StringTokenizer(includes, ", ", false);
while (tok.hasMoreTokens()) {
createInclude().setName(tok.nextToken());
}
}
}
/**
* 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) {
if (isReference()) {
throw tooManyAttributes();
}
if (excludes != null && excludes.length() > 0) {
StringTokenizer tok = new StringTokenizer(excludes, ", ", false);
while (tok.hasMoreTokens()) {
createExclude().setName(tok.nextToken());
}
}
}
/**
* add a name entry to the given list
*/
private NameEntry addPatternToList(Vector list) {
NameEntry result = new NameEntry();
list.addElement(result);
return result;
}
/**
* Sets the name of the file containing the includes patterns.
*
* @param includesFile The file to fetch the include patterns from.
*/
public void setIncludesfile(File includesFile) throws BuildException {
if (isReference()) {
throw tooManyAttributes();
}
createIncludesFile().setName(includesFile.getAbsolutePath());
}
/**
* Sets the name of the file containing the excludes patterns.
*
* @param excludesFile The file to fetch the exclude patterns from.
*/
public void setExcludesfile(File excludesFile) throws BuildException {
if (isReference()) {
throw tooManyAttributes();
}
createExcludesFile().setName(excludesFile.getAbsolutePath());
}
/**
* Reads path matching patterns from a file and adds them to the
* includes or excludes list (as appropriate).
*/
private void readPatterns(File patternfile, Vector patternlist, Project p)
throws BuildException {
BufferedReader patternReader = null;
try {
// Get a FileReader
patternReader =
new BufferedReader(new FileReader(patternfile));
// Create one NameEntry in the appropriate pattern list for each
// line in the file.
String line = patternReader.readLine();
while (line != null) {
if (line.length() > 0) {
line = p.replaceProperties(line);
addPatternToList(patternlist).setName(line);
}
line = patternReader.readLine();
}
} catch(IOException ioe) {
String msg = "An error occured while reading from pattern file: "
+ patternfile;
throw new BuildException(msg, ioe);
} finally {
if( null != patternReader ) {
try {
patternReader.close();
} catch(IOException ioe) {
//Ignore exception
}
}
}
}
public void append2(PatternSet other, Project p) {
if (isReference()) {
throw new BuildException("Cannot append to a reference");
}
Pattern[] incl = other.getIncludePatterns2(p);
if (incl != null) {
for (int i=0; i<incl.length; i++) {
NameEntry ne = createInclude();
ne.setName(incl[i].getPattern());
ne.setSelectorList(incl[i].getSelectorList());
}
}
Pattern[] excl = other.getExcludePatterns2(p);
if (excl != null) {
for (int i=0; i<excl.length; i++) {
NameEntry ne = createExclude();
ne.setName(excl[i].getPattern());
ne.setSelectorList(incl[i].getSelectorList());
}
}
}
/**
* Adds the patterns of the other instance to this set.
*/
public void append(PatternSet other, Project p) {
if (isReference()) {
throw new BuildException("Cannot append to a reference");
}
String[] incl = other.getIncludePatterns(p);
if (incl != null) {
for (int i=0; i<incl.length; i++) {
createInclude().setName(incl[i]);
}
}
String[] excl = other.getExcludePatterns(p);
if (excl != null) {
for (int i=0; i<excl.length; i++) {
createExclude().setName(excl[i]);
}
}
}
/**
* Returns the filtered include patterns as an array of Patterns
*/
public Pattern[] getIncludePatterns2(Project p) {
if (isReference()) {
return getRef(p).getIncludePatterns2(p);
} else {
readFiles(p);
return makeArray2(includeList, p);
}
}
/**
* Returns the filtered exclude patterns as an array of Patterns
*/
public Pattern[] getExcludePatterns2(Project p) {
if (isReference()) {
return getRef(p).getExcludePatterns2(p);
} else {
readFiles(p);
return makeArray2(excludeList, p);
}
}
/**
* Returns the filtered include patterns.
*/
public String[] getIncludePatterns(Project p) {
if (isReference()) {
return getRef(p).getIncludePatterns(p);
} else {
readFiles(p);
return makeArray(includeList, p);
}
}
/**
* Returns the filtered include patterns.
*/
public String[] getExcludePatterns(Project p) {
if (isReference()) {
return getRef(p).getExcludePatterns(p);
} else {
readFiles(p);
return makeArray(excludeList, p);
}
}
/**
* helper for FileSet.
*/
boolean hasPatterns() {
return includesFileList.size() > 0 || excludesFileList.size() > 0
|| includeList.size() > 0 || excludeList.size() > 0;
}
/**
* Performs the check for circular references and returns the
* referenced PatternSet.
*/
private PatternSet getRef(Project p) {
if (!checked) {
Stack stk = new Stack();
stk.push(this);
dieOnCircularReference(stk, p);
}
Object o = ref.getReferencedObject(p);
if (!(o instanceof PatternSet)) {
String msg = ref.getRefId()+" doesn\'t denote a patternset";
throw new BuildException(msg);
} else {
return (PatternSet) o;
}
}
/**
* Convert a vector of NameEntry elements into an array of Patterns
*/
private Pattern[] makeArray2(Vector list, Project p) {
if (list.size() == 0) return null;
Vector tmpPatterns = new Vector();
for (Enumeration e = list.elements() ; e.hasMoreElements() ;) {
NameEntry ne = (NameEntry)e.nextElement();
String pattern = ne.evalName(p);
if (pattern != null && pattern.length() > 0) {
Pattern pat = new Pattern();
pat.setPattern(pattern);
pat.setSelectorList(ne.getSelectorList());
tmpPatterns.addElement(pat);
}
}
Pattern result[] = new Pattern[tmpPatterns.size()];
tmpPatterns.copyInto(result);
return result;
}
/**
* Convert a vector of NameEntry elements into an array of Strings.
*/
private String[] makeArray(Vector list, Project p) {
if (list.size() == 0) {
return null;
}
Vector tmpNames = new Vector();
for (Enumeration e = list.elements() ; e.hasMoreElements() ;) {
NameEntry ne = (NameEntry)e.nextElement();
String pattern = ne.evalName(p);
if (pattern != null && pattern.length() > 0) {
tmpNames.addElement(pattern);
}
}
String result[] = new String[tmpNames.size()];
tmpNames.copyInto(result);
return result;
}
/**
* Read includesfile ot excludesfile if not already done so.
*/
private void readFiles(Project p) {
if (includesFileList.size() > 0) {
Enumeration e = includesFileList.elements();
while (e.hasMoreElements()) {
NameEntry ne = (NameEntry)e.nextElement();
String fileName = ne.evalName(p);
if (fileName != null) {
File inclFile = p.resolveFile(fileName);
if (!inclFile.exists()) {
throw new BuildException("Includesfile "
+ inclFile.getAbsolutePath()
+ " not found.");
}
readPatterns(inclFile, includeList, p);
}
}
includesFileList.removeAllElements();
}
if (excludesFileList.size() > 0) {
Enumeration e = excludesFileList.elements();
while (e.hasMoreElements()) {
NameEntry ne = (NameEntry)e.nextElement();
String fileName = ne.evalName(p);
if (fileName != null) {
File exclFile = p.resolveFile(fileName);
if (!exclFile.exists()) {
throw new BuildException("Excludesfile "
+ exclFile.getAbsolutePath()
+ " not found.");
}
readPatterns(exclFile, excludeList, p);
}
}
excludesFileList.removeAllElements();
}
}
public String toString()
{
return "patternSet{ includes: " + includeList +
" excludes: " + excludeList + " }";
}
}