/*
* Copyright (c) 2001-2004 Ant-Contrib project. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.antcontrib.antclipse;
import java.io.File;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
import org.apache.tools.ant.taskdefs.Property;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Path.PathElement;
import org.apache.tools.ant.util.RegexpPatternMapper;
import org.xml.sax.AttributeList;
import org.xml.sax.HandlerBase;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* Support class for the Antclipse task. Basically, it takes the .classpath Eclipse file
* and feeds a SAX parser. The handler is slightly different according to what we want to
* obtain (a classpath or a fileset)
* @author Adrian Spinei aspinei@myrealbox.com
* @version $Revision: 1.2 $
* @since Ant 1.5
*/
public class ClassPathTask extends Task
{
private String project;
private String idContainer = "antclipse";
private boolean includeSource = false; //default, do not include source
private boolean includeOutput = false; //default, do not include output directory
private boolean includeLibs = true; //default, include all libraries
private boolean verbose = false; //default quiet
RegexpPatternMapper irpm = null;
RegexpPatternMapper erpm = null;
public static final String TARGET_CLASSPATH = "classpath";
public static final String TARGET_FILESET = "fileset";
private String produce = null; //classpath by default
/**
* Setter for task parameter
* @param includeLibs Boolean, whether to include or not the project libraries. Default is true.
*/
public void setIncludeLibs(boolean includeLibs)
{
this.includeLibs = includeLibs;
}
/**
* Setter for task parameter
* @param produce This parameter tells the task wether to produce a "classpath" or a "fileset" (multiple filesets, as a matter of fact).
*/
public void setproduce(String produce)
{
this.produce = produce;
}
/**
* Setter for task parameter
* @param verbose Boolean, telling the app to throw some info during each step. Default is false.
*/
public void setVerbose(boolean verbose)
{
this.verbose = verbose;
}
/**
* Setter for task parameter
* @param excludes A regexp for files to exclude. It is taken into account only when producing a classpath, doesn't work on source or output files. It is a real regexp, not a "*" expression.
*/
public void setExcludes(String excludes)
{
if (excludes != null)
{
erpm = new RegexpPatternMapper();
erpm.setFrom(excludes);
erpm.setTo("."); //mandatory
}
else
erpm = null;
}
/**
* Setter for task parameter
* @param includes A regexp for files to include. It is taken into account only when producing a classpath, doesn't work on source or output files. It is a real regexp, not a "*" expression.
*/
public void setIncludes(String includes)
{
if (includes != null)
{
irpm = new RegexpPatternMapper();
irpm.setFrom(includes);
irpm.setTo("."); //mandatory
}
else
irpm = null;
}
/**
* Setter for task parameter
* @param idContainer The refid which will serve to identify the deliverables. When multiple filesets are produces, their refid is a concatenation between this value and something else (usually obtained from a path). Default "antclipse"
*/
public void setIdContainer(String idContainer)
{
this.idContainer = idContainer;
}
/**
* Setter for task parameter
* @param includeOutput Boolean, whether to include or not the project output directories. Default is false.
*/
public void setIncludeOutput(boolean includeOutput)
{
this.includeOutput = includeOutput;
}
/**
* Setter for task parameter
* @param includeSource Boolean, whether to include or not the project source directories. Default is false.
*/
public void setIncludeSource(boolean includeSource)
{
this.includeSource = includeSource;
}
/**
* Setter for task parameter
* @param project project name
*/
public void setProject(String project)
{
this.project = project;
}
/**
* @see org.apache.tools.ant.Task#execute()
*/
public void execute() throws BuildException
{
if (!TARGET_CLASSPATH.equalsIgnoreCase(this.produce) && !TARGET_FILESET.equals(this.produce))
throw new BuildException(
"Mandatory target must be either '" + TARGET_CLASSPATH + "' or '" + TARGET_FILESET + "'");
ClassPathParser parser = new ClassPathParser();
AbstractCustomHandler handler;
if (TARGET_CLASSPATH.equalsIgnoreCase(this.produce))
{
Path path = new Path(this.getProject());
this.getProject().addReference(this.idContainer, path);
handler = new PathCustomHandler(path);
}
else
{
FileSet fileSet = new FileSet();
this.getProject().addReference(this.idContainer, fileSet);
fileSet.setDir(new File(this.getProject().getBaseDir().getAbsolutePath().toString()));
handler = new FileSetCustomHandler(fileSet);
}
parser.parse(new File(this.getProject().getBaseDir().getAbsolutePath(), ".classpath"), handler);
}
abstract class AbstractCustomHandler extends HandlerBase
{
protected String projDir;
protected static final String ATTRNAME_PATH = "path";
protected static final String ATTRNAME_KIND = "kind";
protected static final String ATTR_LIB = "lib";
protected static final String ATTR_SRC = "src";
protected static final String ATTR_OUTPUT = "output";
protected static final String EMPTY = "";
}
class FileSetCustomHandler extends AbstractCustomHandler
{
private FileSet fileSet = null;
/**
* nazi style, forbid default constructor
*/
private FileSetCustomHandler()
{
}
/**
* @param fileSet
*/
public FileSetCustomHandler(FileSet fileSet)
{
super();
this.fileSet = fileSet;
projDir = getProject().getBaseDir().getAbsolutePath().toString();
}
/**
* @see org.xml.sax.DocumentHandler#endDocument()
*/
public void endDocument() throws SAXException
{
super.endDocument();
if (fileSet != null && !fileSet.hasPatterns())
fileSet.setExcludes("**/*");
//exclude everything or we'll take all the project dirs
}
public void startElement(String tag, AttributeList attrs) throws SAXParseException
{
if (tag.equalsIgnoreCase("classpathentry"))
{
//start by checking if the classpath is coherent at all
String kind = attrs.getValue(ATTRNAME_KIND);
if (kind == null)
throw new BuildException("classpathentry 'kind' attribute is mandatory");
String path = attrs.getValue(ATTRNAME_PATH);
if (path == null)
throw new BuildException("classpathentry 'path' attribute is mandatory");
//put the outputdirectory in a property
if (kind.equalsIgnoreCase(ATTR_OUTPUT))
{
String propName = idContainer + "outpath";
Property property = new Property();
property.setName(propName);
property.setValue(path);
property.setProject(getProject());
property.execute();
if (verbose)
System.out.println("Setting property " + propName + " to value " + path);
}
//let's put the last source directory in a property
if (kind.equalsIgnoreCase(ATTR_SRC))
{
String propName = idContainer + "srcpath";
Property property = new Property();
property.setName(propName);
property.setValue(path);
property.setProject(getProject());
property.execute();
if (verbose)
System.out.println("Setting property " + propName + " to value " + path);
}
if ((kind.equalsIgnoreCase(ATTR_SRC) && includeSource)
|| (kind.equalsIgnoreCase(ATTR_OUTPUT) && includeOutput)
|| (kind.equalsIgnoreCase(ATTR_LIB) && includeLibs))
{
//all seem fine
// check the includes
String[] inclResult = new String[] { "all included" };
if (irpm != null)
{
inclResult = irpm.mapFileName(path);
}
String[] exclResult = null;
if (erpm != null)
{
exclResult = erpm.mapFileName(path);
}
if (inclResult != null && exclResult == null)
{
//THIS is the specific code
if (kind.equalsIgnoreCase(ATTR_OUTPUT))
{
//we have included output so let's build a new fileset
FileSet outFileSet = new FileSet();
String newReference = idContainer + "-" + path.replace(File.separatorChar, '-');
getProject().addReference(newReference, outFileSet);
if (verbose)
System.out.println(
"Created new fileset "
+ newReference
+ " containing all the files from the output dir "
+ projDir
+ File.separator
+ path);
outFileSet.setDefaultexcludes(false);
outFileSet.setDir(new File(projDir + File.separator + path));
outFileSet.setIncludes("**/*"); //get everything
}
else
if (kind.equalsIgnoreCase(ATTR_SRC))
{
//we have included source so let's build a new fileset
FileSet srcFileSet = new FileSet();
String newReference = idContainer + "-" + path.replace(File.separatorChar, '-');
getProject().addReference(newReference, srcFileSet);
if (verbose)
System.out.println(
"Created new fileset "
+ newReference
+ " containing all the files from the source dir "
+ projDir
+ File.separator
+ path);
srcFileSet.setDefaultexcludes(false);
srcFileSet.setDir(new File(projDir + File.separator + path));
srcFileSet.setIncludes("**/*"); //get everything
}
else
{
//not otuptut, just add file after file to the fileset
File file = new File(fileSet.getDir(getProject()) + "/" + path);
if (file.isDirectory())
path += "/**/*";
if (verbose)
System.out.println(
"Adding "
+ path
+ " to fileset "
+ idContainer
+ " at "
+ fileSet.getDir(getProject()));
fileSet.setIncludes(path);
}
}
}
}
}
}
class PathCustomHandler extends AbstractCustomHandler
{
private Path path = null;
/**
* @param path the path to add files
*/
public PathCustomHandler(Path path)
{
super();
this.path = path;
}
/**
* nazi style, forbid default constructor
*/
private PathCustomHandler()
{
}
public void startElement(String tag, AttributeList attrs) throws SAXParseException
{
if (tag.equalsIgnoreCase("classpathentry"))
{
//start by checking if the classpath is coherent at all
String kind = attrs.getValue(ATTRNAME_KIND);
if (kind == null)
throw new BuildException("classpathentry 'kind' attribute is mandatory");
String path = attrs.getValue(ATTRNAME_PATH);
if (path == null)
throw new BuildException("classpathentry 'path' attribute is mandatory");
//put the outputdirectory in a property
if (kind.equalsIgnoreCase(ATTR_OUTPUT))
{
String propName = idContainer + "outpath";
Property property = new Property();
property.setName(propName);
property.setValue(path);
property.setProject(getProject());
property.execute();
if (verbose)
System.out.println("Setting property " + propName + " to value " + path);
}
//let's put the last source directory in a property
if (kind.equalsIgnoreCase(ATTR_SRC))
{
String propName = idContainer + "srcpath";
Property property = new Property();
property.setName(propName);
property.setValue(path);
property.setProject(getProject());
property.execute();
if (verbose)
System.out.println("Setting property " + propName + " to value " + path);
}
if ((kind.equalsIgnoreCase(ATTR_SRC) && includeSource)
|| (kind.equalsIgnoreCase(ATTR_OUTPUT) && includeOutput)
|| (kind.equalsIgnoreCase(ATTR_LIB) && includeLibs))
{
//all seem fine
// check the includes
String[] inclResult = new String[] { "all included" };
if (irpm != null)
{
inclResult = irpm.mapFileName(path);
}
String[] exclResult = null;
if (erpm != null)
{
exclResult = erpm.mapFileName(path);
}
if (inclResult != null && exclResult == null)
{
//THIS is the only specific code
if (verbose)
System.out.println("Adding " + path + " to classpath " + idContainer);
PathElement element = this.path.createPathElement();
element.setLocation(new File(path));
}
}
}
}
}
}