/* * 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]>