/*
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2003 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 [EMAIL PROTECTED]
*
* 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 com.logica.ant;
import java.io.File;
import java.util.Enumeration;
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.taskdefs.CallTarget;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.PatternSet;
/**
* Call another target(s) in the same project for each file in a specified
* fileset. The targets are invoked with nested properties from the
* <code><antcall></code> element; four additional properties are
* passed: <BR>
* <code>foreach.file</code>--a full filename from the defined fileset,<BR>
* <code>foreach.dir</code>--the directory of the file,<BR>
* <code>foreach.name.ext</code>--the name of the file, without path but
* with extension,<BR>
* <code>foreach.name</code>--the name of the file, without path and without
* extension
* <code>foreach.name.withpath</code>--the name of the file with path
* relative to the current directory
* <pre>
* <target name="foo">
* <foreach>
* <fileset dir="${server.src}" casesensitive="yes">
* <include name="**\/*.java"/>
* <exclude name="**\/*Test*"/>
* </fileset>
* <antcall target="bar">
* <param name="property1" value="aaaaa" />
* <param name="foo" value="bar" />
* </antcall>
* </foreach>
* </target>
*
* <target name="bar" depends="init">
* <echo message="prop is ${property1} ${foo}" />
* <echo message="foreach.file is ${foreach.file}" />
* <echo message="foreach.dir is ${foreach.dir}" />
* <echo message="foreach.name.ext is ${foreach.name.ext}" />
* <echo message="foreach.name is ${foreach.name}" />
* </target>
* </pre>
*
* <p>This only works as expected if neither property1 nor foo are
* defined in the project itself.
*
* @author Stefano Mazzocchi
* <a href="mailto:[EMAIL PROTECTED]">[EMAIL PROTECTED]</a>
* @author Tom Dimock <a href="mailto:[EMAIL PROTECTED]">[EMAIL PROTECTED]</a>
* @author Glenn McAllister
* <a href="mailto:[EMAIL PROTECTED]">[EMAIL PROTECTED]</a>
* @author Jon S. Stevens <a
href="mailto:[EMAIL PROTECTED]">[EMAIL PROTECTED]</a>
* @author Jan Vanovcan <a href="mailto:[EMAIL PROTECTED]">
* [EMAIL PROTECTED]</a>
*
* @since Ant 1.5.1
*
* @ant.task name="foreach" category="control"
*/
public class ForEach extends MatchingTask {
protected File file = null;
protected File dir = null;
protected Vector filesets = new Vector();
protected boolean usedMatchingTask = false;
// by default, process matching empty dirs
protected boolean includeEmpty = false;
private int verbosity = Project.MSG_VERBOSE;
private boolean quiet = false;
private boolean failonerror = true;
/*
* The target(s) we will call
*/
private Vector callTarget = new Vector();
/**
* Set the call target tha should be invoked
*
* @param task the call target to be invoked
*/
public void addConfiguredAntcall(CallTarget task) {
if (task == null)
throw new BuildException("Tried to add a NULL
<antcall>");
callTarget.addElement(task);
log("Added call target...", Project.MSG_DEBUG);
}
/*
* From this point on the source code is copied from the Ant's
Delete task.
* The only difference is in replacing word 'Delete/Remove' by
'Process'. Of
* course the private methods are replaced.
*/
/**
* Set the name of a single file to be processed.
*
* @param file the file to be processed
*/
public void setFile(File file) {
this.file = file;
}
/**
* Set the directory from which files are to be processed
*
* @param dir the directory path.
*/
public void setDir(File dir) {
this.dir = dir;
}
/**
* If true, list all names of processed files.
*
* @param verbose "true" or "on"
*/
public void setVerbose(boolean verbose) {
if (verbose) {
this.verbosity = Project.MSG_INFO;
} else {
this.verbosity = Project.MSG_VERBOSE;
}
}
/**
* If true and the file does not exist, do not display a diagnostic
* message or modify the exit status to reflect an error.
* This means that if a file or directory cannot be processed, then
no
* error is reported. Default is false meaning things are "
* noisy"
* @param quiet "true" or "on"
*/
public void setQuiet(boolean quiet) {
this.quiet = quiet;
if (quiet) {
this.failonerror = false;
}
}
/**
* If false, note errors but continue.
*
* @param failonerror true or false
*/
public void setFailOnError(boolean failonerror) {
this.failonerror = failonerror;
}
/**
* If true, process empty directories.
*/
public void setIncludeEmptyDirs(boolean includeEmpty) {
this.includeEmpty = includeEmpty;
}
/**
* Adds a set of files to be processed.
*/
public void addFileset(FileSet set) {
filesets.addElement(set);
}
/**
* add a name entry on the include list
*/
public PatternSet.NameEntry createInclude() {
usedMatchingTask = true;
return super.createInclude();
}
/**
* add a name entry on the include files list
*/
public PatternSet.NameEntry createIncludesFile() {
usedMatchingTask = true;
return super.createIncludesFile();
}
/**
* add a name entry on the exclude list
*/
public PatternSet.NameEntry createExclude() {
usedMatchingTask = true;
return super.createExclude();
}
/**
* add a name entry on the include files list
*/
public PatternSet.NameEntry createExcludesFile() {
usedMatchingTask = true;
return super.createExcludesFile();
}
/**
* add a set of patterns
*/
public PatternSet createPatternSet() {
usedMatchingTask = true;
return super.createPatternSet();
}
/**
* 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) {
usedMatchingTask = true;
super.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) {
usedMatchingTask = true;
super.setExcludes(excludes);
}
/**
* 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) {
usedMatchingTask = true;
super.setDefaultexcludes(useDefaultExcludes);
}
/**
* Sets the name of the file containing the includes patterns.
*
* @param includesfile A string containing the filename to fetch
* the include patterns from.
*/
public void setIncludesfile(File includesfile) {
usedMatchingTask = true;
super.setIncludesfile(includesfile);
}
/**
* Sets the name of the file containing the includes patterns.
*
* @param excludesfile A string containing the filename to fetch
* the include patterns from.
*/
public void setExcludesfile(File excludesfile) {
usedMatchingTask = true;
super.setExcludesfile(excludesfile);
}
/**
* Process the file(s).
*/
public void execute() throws BuildException {
if (usedMatchingTask) {
log(
"DEPRECATED - Use of the implicit FileSet is
deprecated. "
+ "Use a nested fileset element
instead.");
}
if (file == null && dir == null && filesets.size() == 0) {
throw new BuildException(
"At least one of the file or dir "
+ "attributes, or a fileset element,
"
+ "must be set.");
}
if (quiet && failonerror) {
throw new BuildException(
"quiet and failonerror cannot both be " +
"set to true",
location);
}
// process the single file
if (file != null) {
if (file.exists()) {
if (file.isDirectory()) {
log(
"Directory "
+
file.getAbsolutePath()
+ " cannot be
processed using the file attribute. "
+ "Use dir
instead.");
} else {
log("Processing: " +
file.getAbsolutePath(), Project.MSG_VERBOSE);
if (!process(file)) {
String message =
"Unable to process
file " + file.getAbsolutePath();
if (failonerror) {
throw new
BuildException(message);
} else {
log(
message,
quiet ?
Project.MSG_VERBOSE : Project.MSG_WARN);
}
}
}
} else {
log(
"Could not find file "
+ file.getAbsolutePath()
+ " to process.",
Project.MSG_VERBOSE);
}
}
// process the directory
if (dir != null
&& dir.exists()
&& dir.isDirectory()
&& !usedMatchingTask) {
if (verbosity == Project.MSG_VERBOSE) {
log("Processing directory " +
dir.getAbsolutePath());
}
processDir(dir);
}
// process the files in the filesets
for (int i = 0; i < filesets.size(); i++) {
FileSet fs = (FileSet) filesets.elementAt(i);
try {
DirectoryScanner ds =
fs.getDirectoryScanner(project);
String[] files = ds.getIncludedFiles();
String[] dirs = ds.getIncludedDirectories();
processFiles(fs.getDir(project), files,
dirs);
} catch (BuildException be) {
// directory doesn't exist or is not
readable
if (failonerror) {
throw be;
} else {
log(
be.getMessage(),
quiet ? Project.MSG_VERBOSE
: Project.MSG_WARN);
}
}
}
// process the files from the default fileset
if (usedMatchingTask && dir != null) {
try {
DirectoryScanner ds =
super.getDirectoryScanner(dir);
String[] files = ds.getIncludedFiles();
String[] dirs = ds.getIncludedDirectories();
processFiles(dir, files, dirs);
} catch (BuildException be) {
// directory doesn't exist or is not
readable
if (failonerror) {
throw be;
} else {
log(
be.getMessage(),
quiet ? Project.MSG_VERBOSE
: Project.MSG_WARN);
}
}
}
}
/********************************************************************
* Private methods
********************************************************************/
/*
* All processXXX methods finish here ;-)
*/
private boolean process(File file) {
/*
* Try to set up the environment...
*/
log("Processing : " + file.getAbsolutePath(),
Project.MSG_VERBOSE);
String foreachFile = file.getAbsolutePath();
this.getProject().setProperty("foreach.file", foreachFile);
String foreachDir = new String("");
int lastSlash = foreachFile.lastIndexOf(File.separatorChar);
if (lastSlash > 0)
foreachDir = foreachFile.substring(0, lastSlash);
this.getProject().setProperty("foreach.dir", foreachDir);
String foreachNameExt = file.getName();
this.getProject().setProperty("foreach.name.ext",
foreachNameExt);
String foreachName = file.getName();
int dotPosition = foreachName.lastIndexOf('.');
if (dotPosition > 0)
foreachName = foreachName.substring(0, dotPosition);
this.getProject().setProperty("foreach.name", foreachName);
this.getProject().setProperty("foreach.name.withpath",
file.getPath());
/*
* For each file in the fileset call the target with the
proper
* environment. The environment (properties) is set
according to the
* current file. All embedded tasks are executed--the order
is quite
* unknown (depends on Ant's insertion order), but should be
the same
* for each iteration.
*/
for (Enumeration iter = callTarget.elements();
iter.hasMoreElements();
) {
CallTarget element = (CallTarget)
iter.nextElement();
element.perform();
}
return true;
}
private boolean processDir(File file) {
String files[] = dir.list();
if (files == null) {
throw new BuildException(
"The '" + dir.getAbsolutePath() + "' is not
a directory.",
location);
}
for (int i = 0; i < files.length; i++) {
File f = new File(files[i]);
process(f);
}
return true;
}
private boolean processFiles(File file, String[] s1, String[] s2) {
for (int i = 0; i < s1.length; i++) {
process(new File(s1[i]));
}
return true;
}
}
> -----Original Message-----
> From: Manjunath Rane [mailto:[EMAIL PROTECTED]
> Sent: Monday, January 13, 2003 8:44 AM
> To: Ant Developers List
> Subject: RE: echo and filesets
>
>
> sure, i would like it...please do forward the same
>
> Cheers,
> Manjunath Rane
>
> -----Original Message-----
> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]
> Sent: Monday, January 13, 2003 1:50 PM
> To: [EMAIL PROTECTED]
> Subject: RE: echo and filesets
>
>
> Matthew,
>
> I wrote a task that takes a fileset and calls any ant target
> for each file
> in the fileset. It passes several formats of the currently processed
> filename in properties:
>
> foreach.file--a full filename from the defined fileset,
> foreach.dir--the directory of the file,
> foreach.name.ext--the name of the file, without path but with
> extension,
> foreach.name--the name of the file, without path and without extension
>
> Example:
>
> <target name="foo">
> <foreach>
> <fileset dir="${server.src}" casesensitive="yes">
> <include name="**/*.java"/>
> <exclude name="**/*Test*"/>
> </fileset>
> <antcall target="bar">
> <param name="property1" value="aaaaa" />
> <param name="foo" value="bar" />
> </antcall>
> </foreach>
> </target>
>
> <target name="bar" depends="init">
> <echo message="prop is ${property1} ${foo}" />
> <echo message="foreach.file is ${foreach.file}" />
> <echo message="foreach.dir is ${foreach.dir}" />
> <echo message="foreach.name.ext is ${foreach.name.ext}" />
> <echo message="foreach.name is ${foreach.name}" />
> </target>
>
> It is based on the core <delete> task.
>
> Are you interested in it? Is there anyone else interested?
> (Wouldn't mind to
> have it included in the Ant's distribution ;-))
> Jan
>
> > -----Original Message-----
> > From: Inger, Matthew [mailto:[EMAIL PROTECTED]
> > Sent: Friday, January 10, 2003 8:25 PM
> > To: '[EMAIL PROTECTED]'
> > Subject: echo and filesets
> >
> >
> > Would it be possible (i would even be willing to write the code) to
> > extend the echo task so that it could take a fileset argument? And
> > it would either echo the fileset to the standard output area, or to
> > the file specified in the command?
> >
> > ie.
> >
> >
> > <fileset id="myFs" dir="src" includes="**/*.java" />
> >
> > <echo file="fileList.txt">
> > <fileset refid="myFs" />
> > </echo>
> >
> >
> > Reason i ask is that right now, we are using the exec command
> > and specifying an output file for a "cmd.exe /c dir /s /b
> > *.java" command to
> > get the filelist. I'd rather do it in a more os independent manner.
> >
> > Once we have the file, we're passing the filename to the <ajc>
> > (aspect java compiler) for processing. It uses the contents of
> > this file to actually build the project (it needs all java
> file names
> > to completely aspect and produce appropriate class files).
> >
> > http://www.aspectj.org for more info on aspectj
> >
> >
> >
>
> This e-mail and any attachment is for authorised use by the intended
> recipient(s) only. It may contain proprietary material, confidential
> information and/or be subject to legal privilege. It should
> not be copied,
> disclosed to, retained or used by, any other party. If you are not an
> intended recipient then please promptly delete this e-mail and any
> attachment and all copies and inform the sender. Thank you.
>
> --
> To unsubscribe, e-mail:
<mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>
This e-mail and any attachment is for authorised use by the intended
recipient(s) only. It may contain proprietary material, confidential
information and/or be subject to legal privilege. It should not be copied,
disclosed to, retained or used by, any other party. If you are not an intended
recipient then please promptly delete this e-mail and any attachment and all
copies and inform the sender. Thank you.
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>