patch from PR1545. There is also more to come. PR: 1545 Submitted by: Michael McCallum <gholam@xtra.co.nz> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@269459 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -0,0 +1,271 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 2001 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 apache@apache.org. | |||||
| * | |||||
| * 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 org.apache.tools.ant; | |||||
| import java.io.*; | |||||
| import java.util.*; | |||||
| import org.apache.tools.ant.types.FilterSet; | |||||
| /** | |||||
| * Central representation of an Ant project. This class defines a | |||||
| * Ant project with all of it's targets and tasks. It also provides | |||||
| * the mechanism to kick off a build using a particular target name. | |||||
| * <p> | |||||
| * This class also encapsulates methods which allow Files to be refered | |||||
| * to using abstract path names which are translated to native system | |||||
| * file paths at runtime as well as defining various project properties. | |||||
| * | |||||
| * @author duncan@x180.com | |||||
| * @author <a href="mailto:conor@apache.org">Conor MacNeill</a> | |||||
| */ | |||||
| public class FileUtils { | |||||
| private static Object lockReflection = new Object(); | |||||
| private static java.lang.reflect.Method setLastModified = null; | |||||
| /** | |||||
| * Convienence method to copy a file from a source to a destination. | |||||
| * No filtering is performed. | |||||
| * | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void copyFile(String sourceFile, String destFile) throws IOException { | |||||
| copyFile(new File(sourceFile), new File(destFile), null, false, false); | |||||
| } | |||||
| /** | |||||
| * Convienence method to copy a file from a source to a destination | |||||
| * specifying if token filtering must be used. | |||||
| * | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void copyFile(String sourceFile, String destFile, FilterSet filterSet) | |||||
| throws IOException | |||||
| { | |||||
| copyFile(new File(sourceFile), new File(destFile), filterSet, false, false); | |||||
| } | |||||
| /** | |||||
| * Convienence method to copy a file from a source to a | |||||
| * destination specifying if token filtering must be used and if | |||||
| * source files may overwrite newer destination files. | |||||
| * | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void copyFile(String sourceFile, String destFile, FilterSet filterSet, | |||||
| boolean overwrite) throws IOException { | |||||
| copyFile(new File(sourceFile), new File(destFile), filterSet, | |||||
| overwrite, false); | |||||
| } | |||||
| /** | |||||
| * Convienence method to copy a file from a source to a | |||||
| * destination specifying if token filtering must be used, if | |||||
| * source files may overwrite newer destination files and the | |||||
| * last modified time of <code>destFile</code> file should be made equal | |||||
| * to the last modified time of <code>sourceFile</code>. | |||||
| * | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void copyFile(String sourceFile, String destFile, FilterSet filterSet, | |||||
| boolean overwrite, boolean preserveLastModified) | |||||
| throws IOException { | |||||
| copyFile(new File(sourceFile), new File(destFile), filterSet, | |||||
| overwrite, preserveLastModified); | |||||
| } | |||||
| /** | |||||
| * Convienence method to copy a file from a source to a destination. | |||||
| * No filtering is performed. | |||||
| * | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void copyFile(File sourceFile, File destFile) throws IOException { | |||||
| copyFile(sourceFile, destFile, null, false, false); | |||||
| } | |||||
| /** | |||||
| * Convienence method to copy a file from a source to a destination | |||||
| * specifying if token filtering must be used. | |||||
| * | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void copyFile(File sourceFile, File destFile, FilterSet filterSet) | |||||
| throws IOException { | |||||
| copyFile(sourceFile, destFile, filterSet, false, false); | |||||
| } | |||||
| /** | |||||
| * Convienence method to copy a file from a source to a | |||||
| * destination specifying if token filtering must be used and if | |||||
| * source files may overwrite newer destination files. | |||||
| * | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void copyFile(File sourceFile, File destFile, FilterSet filterSet, | |||||
| boolean overwrite) throws IOException { | |||||
| copyFile(sourceFile, destFile, filterSet, overwrite, false); | |||||
| } | |||||
| /** | |||||
| * Convienence method to copy a file from a source to a | |||||
| * destination specifying if token filtering must be used, if | |||||
| * source files may overwrite newer destination files and the | |||||
| * last modified time of <code>destFile</code> file should be made equal | |||||
| * to the last modified time of <code>sourceFile</code>. | |||||
| * | |||||
| * @throws IOException | |||||
| */ | |||||
| public static void copyFile(File sourceFile, File destFile, FilterSet filterSet, | |||||
| boolean overwrite, boolean preserveLastModified) | |||||
| throws IOException { | |||||
| if (overwrite || !destFile.exists() || | |||||
| destFile.lastModified() < sourceFile.lastModified()) { | |||||
| if (destFile.exists() && destFile.isFile()) { | |||||
| destFile.delete(); | |||||
| } | |||||
| // ensure that parent dir of dest file exists! | |||||
| // not using getParentFile method to stay 1.1 compat | |||||
| File parent = new File(destFile.getParent()); | |||||
| if (!parent.exists()) { | |||||
| parent.mkdirs(); | |||||
| } | |||||
| if (filterSet != null) { | |||||
| BufferedReader in = new BufferedReader(new FileReader(sourceFile)); | |||||
| BufferedWriter out = new BufferedWriter(new FileWriter(destFile)); | |||||
| int length; | |||||
| String newline = null; | |||||
| String line = in.readLine(); | |||||
| while (line != null) { | |||||
| if (line.length() == 0) { | |||||
| out.newLine(); | |||||
| } else { | |||||
| newline = filterSet.replaceTokens(line); | |||||
| out.write(newline); | |||||
| out.newLine(); | |||||
| } | |||||
| line = in.readLine(); | |||||
| } | |||||
| out.close(); | |||||
| in.close(); | |||||
| } else { | |||||
| FileInputStream in = new FileInputStream(sourceFile); | |||||
| FileOutputStream out = new FileOutputStream(destFile); | |||||
| byte[] buffer = new byte[8 * 1024]; | |||||
| int count = 0; | |||||
| do { | |||||
| out.write(buffer, 0, count); | |||||
| count = in.read(buffer, 0, buffer.length); | |||||
| } while (count != -1); | |||||
| in.close(); | |||||
| out.close(); | |||||
| } | |||||
| if (preserveLastModified) { | |||||
| setFileLastModified(destFile, sourceFile.lastModified()); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Calls File.setLastModified(long time) in a Java 1.1 compatible way. | |||||
| */ | |||||
| public static void setFileLastModified(File file, long time) throws BuildException { | |||||
| if (Project.getJavaVersion() == Project.JAVA_1_1) { | |||||
| return; | |||||
| } | |||||
| if (setLastModified == null) { | |||||
| synchronized (lockReflection) { | |||||
| if (setLastModified == null) { | |||||
| try { | |||||
| setLastModified = | |||||
| java.io.File.class.getMethod("setLastModified", | |||||
| new Class[] {Long.TYPE}); | |||||
| } catch (NoSuchMethodException nse) { | |||||
| throw new BuildException("File.setlastModified not in JDK > 1.1?", | |||||
| nse); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| Long[] times = new Long[1]; | |||||
| if (time < 0) { | |||||
| times[0] = new Long(System.currentTimeMillis()); | |||||
| } else { | |||||
| times[0] = new Long(time); | |||||
| } | |||||
| try { | |||||
| setLastModified.invoke(file, times); | |||||
| } catch (java.lang.reflect.InvocationTargetException ite) { | |||||
| Throwable nested = ite.getTargetException(); | |||||
| throw new BuildException("Exception setting the modification time " | |||||
| + "of " + file, nested); | |||||
| } catch (Throwable other) { | |||||
| throw new BuildException("Exception setting the modification time " | |||||
| + "of " + file, other); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -58,6 +58,8 @@ import java.io.*; | |||||
| import java.util.*; | import java.util.*; | ||||
| import java.text.*; | import java.text.*; | ||||
| import org.apache.tools.ant.types.FilterSet; | |||||
| /** | /** | ||||
| * Central representation of an Ant project. This class defines a | * Central representation of an Ant project. This class defines a | ||||
| * Ant project with all of it's targets and tasks. It also provides | * Ant project with all of it's targets and tasks. It also provides | ||||
| @@ -91,8 +93,8 @@ public class Project { | |||||
| public static final String JAVA_1_3 = "1.3"; | public static final String JAVA_1_3 = "1.3"; | ||||
| public static final String JAVA_1_4 = "1.4"; | public static final String JAVA_1_4 = "1.4"; | ||||
| public static final String TOKEN_START = "@"; | |||||
| public static final String TOKEN_END = "@"; | |||||
| public static final String TOKEN_START = FilterSet.DEFAULT_TOKEN_START; | |||||
| public static final String TOKEN_END = FilterSet.DEFAULT_TOKEN_END; | |||||
| private String name; | private String name; | ||||
| @@ -103,14 +105,11 @@ public class Project { | |||||
| private Hashtable dataClassDefinitions = new Hashtable(); | private Hashtable dataClassDefinitions = new Hashtable(); | ||||
| private Hashtable taskClassDefinitions = new Hashtable(); | private Hashtable taskClassDefinitions = new Hashtable(); | ||||
| private Hashtable targets = new Hashtable(); | private Hashtable targets = new Hashtable(); | ||||
| private Hashtable filters = new Hashtable(); | |||||
| private FilterSet globalFilterSet = new FilterSet(); | |||||
| private File baseDir; | private File baseDir; | ||||
| private Vector listeners = new Vector(); | private Vector listeners = new Vector(); | ||||
| private static java.lang.reflect.Method setLastModified = null; | |||||
| private static Object lockReflection = new Object(); | |||||
| /** The system classloader - may be null */ | /** The system classloader - may be null */ | ||||
| private ClassLoader systemLoader = null; | private ClassLoader systemLoader = null; | ||||
| @@ -254,6 +253,12 @@ public class Project { | |||||
| fireMessageLogged(target, msg, msgLevel); | fireMessageLogged(target, msg, msgLevel); | ||||
| } | } | ||||
| public FilterSet getGlobalFilterSet() { | |||||
| return globalFilterSet; | |||||
| } | |||||
| public void setProperty(String name, String value) { | public void setProperty(String name, String value) { | ||||
| // command line properties take precedence | // command line properties take precedence | ||||
| if (null != userProperties.get(name)) { | if (null != userProperties.get(name)) { | ||||
| @@ -315,15 +320,19 @@ public class Project { | |||||
| return name; | return name; | ||||
| } | } | ||||
| /** @deprecated */ | |||||
| public void addFilter(String token, String value) { | public void addFilter(String token, String value) { | ||||
| if (token == null) return; | |||||
| log("Setting token to filter: " + token + " -> " | |||||
| + value, MSG_DEBUG); | |||||
| this.filters.put(token, value); | |||||
| if (token == null) { | |||||
| return; | |||||
| } | |||||
| globalFilterSet.addFilter(new FilterSet.Filter(token, value)); | |||||
| } | } | ||||
| /** @deprecated */ | |||||
| public Hashtable getFilters() { | public Hashtable getFilters() { | ||||
| return filters; | |||||
| // we need to build the hashtable dynamically | |||||
| return globalFilterSet.getFilterHash(); | |||||
| } | } | ||||
| // match basedir attribute in xml | // match basedir attribute in xml | ||||
| @@ -505,6 +514,9 @@ public class Project { | |||||
| } else { | } else { | ||||
| o = ctor.newInstance(new Object[] {this}); | o = ctor.newInstance(new Object[] {this}); | ||||
| } | } | ||||
| if (o instanceof ProjectComponent) { | |||||
| ((ProjectComponent)o).setProject(this); | |||||
| } | |||||
| String msg = " +DataType: " + typeName; | String msg = " +DataType: " + typeName; | ||||
| log (msg, MSG_DEBUG); | log (msg, MSG_DEBUG); | ||||
| return o; | return o; | ||||
| @@ -674,9 +686,11 @@ public class Project { | |||||
| * No filtering is performed. | * No filtering is performed. | ||||
| * | * | ||||
| * @throws IOException | * @throws IOException | ||||
| * | |||||
| * @deprecated | |||||
| */ | */ | ||||
| public void copyFile(String sourceFile, String destFile) throws IOException { | public void copyFile(String sourceFile, String destFile) throws IOException { | ||||
| copyFile(new File(sourceFile), new File(destFile), false); | |||||
| FileUtils.copyFile(sourceFile, destFile); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -686,9 +700,8 @@ public class Project { | |||||
| * @throws IOException | * @throws IOException | ||||
| */ | */ | ||||
| public void copyFile(String sourceFile, String destFile, boolean filtering) | public void copyFile(String sourceFile, String destFile, boolean filtering) | ||||
| throws IOException | |||||
| { | |||||
| copyFile(new File(sourceFile), new File(destFile), filtering); | |||||
| throws IOException { | |||||
| FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -700,8 +713,7 @@ public class Project { | |||||
| */ | */ | ||||
| public void copyFile(String sourceFile, String destFile, boolean filtering, | public void copyFile(String sourceFile, String destFile, boolean filtering, | ||||
| boolean overwrite) throws IOException { | boolean overwrite) throws IOException { | ||||
| copyFile(new File(sourceFile), new File(destFile), filtering, | |||||
| overwrite); | |||||
| FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null, overwrite); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -716,8 +728,8 @@ public class Project { | |||||
| public void copyFile(String sourceFile, String destFile, boolean filtering, | public void copyFile(String sourceFile, String destFile, boolean filtering, | ||||
| boolean overwrite, boolean preserveLastModified) | boolean overwrite, boolean preserveLastModified) | ||||
| throws IOException { | throws IOException { | ||||
| copyFile(new File(sourceFile), new File(destFile), filtering, | |||||
| overwrite, preserveLastModified); | |||||
| FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null, | |||||
| overwrite, preserveLastModified); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -727,7 +739,7 @@ public class Project { | |||||
| * @throws IOException | * @throws IOException | ||||
| */ | */ | ||||
| public void copyFile(File sourceFile, File destFile) throws IOException { | public void copyFile(File sourceFile, File destFile) throws IOException { | ||||
| copyFile(sourceFile, destFile, false); | |||||
| FileUtils.copyFile(sourceFile, destFile); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -738,7 +750,7 @@ public class Project { | |||||
| */ | */ | ||||
| public void copyFile(File sourceFile, File destFile, boolean filtering) | public void copyFile(File sourceFile, File destFile, boolean filtering) | ||||
| throws IOException { | throws IOException { | ||||
| copyFile(sourceFile, destFile, filtering, false); | |||||
| FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -750,7 +762,7 @@ public class Project { | |||||
| */ | */ | ||||
| public void copyFile(File sourceFile, File destFile, boolean filtering, | public void copyFile(File sourceFile, File destFile, boolean filtering, | ||||
| boolean overwrite) throws IOException { | boolean overwrite) throws IOException { | ||||
| copyFile(sourceFile, destFile, filtering, overwrite, false); | |||||
| FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null, overwrite); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -765,63 +777,8 @@ public class Project { | |||||
| public void copyFile(File sourceFile, File destFile, boolean filtering, | public void copyFile(File sourceFile, File destFile, boolean filtering, | ||||
| boolean overwrite, boolean preserveLastModified) | boolean overwrite, boolean preserveLastModified) | ||||
| throws IOException { | throws IOException { | ||||
| if (overwrite || !destFile.exists() || | |||||
| destFile.lastModified() < sourceFile.lastModified()) { | |||||
| if (destFile.exists() && destFile.isFile()) { | |||||
| destFile.delete(); | |||||
| } | |||||
| log("Copy: " + sourceFile.getAbsolutePath() + " -> " | |||||
| + destFile.getAbsolutePath(), MSG_VERBOSE); | |||||
| // ensure that parent dir of dest file exists! | |||||
| // not using getParentFile method to stay 1.1 compat | |||||
| File parent = new File(destFile.getParent()); | |||||
| if (!parent.exists()) { | |||||
| parent.mkdirs(); | |||||
| } | |||||
| if (filtering) { | |||||
| BufferedReader in = new BufferedReader(new FileReader(sourceFile)); | |||||
| BufferedWriter out = new BufferedWriter(new FileWriter(destFile)); | |||||
| int length; | |||||
| String newline = null; | |||||
| String line = in.readLine(); | |||||
| while (line != null) { | |||||
| if (line.length() == 0) { | |||||
| out.newLine(); | |||||
| } else { | |||||
| newline = replace(line, filters); | |||||
| out.write(newline); | |||||
| out.newLine(); | |||||
| } | |||||
| line = in.readLine(); | |||||
| } | |||||
| out.close(); | |||||
| in.close(); | |||||
| } else { | |||||
| FileInputStream in = new FileInputStream(sourceFile); | |||||
| FileOutputStream out = new FileOutputStream(destFile); | |||||
| byte[] buffer = new byte[8 * 1024]; | |||||
| int count = 0; | |||||
| do { | |||||
| out.write(buffer, 0, count); | |||||
| count = in.read(buffer, 0, buffer.length); | |||||
| } while (count != -1); | |||||
| in.close(); | |||||
| out.close(); | |||||
| } | |||||
| if (preserveLastModified) { | |||||
| setFileLastModified(destFile, sourceFile.lastModified()); | |||||
| } | |||||
| } | |||||
| FileUtils.copyFile(sourceFile, destFile, filtering ? globalFilterSet : null, | |||||
| overwrite, preserveLastModified); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -833,82 +790,8 @@ public class Project { | |||||
| + " in JDK 1.1", Project.MSG_WARN); | + " in JDK 1.1", Project.MSG_WARN); | ||||
| return; | return; | ||||
| } | } | ||||
| if (setLastModified == null) { | |||||
| synchronized (lockReflection) { | |||||
| if (setLastModified == null) { | |||||
| try { | |||||
| setLastModified = | |||||
| java.io.File.class.getMethod("setLastModified", | |||||
| new Class[] {Long.TYPE}); | |||||
| } catch (NoSuchMethodException nse) { | |||||
| throw new BuildException("File.setlastModified not in JDK > 1.1?", | |||||
| nse); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| Long[] times = new Long[1]; | |||||
| if (time < 0) { | |||||
| times[0] = new Long(System.currentTimeMillis()); | |||||
| } else { | |||||
| times[0] = new Long(time); | |||||
| } | |||||
| try { | |||||
| log("Setting modification time for " + file, MSG_VERBOSE); | |||||
| setLastModified.invoke(file, times); | |||||
| } catch (java.lang.reflect.InvocationTargetException ite) { | |||||
| Throwable nested = ite.getTargetException(); | |||||
| throw new BuildException("Exception setting the modification time " | |||||
| + "of " + file, nested); | |||||
| } catch (Throwable other) { | |||||
| throw new BuildException("Exception setting the modification time " | |||||
| + "of " + file, other); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Does replacement on the given string using the given token table. | |||||
| * | |||||
| * @returns the string with the token replaced. | |||||
| */ | |||||
| private String replace(String s, Hashtable tokens) { | |||||
| int index = s.indexOf(TOKEN_START); | |||||
| if (index > -1) { | |||||
| try { | |||||
| StringBuffer b = new StringBuffer(); | |||||
| int i = 0; | |||||
| String token = null; | |||||
| String value = null; | |||||
| do { | |||||
| int endIndex = s.indexOf(TOKEN_END, | |||||
| index + TOKEN_START.length() + 1); | |||||
| if (endIndex == -1) { | |||||
| break; | |||||
| } | |||||
| token = s.substring(index + TOKEN_START.length(), endIndex); | |||||
| b.append(s.substring(i, index)); | |||||
| if (tokens.containsKey(token)) { | |||||
| value = (String) tokens.get(token); | |||||
| log("Replacing: " + TOKEN_START + token + TOKEN_END + " -> " + value, MSG_VERBOSE); | |||||
| b.append(value); | |||||
| i = index + TOKEN_START.length() + token.length() + TOKEN_END.length(); | |||||
| } else { | |||||
| // just append TOKEN_START and search further | |||||
| b.append(TOKEN_START); | |||||
| i = index + TOKEN_START.length(); | |||||
| } | |||||
| } while ((index = s.indexOf(TOKEN_START, i)) > -1); | |||||
| b.append(s.substring(i)); | |||||
| return b.toString(); | |||||
| } catch (StringIndexOutOfBoundsException e) { | |||||
| return s; | |||||
| } | |||||
| } else { | |||||
| return s; | |||||
| } | |||||
| FileUtils.setFileLastModified(file, time); | |||||
| log("Setting modification time for " + file, MSG_VERBOSE); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -73,6 +73,7 @@ import java.util.*; | |||||
| * | * | ||||
| * @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com</a> | * @author Glenn McAllister <a href="mailto:glennm@ca.ibm.com">glennm@ca.ibm.com</a> | ||||
| * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a> | ||||
| * @author <A href="gholam@xtra.co.nz">Michael McCallum</A> | |||||
| */ | */ | ||||
| public class Copy extends Task { | public class Copy extends Task { | ||||
| protected File file = null; // the source file | protected File file = null; // the source file | ||||
| @@ -91,7 +92,8 @@ public class Copy extends Task { | |||||
| protected Hashtable dirCopyMap = new Hashtable(); | protected Hashtable dirCopyMap = new Hashtable(); | ||||
| protected Mapper mapperElement = null; | protected Mapper mapperElement = null; | ||||
| private Vector filterSets = new Vector(); | |||||
| /** | /** | ||||
| * Sets a single source file to copy. | * Sets a single source file to copy. | ||||
| */ | */ | ||||
| @@ -113,6 +115,15 @@ public class Copy extends Task { | |||||
| this.destDir = destDir; | this.destDir = destDir; | ||||
| } | } | ||||
| /** | |||||
| * Create a nested filterset | |||||
| */ | |||||
| public FilterSet createFilterSet() { | |||||
| FilterSet filterSet = new FilterSet(); | |||||
| filterSets.addElement(filterSet); | |||||
| return filterSet; | |||||
| } | |||||
| /** | /** | ||||
| * Give the copied files the same last modified time as the original files. | * Give the copied files the same last modified time as the original files. | ||||
| */ | */ | ||||
| @@ -120,6 +131,15 @@ public class Copy extends Task { | |||||
| preserveLastModified = Project.toBoolean(preserve); | preserveLastModified = Project.toBoolean(preserve); | ||||
| } | } | ||||
| /** | |||||
| * Get the filtersets being applied to this operation. | |||||
| * | |||||
| * @return a vector of FilterSet objects | |||||
| */ | |||||
| protected Vector getFilterSets() { | |||||
| return filterSets; | |||||
| } | |||||
| /** | /** | ||||
| * Sets filtering. | * Sets filtering. | ||||
| */ | */ | ||||
| @@ -338,11 +358,15 @@ public class Copy extends Task { | |||||
| try { | try { | ||||
| log("Copying " + fromFile + " to " + toFile, verbosity); | log("Copying " + fromFile + " to " + toFile, verbosity); | ||||
| project.copyFile(fromFile, | |||||
| toFile, | |||||
| filtering, | |||||
| forceOverwrite, | |||||
| preserveLastModified); | |||||
| FilterSet executionFilterSet = new FilterSet(); | |||||
| if (filtering) { | |||||
| executionFilterSet.addFilterSet(project.getGlobalFilterSet()); | |||||
| } | |||||
| for (Enumeration filterEnum = filterSets.elements(); filterEnum.hasMoreElements();) { | |||||
| executionFilterSet.addFilterSet((FilterSet)filterEnum.nextElement()); | |||||
| } | |||||
| FileUtils.copyFile(fromFile, toFile, executionFilterSet, | |||||
| forceOverwrite, preserveLastModified); | |||||
| } catch (IOException ioe) { | } catch (IOException ioe) { | ||||
| String msg = "Failed to copy " + fromFile + " to " + toFile | String msg = "Failed to copy " + fromFile + " to " + toFile | ||||
| + " due to " + ioe.getMessage(); | + " due to " + ioe.getMessage(); | ||||
| @@ -100,7 +100,17 @@ public class Move extends Copy { | |||||
| try { | try { | ||||
| log("Moving " + fromFile + " to " + toFile, verbosity); | log("Moving " + fromFile + " to " + toFile, verbosity); | ||||
| project.copyFile(fromFile, toFile, filtering, forceOverwrite); | |||||
| FilterSet executionFilterSet = new FilterSet(); | |||||
| if (filtering) { | |||||
| executionFilterSet.addFilterSet(project.getGlobalFilterSet()); | |||||
| } | |||||
| for (Enumeration filterEnum = getFilterSets().elements(); filterEnum.hasMoreElements();) { | |||||
| executionFilterSet.addFilterSet((FilterSet)filterEnum.nextElement()); | |||||
| } | |||||
| FileUtils.copyFile(fromFile, toFile, executionFilterSet, | |||||
| forceOverwrite); | |||||
| File f = new File(fromFile); | File f = new File(fromFile); | ||||
| if (!f.delete()) { | if (!f.delete()) { | ||||
| throw new BuildException("Unable to delete file " + f.getAbsolutePath()); | throw new BuildException("Unable to delete file " + f.getAbsolutePath()); | ||||
| @@ -0,0 +1,417 @@ | |||||
| /* | |||||
| * The Apache Software License, Version 1.1 | |||||
| * | |||||
| * Copyright (c) 1999 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 apache@apache.org. | |||||
| * | |||||
| * 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 org.apache.tools.ant.types; | |||||
| // java io classes | |||||
| import java.io.File; | |||||
| import java.io.FileInputStream; | |||||
| import java.io.IOException; | |||||
| // java util classes | |||||
| import java.util.Enumeration; | |||||
| import java.util.Hashtable; | |||||
| import java.util.Properties; | |||||
| import java.util.Vector; | |||||
| // ant classes | |||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Project; | |||||
| import org.apache.tools.ant.Task; | |||||
| /** | |||||
| * A set of filters to be applied to something. | |||||
| * | |||||
| * A filter set may have starttoken and endtokens defined. | |||||
| * | |||||
| * @author <A href="mailto:gholam@xtra.co.nz"> Michael McCallum </A> | |||||
| * @created 14 March 2001 | |||||
| */ | |||||
| public class FilterSet extends DataType { | |||||
| /** | |||||
| * Individual filter component of filterset | |||||
| * | |||||
| * @author Michael McCallum | |||||
| * @created 14 March 2001 | |||||
| */ | |||||
| public static class Filter { | |||||
| /** Token which will be replaced in the filter operation */ | |||||
| String token; | |||||
| /** The value which will replace the token in the filtering operation */ | |||||
| String value; | |||||
| /** | |||||
| * Constructor for the Filter object | |||||
| * | |||||
| * @param token The token which will be replaced when filtering | |||||
| * @param value The value which will replace the token when filtering | |||||
| */ | |||||
| public Filter(String token, String value) { | |||||
| this.token = token; | |||||
| this.value = value; | |||||
| } | |||||
| /** | |||||
| * No argument conmstructor | |||||
| */ | |||||
| public Filter() { | |||||
| } | |||||
| /** | |||||
| * Sets the Token attribute of the Filter object | |||||
| * | |||||
| * @param token The new Token value | |||||
| */ | |||||
| public void setToken( String token ) { | |||||
| this.token = token; | |||||
| } | |||||
| /** | |||||
| * Sets the Value attribute of the Filter object | |||||
| * | |||||
| * @param value The new Value value | |||||
| */ | |||||
| public void setValue( String value ) { | |||||
| this.value = value; | |||||
| } | |||||
| /** | |||||
| * Gets the Token attribute of the Filter object | |||||
| * | |||||
| * @return The Token value | |||||
| */ | |||||
| public String getToken() { | |||||
| return token; | |||||
| } | |||||
| /** | |||||
| * Gets the Value attribute of the Filter object | |||||
| * | |||||
| * @return The Value value | |||||
| */ | |||||
| public String getValue() { | |||||
| return value; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * The filtersfile nested element. | |||||
| * | |||||
| * @author Michael McCallum | |||||
| * @created Thursday, April 19, 2001 | |||||
| */ | |||||
| public class FiltersFile { | |||||
| /** | |||||
| * Constructor for the Filter object | |||||
| */ | |||||
| public FiltersFile() { | |||||
| } | |||||
| /** | |||||
| * Sets the file from which filters will be read. | |||||
| * | |||||
| * @param file the file from which filters will be read. | |||||
| */ | |||||
| public void setFile(File file) { | |||||
| readFiltersFromFile(file); | |||||
| } | |||||
| } | |||||
| /** The default token start string */ | |||||
| public static final String DEFAULT_TOKEN_START = "@"; | |||||
| /** The default token end string */ | |||||
| public static final String DEFAULT_TOKEN_END = "@"; | |||||
| private String startOftoken = DEFAULT_TOKEN_START; | |||||
| private String endOftoken = DEFAULT_TOKEN_END; | |||||
| /** | |||||
| * List of ordered filters and filter files. | |||||
| */ | |||||
| private Vector filters = new Vector(); | |||||
| public FilterSet() { | |||||
| } | |||||
| /** | |||||
| * Create a Filterset from another filterset | |||||
| * | |||||
| * @param filterset the filterset upon which this filterset will be based. | |||||
| */ | |||||
| protected FilterSet(FilterSet filterset) { | |||||
| super(); | |||||
| this.filters = (Vector)filterset.getFilters().clone(); | |||||
| } | |||||
| protected Vector getFilters() { | |||||
| if (isReference()) { | |||||
| return getRef().getFilters(); | |||||
| } | |||||
| return filters; | |||||
| } | |||||
| protected FilterSet getRef() { | |||||
| return (FilterSet)getCheckedRef(FilterSet.class, "filterset"); | |||||
| } | |||||
| /** | |||||
| * Gets the filter hash of the FilterSet. | |||||
| * | |||||
| * @return The hash of the tokens and values for quick lookup. | |||||
| */ | |||||
| public Hashtable getFilterHash() { | |||||
| int filterSize = getFilters().size(); | |||||
| Hashtable filterHash = new Hashtable(filterSize); | |||||
| for (Enumeration e = getFilters().elements(); e.hasMoreElements();) { | |||||
| Filter filter = (Filter) e.nextElement(); | |||||
| filterHash.put(filter.getToken(), filter.getValue()); | |||||
| } | |||||
| return filterHash; | |||||
| } | |||||
| /** | |||||
| * set the file containing the filters for this filterset. | |||||
| * | |||||
| * @param filtersFile sets the filter fil to read filters for this filter set from. | |||||
| * @exception BuildException if there is a problem reading the filters | |||||
| */ | |||||
| public void setFiltersfile(File filtersFile) throws BuildException { | |||||
| if (isReference()) { | |||||
| throw tooManyAttributes(); | |||||
| } | |||||
| readFiltersFromFile(filtersFile); | |||||
| } | |||||
| /** | |||||
| * The string used to id the beginning of a token. | |||||
| * | |||||
| * @param startOfToken The new Begintoken value | |||||
| */ | |||||
| public void setBeginToken(String startOfToken) { | |||||
| if (isReference()) { | |||||
| throw tooManyAttributes(); | |||||
| } | |||||
| startOftoken = startOfToken; | |||||
| } | |||||
| /** | |||||
| * The string used to id the end of a token. | |||||
| * | |||||
| * @param endOfToken The new Endtoken value | |||||
| */ | |||||
| public void setEndToken( String endOfToken ) { | |||||
| if (isReference()) { | |||||
| throw tooManyAttributes(); | |||||
| } | |||||
| endOftoken = endOfToken; | |||||
| } | |||||
| /** | |||||
| * Read the filters from the given file. | |||||
| * | |||||
| * @param filtersFile the file from which filters are read | |||||
| * @exception BuildException Throw a build exception when unable to read the | |||||
| * file. | |||||
| */ | |||||
| public void readFiltersFromFile(File filtersFile) throws BuildException { | |||||
| if (filtersFile.isFile()) { | |||||
| log("Reading filters from " + filtersFile, Project.MSG_VERBOSE ); | |||||
| FileInputStream in = null; | |||||
| try { | |||||
| Properties props = new Properties(); | |||||
| in = new FileInputStream(filtersFile); | |||||
| props.load(in); | |||||
| Enumeration enum = props.propertyNames(); | |||||
| Vector filters = getFilters(); | |||||
| while (enum.hasMoreElements()) { | |||||
| String strPropName = (String) enum.nextElement(); | |||||
| String strValue = props.getProperty(strPropName); | |||||
| filters.addElement(new Filter(strPropName, strValue)); | |||||
| } | |||||
| } | |||||
| catch (Exception e) { | |||||
| throw new BuildException( "Could not read filters from file: " + filtersFile ); | |||||
| } | |||||
| finally { | |||||
| if ( in != null ) { | |||||
| try { | |||||
| in.close(); | |||||
| } | |||||
| catch (IOException ioex) { | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| throw new BuildException( "Must specify a file not a directory in the filtersfile attribute:" + filtersFile ); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Does replacement on the given string with token matching. | |||||
| * This uses the defined starttoken and endtoken values which default to @ for both. | |||||
| * | |||||
| * @param line The line to process the tokens in. | |||||
| * @return The string with the tokens replaced. | |||||
| */ | |||||
| public String replaceTokens(String line) { | |||||
| int index = line.indexOf(startOftoken); | |||||
| if (index > -1) { | |||||
| Hashtable tokens = getFilterHash(); | |||||
| try { | |||||
| StringBuffer b = new StringBuffer(); | |||||
| int i = 0; | |||||
| String token = null; | |||||
| String value = null; | |||||
| do { | |||||
| int endIndex = line.indexOf(endOftoken, index + startOftoken.length() + 1 ); | |||||
| if (endIndex == -1) { | |||||
| break; | |||||
| } | |||||
| token = line.substring(index + startOftoken.length(), endIndex ); | |||||
| b.append(line.substring(i, index)); | |||||
| if (tokens.containsKey(token)) { | |||||
| value = (String)tokens.get(token); | |||||
| log( "Replacing: " + startOftoken + token + endOftoken + " -> " + value, Project.MSG_VERBOSE ); | |||||
| b.append(value); | |||||
| i = index + startOftoken.length() + token.length() + endOftoken.length(); | |||||
| } | |||||
| else { | |||||
| // just append startOftoken and search further | |||||
| b.append(startOftoken); | |||||
| i = index + startOftoken.length(); | |||||
| } | |||||
| } while ((index = line.indexOf( startOftoken, i )) > -1 ); | |||||
| b.append(line.substring(i)); | |||||
| return b.toString(); | |||||
| } | |||||
| catch (StringIndexOutOfBoundsException e) { | |||||
| return line; | |||||
| } | |||||
| } | |||||
| else { | |||||
| return line; | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Create a new filter | |||||
| * | |||||
| * @param the filter to be added | |||||
| */ | |||||
| public void addFilter(Filter filter) { | |||||
| if (isReference()) { | |||||
| throw noChildrenAllowed(); | |||||
| } | |||||
| filters.addElement(filter); | |||||
| } | |||||
| /** | |||||
| * Create a new FiltersFile | |||||
| * | |||||
| * @return The filter that was created. | |||||
| */ | |||||
| public FiltersFile createFiltersfile() { | |||||
| if (isReference()) { | |||||
| throw noChildrenAllowed(); | |||||
| } | |||||
| return new FiltersFile(); | |||||
| } | |||||
| /** | |||||
| * Add a new filter made from the given token and value. | |||||
| * | |||||
| * @param token The token for the new filter. | |||||
| * @param value The value for the new filter. | |||||
| */ | |||||
| public void addFilter(String token, String value) { | |||||
| if (isReference()) { | |||||
| throw noChildrenAllowed(); | |||||
| } | |||||
| filters.addElement(new Filter(token, value)); | |||||
| } | |||||
| /** | |||||
| * Add a Filterset to this filter set | |||||
| * | |||||
| * @param filterSet the filterset to be added to this filterset | |||||
| */ | |||||
| public void addFilterSet(FilterSet filterSet) { | |||||
| if (isReference()) { | |||||
| throw noChildrenAllowed(); | |||||
| } | |||||
| for (Enumeration e = filterSet.getFilters().elements(); e.hasMoreElements();) { | |||||
| filters.addElement((Filter)e.nextElement()); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Test to see if this filter set it empty. | |||||
| * | |||||
| * @return Return true if there are filter in this set otherwise false. | |||||
| */ | |||||
| public boolean hasFilters() { | |||||
| return getFilters().size() > 0; | |||||
| } | |||||
| } | |||||
| @@ -2,3 +2,5 @@ path=org.apache.tools.ant.types.Path | |||||
| fileset=org.apache.tools.ant.types.FileSet | fileset=org.apache.tools.ant.types.FileSet | ||||
| patternset=org.apache.tools.ant.types.PatternSet | patternset=org.apache.tools.ant.types.PatternSet | ||||
| mapper=org.apache.tools.ant.types.Mapper | mapper=org.apache.tools.ant.types.Mapper | ||||
| filterset=org.apache.tools.ant.types.FilterSet | |||||