/* * Copyright 2000-2004 The Apache Software Foundation. * * 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 org.apache.tools.ant.taskdefs; import java.io.File; import java.io.IOException; import java.util.Hashtable; import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.AbstractFileSet; import org.apache.tools.ant.types.DirSet; import org.apache.tools.ant.types.EnumeratedAttribute; import org.apache.tools.ant.types.FileList; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Mapper; import org.apache.tools.ant.util.FileNameMapper; import org.apache.tools.ant.util.SourceFileScanner; /** * Executes a given command, supplying a set of files as arguments. * * @since Ant 1.2 * * @ant.task category="control" name="apply" */ public class ExecuteOn extends ExecTask { protected Vector filesets = new Vector(); // contains AbstractFileSet // (both DirSet and FileSet) private Vector filelists = new Vector(); private boolean relative = false; private boolean parallel = false; private boolean forwardSlash = false; protected String type = "file"; protected Commandline.Marker srcFilePos = null; private boolean skipEmpty = false; protected Commandline.Marker targetFilePos = null; protected Mapper mapperElement = null; protected FileNameMapper mapper = null; protected File destDir = null; private int maxParallel = -1; private boolean addSourceFile = true; private boolean verbose = false; private boolean ignoreMissing = true; private boolean force = false; /** * Has <srcfile> been specified before <targetfile> */ protected boolean srcIsFirst = true; /** * Source files to operate upon. */ public void addFileset(FileSet set) { filesets.addElement(set); } /** * Adds directories to operate on. * * @param set the DirSet to add. * * @since Ant 1.6 */ public void addDirset(DirSet set) { filesets.addElement(set); } /** * Source files to operate upon. */ public void addFilelist(FileList list) { filelists.addElement(list); } /** * Whether the filenames should be passed on the command line as * absolute or relative pathnames. Paths are relative to the base * directory of the corresponding fileset for source files or the * dest attribute for target files. */ public void setRelative(boolean relative) { this.relative = relative; } /** * If true, run the command only once, appending all files as arguments. * If false, command will be executed once for every file. Defaults to false. */ public void setParallel(boolean parallel) { this.parallel = parallel; } /** * Whether the command works only on files, directories or both? */ public void setType(FileDirBoth type) { this.type = type.getValue(); } /** * If no source files have been found or are newer than their * corresponding target files, do not run the command. */ public void setSkipEmptyFilesets(boolean skip) { skipEmpty = skip; } /** * The directory where target files are to be placed. */ public void setDest(File destDir) { this.destDir = destDir; } /** * The source and target file names on Windows and OS/2 must use * forward slash as file separator. */ public void setForwardslash(boolean forwardSlash) { this.forwardSlash = forwardSlash; } /** * Limit the command line length by passing at maximum this many * sourcefiles at once to the command. * *
Set to <= 0 for unlimited - this is the default.
* * @since Ant 1.6 */ public void setMaxParallel(int max) { maxParallel = max; } /** * Whether to send the source file name on the command line. * *Defaults to true.
*
* @since Ant 1.6
*/
public void setAddsourcefile(boolean b) {
addSourceFile = b;
}
/**
* Whether to print a verbose summary after execution.
*
* @since Ant 1.6
*/
public void setVerbose(boolean b) {
verbose = b;
}
/**
* Whether to ignore nonexistent files from filelists.
*
* @since Ant 1.6.2
*/
public void setIgnoremissing(boolean b) {
ignoreMissing = b;
}
/**
* Whether to bypass timestamp comparisons for target files.
*
* @since Ant 1.7
*/
public void setForce(boolean b) {
force = b;
}
/**
* Marker that indicates where the name of the source file should
* be put on the command line.
*/
public Commandline.Marker createSrcfile() {
if (srcFilePos != null) {
throw new BuildException(getTaskType() + " doesn\'t support multiple "
+ "srcfile elements.", getLocation());
}
srcFilePos = cmdl.createMarker();
return srcFilePos;
}
/**
* Marker that indicates where the name of the target file should
* be put on the command line.
*/
public Commandline.Marker createTargetfile() {
if (targetFilePos != null) {
throw new BuildException(getTaskType() + " doesn\'t support multiple "
+ "targetfile elements.", getLocation());
}
targetFilePos = cmdl.createMarker();
srcIsFirst = (srcFilePos != null);
return targetFilePos;
}
/**
* Mapper to use for mapping source files to target files.
*/
public Mapper createMapper() throws BuildException {
if (mapperElement != null) {
throw new BuildException("Cannot define more than one mapper",
getLocation());
}
mapperElement = new Mapper(getProject());
return mapperElement;
}
/**
* A nested filenamemapper
* @param fileNameMapper the mapper to add
* @since Ant 1.6.3
*/
public void add(FileNameMapper fileNameMapper) {
createMapper().add(fileNameMapper);
}
/**
* @todo using taskName here is brittle, as a user could override it.
* this should probably be modified to use the classname instead.
*/
protected void checkConfiguration() {
if ("execon".equals(getTaskName())) {
log("!! execon is deprecated. Use apply instead. !!");
}
super.checkConfiguration();
if (filesets.size() == 0 && filelists.size() == 0) {
throw new BuildException("no filesets and no filelists specified",
getLocation());
}
if (targetFilePos != null || mapperElement != null
|| destDir != null) {
if (mapperElement == null) {
throw new BuildException("no mapper specified", getLocation());
}
if (destDir == null) {
throw new BuildException("no dest attribute specified",
getLocation());
}
mapper = mapperElement.getImplementation();
}
}
protected ExecuteStreamHandler createHandler() throws BuildException {
//if we have a RedirectorElement, return a decoy
return (redirectorElement == null)
? super.createHandler() : new PumpStreamHandler();
}
protected void setupRedirector() {
super.setupRedirector();
redirector.setAppendProperties(true);
}
protected void runExec(Execute exe) throws BuildException {
int totalFiles = 0;
int totalDirs = 0;
boolean haveExecuted = false;
try {
Vector fileNames = new Vector();
Vector baseDirs = new Vector();
for (int i = 0; i < filesets.size(); i++) {
String currentType = type;
AbstractFileSet fs = (AbstractFileSet) filesets.elementAt(i);
if (fs instanceof DirSet) {
if (!"dir".equals(type)) {
log("Found a nested dirset but type is " + type + ". "
+ "Temporarily switching to type=\"dir\" on the"
+ " assumption that you really did mean"
+ "