/**********************************************************************
* Copyright (c) 2005-2009 ant4eclipse project team.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Nils Hartmann, Daniel Kasmeroglu, Gerd Wuetherich
**********************************************************************/
package org.ant4eclipse.ant.pde;
import java.io.File;
import java.util.List;
import org.ant4eclipse.ant.platform.core.task.AbstractAnt4EclipseFileSet;
import org.ant4eclipse.lib.core.logging.A4ELogging;
import org.ant4eclipse.lib.pde.model.buildproperties.AbstractBuildProperties;
import org.ant4eclipse.lib.pde.model.buildproperties.PluginBuildProperties;
import org.ant4eclipse.lib.pde.model.featureproject.FeatureProjectRole;
import org.ant4eclipse.lib.pde.model.pluginproject.PluginProjectRole;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DirectoryScanner;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.resources.FileResource;
import org.apache.tools.ant.types.selectors.SelectorUtils;
/**
* <p>
* The {@link PdeProjectFileSet} type can be used to define plug-in project relative file sets.
* </p>
*
* @author Gerd Wütherich (gerd@gerd-wuetherich.de)
*/
public class PdeProjectFileSet extends AbstractAnt4EclipseFileSet {
/** the bundle root (self) */
private static final String SELF = ".";
/** the name of the (default) self directory */
private static final String DEFAULT_SELF_DIRECTORY = "@dot";
/** the ant attribute 'excludeLibraries' */
private boolean _excludeLibraries = false;
/** - */
private boolean _sourceBundle = false;
/** - */
private AbstractBuildProperties _buildProperties;
/**
* <p>
* Creates a new instance of type {@link PdeProjectFileSet}.
* </p>
*
* @param project
* the ant project
*/
public PdeProjectFileSet(Project project) {
super(project);
}
/**
* <p>
* </p>
*
* @return the sourceBundle
*/
public boolean isSourceBundle() {
return this._sourceBundle;
}
/**
* <p>
* </p>
*
* @param sourceBundle
* the sourceBundle to set
*/
public void setSourceBundle(boolean sourceBundle) {
this._sourceBundle = sourceBundle;
}
/**
* <p>
* </p>
*
* @return the excludeLibraries
*/
public boolean isExcludeLibraries() {
return this._excludeLibraries;
}
/**
* <p>
* </p>
*
* @param excludeLibraries
* the excludeLibraries to set
*/
public void setExcludeLibraries(boolean excludeLibraries) {
this._excludeLibraries = excludeLibraries;
}
/**
* <p>
* Computes the file set.
* </p>
*/
@Override
protected void doComputeFileSet(List<Resource> resourceList) {
// require workspace and project name set
requireWorkspaceAndProjectNameSet();
if (!(getEclipseProject().hasRole(PluginProjectRole.class) || getEclipseProject().hasRole(FeatureProjectRole.class))) {
throw new BuildException(String.format(
"Project '%s' must have role 'PluginProjectRole' or 'FeatureProjectRole'.", getEclipseProject()
.getSpecifiedName()));
}
this._buildProperties = getEclipseProject().hasRole(PluginProjectRole.class) ? getEclipseProject().getRole(
PluginProjectRole.class).getBuildProperties() : getEclipseProject().getRole(FeatureProjectRole.class)
.getBuildProperties();
// nothing to do if no inclusion pattern is defined
if (this._sourceBundle && (!this._buildProperties.hasSourceIncludes())) {
return;
} else if ((!this._sourceBundle) && (!this._buildProperties.hasBinaryIncludes())) {
return;
}
// clear the resource list
resourceList.clear();
// iterate over the included pattern set
String[] includes = this._sourceBundle ? this._buildProperties.getSourceIncludes() : this._buildProperties
.getBinaryIncludes();
for (String token : includes) {
processEntry(resourceList, token);
}
// debug the resolved entries
if (A4ELogging.isDebuggingEnabled()) {
A4ELogging.debug("Resolved pde project file set for project '%s'. Entries are:", getEclipseProject()
.getSpecifiedName());
for (Resource resource : resourceList) {
A4ELogging.debug("- '%s'", resource);
}
}
}
/**
* <p>
*
* </p>
*
* @param resourceList
* The list the resources should be added to
* @param token
* The token that should be processed
*/
private void processEntry(List<Resource> resourceList, String token) {
// if token is a library name and _excludeLibraries
if (this._excludeLibraries && this._buildProperties instanceof PluginBuildProperties
&& ((PluginBuildProperties) this._buildProperties).hasLibrary(token)) {
return;
}
// 'patch' the dot
if (token.equals(SELF)) {
token = DEFAULT_SELF_DIRECTORY;
}
// 'process' the token
if (getEclipseProject().hasChild(token)) {
// get the project child with the given name
File file = getEclipseProject().getChild(token);
if (file.isFile()) {
// if the child is a file, just add it to the list
resourceList.add(new FileResource(getEclipseProject().getFolder(), token));
} else {
// if the child is a directory, scan the directory
DirectoryScanner directoryScanner = new DirectoryScanner();
directoryScanner.setBasedir(file);
directoryScanner.setCaseSensitive(isCaseSensitive());
directoryScanner.setIncludes(null);
if (getDefaultexcludes()) {
directoryScanner.addDefaultExcludes();
}
// do the job
directoryScanner.scan();
// get the included files and add it to the resource list
String[] files = directoryScanner.getIncludedFiles();
for (String fileName : files) {
if (token.equals(DEFAULT_SELF_DIRECTORY)) {
if (!matchExcludePattern(fileName)) {
resourceList.add(new FileResource(file, fileName));
}
} else {
if (!matchExcludePattern(token + File.separatorChar + fileName)) {
String filePath = normalize(file.getPath());
String rootPath = normalize(filePath).substring(0, filePath.lastIndexOf(normalize(token)));
resourceList.add(new FileResource(new File(rootPath), token + File.separatorChar + fileName));
}
}
}
}
}
}
/**
* <p>
* Helper method. Normalizes the given path.
* </p>
*
* @param path
* the path to normalize
* @return the normalized path
*/
private String normalize(String path) {
// replace '/' and '\' with File.separatorChar
String result = path.replace('/', File.separatorChar).replace('\\', File.separatorChar);
// remove trailing '/' and '\'
if (result.endsWith("/") || result.endsWith("\\")) {
result = result.substring(0, result.length() - 1);
}
// return result
return result;
}
/**
* <p>
* Helper method. Checks if the given string (which is a path) matches one of the exclude patterns.
* </p>
*
* @param path
* the path
* @return <code>true</code> if the given path matches an exclusion pattern.
*/
private boolean matchExcludePattern(String path) {
String[] excludes = this._sourceBundle ? this._buildProperties.getSourceExcludes() : this._buildProperties
.getBinaryExcludes();
// iterate over all excluded pattern
for (String pattern : excludes) {
// if the given path matches an exclusion pattern, return true
if (SelectorUtils.matchPath(normalize(pattern), normalize(path), isCaseSensitive())) {
return true;
}
}
// return false
return false;
}
}