or end of a file. Discussion started at http://marc.theaimsgroup.com/?l=ant-user&m=106336791228585&w=2 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275260 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -604,6 +604,10 @@ Other changes: | |||
| used to checkout/list files based on a date instead of a label. | |||
| Bugzilla Report 20578. | |||
| * New filter <concatfilter>. Adds the content of file at the beginning | |||
| or end of a file. Discussion started at | |||
| http://marc.theaimsgroup.com/?l=ant-user&m=106336791228585&w=2 | |||
| Changes from Ant 1.5.3 to Ant 1.5.4 | |||
| =================================== | |||
| @@ -0,0 +1,103 @@ | |||
| <?xml version="1.0"?> | |||
| <project default="cleanup" basedir="."> | |||
| <target name="init"> | |||
| <mkdir dir="result" /> | |||
| <echo file="result/before.txt" message="this-should-be-the-first-line${line.separator}"/> | |||
| <echo file="result/after.txt" message="this-should-be-the-last-line${line.separator}"/> | |||
| <copy file="input/head-tail.test" tofile="input/concatfilter.test"/> | |||
| <fixcrlf srcDir="input" includes="concatfilter.test"/> | |||
| </target> | |||
| <target name="cleanup"> | |||
| <delete dir="result"/> | |||
| <delete> | |||
| <fileset dir="input" includes="concatfilter.test"/> | |||
| </delete> | |||
| </target> | |||
| <target name="testFilterReaderNoArgs" depends="init"> | |||
| <copy file="input/concatfilter.test" | |||
| tofile="result/concat.filterReaderNoArgs.test"> | |||
| <filterchain> | |||
| <filterreader classname="org.apache.tools.ant.filters.ConcatFilter"/> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="testFilterReaderBefore" depends="init"> | |||
| <copy file="input/concatfilter.test" | |||
| tofile="result/concat.filterReaderBefore.test"> | |||
| <filterchain> | |||
| <filterreader classname="org.apache.tools.ant.filters.ConcatFilter"> | |||
| <param name="before" value="result/before.txt"/> | |||
| </filterreader> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="testFilterReaderAfter" depends="init"> | |||
| <copy file="input/concatfilter.test" | |||
| tofile="result/concat.filterReaderAfter.test"> | |||
| <filterchain> | |||
| <filterreader classname="org.apache.tools.ant.filters.ConcatFilter"> | |||
| <param name="after" value="result/after.txt"/> | |||
| </filterreader> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="testFilterReaderBeforeAfter" depends="init"> | |||
| <copy file="input/concatfilter.test" | |||
| tofile="result/concat.filterReaderBeforeAfter.test"> | |||
| <filterchain> | |||
| <filterreader classname="org.apache.tools.ant.filters.ConcatFilter"> | |||
| <param name="before" value="result/before.txt"/> | |||
| <param name="after" value="result/after.txt"/> | |||
| </filterreader> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="testConcatFilter" depends="init"> | |||
| <typedef name="concatfilter" classname="org.apache.tools.ant.filters.ConcatFilter"/> | |||
| <copy file="input/concatfilter.test" | |||
| tofile="result/concat.concatfilter.test"> | |||
| <filterchain> | |||
| <concatfilter/> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="testConcatFilterBefore" depends="init"> | |||
| <typedef name="concatfilter" classname="org.apache.tools.ant.filters.ConcatFilter"/> | |||
| <copy file="input/concatfilter.test" | |||
| tofile="result/concat.concatfilterBefore.test"> | |||
| <filterchain> | |||
| <concatfilter before="result/before.txt"/> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="testConcatFilterAfter" depends="init"> | |||
| <typedef name="concatfilter" classname="org.apache.tools.ant.filters.ConcatFilter"/> | |||
| <copy file="input/concatfilter.test" | |||
| tofile="result/concat.concatfilterAfter.test"> | |||
| <filterchain> | |||
| <concatfilter after="result/after.txt"/> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| <target name="testConcatFilterBeforeAfter" depends="init"> | |||
| <typedef name="concatfilter" classname="org.apache.tools.ant.filters.ConcatFilter"/> | |||
| <copy file="input/concatfilter.test" | |||
| tofile="result/concat.concatfilterBeforeAfter.test"> | |||
| <filterchain> | |||
| <concatfilter before="result/before.txt" after="result/after.txt"/> | |||
| </filterchain> | |||
| </copy> | |||
| </target> | |||
| </project> | |||
| @@ -0,0 +1,246 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 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 "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.filters; | |||
| import java.io.IOException; | |||
| import java.io.Reader; | |||
| import java.io.File; | |||
| import java.io.BufferedReader; | |||
| import java.io.FileReader; | |||
| import org.apache.tools.ant.types.Parameter; | |||
| /** | |||
| * Concats a file before and/or after the file. | |||
| * | |||
| * <p>Example:<pre> | |||
| * <copy todir="build"> | |||
| * <fileset dir="src" includes="*.java"/> | |||
| * <filterchain> | |||
| * <concatfilter before="apache-license-java.txt"/> | |||
| * </filterchain> | |||
| * </copy> | |||
| * </pre> | |||
| * Copies all java sources from <i>src</i> to <i>build</i> and adds the | |||
| * content of <i>apache-license-java.txt</i> add the beginning of each | |||
| * file.</p> | |||
| * | |||
| * @since 1.6 | |||
| * @version 2003-09-17 | |||
| * @author Jan Matèrne | |||
| */ | |||
| public final class ConcatFilter extends BaseParamFilterReader | |||
| implements ChainableReader { | |||
| /** File to add before the content. */ | |||
| private File before; | |||
| /** File to add after the content. */ | |||
| private File after; | |||
| /** Reader for before-file. */ | |||
| private Reader beforeReader = new EmptyReader(); | |||
| /** Reader for after-file. */ | |||
| private Reader afterReader = new EmptyReader(); | |||
| /** | |||
| * Constructor for "dummy" instances. | |||
| * | |||
| * @see BaseFilterReader#BaseFilterReader() | |||
| */ | |||
| public ConcatFilter() { | |||
| super(); | |||
| } | |||
| /** | |||
| * Creates a new filtered reader. | |||
| * | |||
| * @param in A Reader object providing the underlying stream. | |||
| * Must not be <code>null</code>. | |||
| */ | |||
| public ConcatFilter(final Reader in) { | |||
| super(in); | |||
| } | |||
| /** | |||
| * Returns the next character in the filtered stream. If the desired | |||
| * number of lines have already been read, the resulting stream is | |||
| * effectively at an end. Otherwise, the next character from the | |||
| * underlying stream is read and returned. | |||
| * | |||
| * @return the next character in the resulting stream, or -1 | |||
| * if the end of the resulting stream has been reached | |||
| * | |||
| * @exception IOException if the underlying stream throws an IOException | |||
| * during reading | |||
| */ | |||
| public int read() throws IOException { | |||
| // do the "singleton" initialization | |||
| if (!getInitialized()) { | |||
| initialize(); | |||
| setInitialized(true); | |||
| } | |||
| int ch = -1; | |||
| // The readers return -1 if they end. So simply read the "before" | |||
| // after that the "content" and at the end the "after" file. | |||
| ch = beforeReader.read(); | |||
| if (ch == -1) { | |||
| ch = super.read(); | |||
| } | |||
| if (ch == -1) { | |||
| ch = afterReader.read(); | |||
| } | |||
| return ch; | |||
| } | |||
| /** | |||
| * Sets <i>before</i> attribute. | |||
| * @param before new value | |||
| */ | |||
| public void setBefore(final File before) { | |||
| this.before = before; | |||
| } | |||
| /** | |||
| * Returns <i>before</i> attribute. | |||
| * @return before attribute | |||
| */ | |||
| public File getBefore() { | |||
| return before; | |||
| } | |||
| /** | |||
| * Sets <i>after</i> attribute. | |||
| * @param after new value | |||
| */ | |||
| public void setAfter(final File after) { | |||
| this.after = after; | |||
| } | |||
| /** | |||
| * Returns <i>after</i> attribute. | |||
| * @return after attribute | |||
| */ | |||
| public File getAfter() { | |||
| return after; | |||
| } | |||
| /** | |||
| * Creates a new ConcatReader using the passed in | |||
| * Reader for instantiation. | |||
| * | |||
| * @param rdr A Reader object providing the underlying stream. | |||
| * Must not be <code>null</code>. | |||
| * | |||
| * @return a new filter based on this configuration, but filtering | |||
| * the specified reader | |||
| */ | |||
| public Reader chain(final Reader rdr) { | |||
| ConcatFilter newFilter = new ConcatFilter(rdr); | |||
| newFilter.setBefore(getBefore()); | |||
| newFilter.setAfter(getAfter()); | |||
| // Usually the initialized is set to true. But here it must not. | |||
| // Because the before and after readers have to be instantiated | |||
| // on runtime | |||
| //newFilter.setInitialized(true); | |||
| return newFilter; | |||
| } | |||
| /** | |||
| * Scans the parameters list for the "lines" parameter and uses | |||
| * it to set the number of lines to be returned in the filtered stream. | |||
| * also scan for skip parameter. | |||
| */ | |||
| private void initialize() throws IOException { | |||
| // get parameters | |||
| Parameter[] params = getParameters(); | |||
| if (params != null) { | |||
| for (int i = 0; i < params.length; i++) { | |||
| if ("before".equals(params[i].getName())) { | |||
| setBefore(new File(params[i].getValue())); | |||
| continue; | |||
| } | |||
| if ("after".equals(params[i].getName())) { | |||
| setAfter(new File(params[i].getValue())); | |||
| continue; | |||
| } | |||
| } | |||
| } | |||
| if (before != null) { | |||
| if (!before.isAbsolute()) { | |||
| before = new File(getProject().getBaseDir(), before.getPath()); | |||
| } | |||
| beforeReader = new BufferedReader(new FileReader(before)); | |||
| } | |||
| if (after != null) { | |||
| if (!after.isAbsolute()) { | |||
| after = new File(getProject().getBaseDir(), after.getPath()); | |||
| } | |||
| afterReader = new BufferedReader(new FileReader(after)); | |||
| } | |||
| } | |||
| /** | |||
| * Reader which is always at the end of file. | |||
| * Used for easier algorithm (polymorphism instead if-cascades). | |||
| */ | |||
| private class EmptyReader extends Reader { | |||
| public int read(char[] ch, int i1, int i2) { return -1; } | |||
| public void close() { } | |||
| } | |||
| } | |||
| @@ -0,0 +1,195 @@ | |||
| /* | |||
| * The Apache Software License, Version 1.1 | |||
| * | |||
| * Copyright (c) 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 "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.filters; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import org.apache.tools.ant.BuildFileTest; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| /** | |||
| * JUnit Testcases for ConcatReader | |||
| * @author Jan Matèrne | |||
| */ | |||
| public class ConcatFilterTest extends BuildFileTest { | |||
| private static FileUtils fu = FileUtils.newFileUtils(); | |||
| private static final String lSep = System.getProperty("line.separator"); | |||
| private static final String FILE_BEGINNING_WITH = | |||
| "this-should-be-the-first-line" + lSep | |||
| + "Line 1" + lSep | |||
| + "Line 2" + lSep | |||
| + "Line 3" + lSep | |||
| + "Line 4" + lSep | |||
| ; | |||
| private static final String FILE_BEGINNING = | |||
| "Line 1" + lSep | |||
| + "Line 2" + lSep | |||
| + "Line 3" + lSep | |||
| + "Line 4" + lSep | |||
| + "Line 5" + lSep | |||
| ; | |||
| private static final String FILE_ENDING_WITH = | |||
| "Line 57" + lSep | |||
| + "Line 58" + lSep | |||
| + "Line 59" + lSep | |||
| + "Line 60" + lSep | |||
| + "this-should-be-the-last-line" + lSep | |||
| ; | |||
| private static final String FILE_ENDING = | |||
| "Line 56" + lSep | |||
| + "Line 57" + lSep | |||
| + "Line 58" + lSep | |||
| + "Line 59" + lSep | |||
| + "Line 60" + lSep | |||
| ; | |||
| public ConcatFilterTest(String name) { | |||
| super(name); | |||
| } | |||
| public void setUp() { | |||
| configureProject("src/etc/testcases/filters/concat.xml"); | |||
| } | |||
| public void tearDown() { | |||
| // I dont know why - but on my machine I always get a | |||
| // "Unable to delete file ...result\after.txt" (or before.txt) | |||
| // from Delete.removeDir(Delete.java:612). | |||
| // Win2000, JDK 1.4.1_02 | |||
| // A <sleep> before <delete> doesn´t work. From 10ms to 3000ms. | |||
| // I modified the taskdefs.Delete.DELETE_RETRY_SLEEP_MILLIS | |||
| // from 10 up to 2000 ms, but no success. | |||
| // So I give up - and hope for a suggestion from another one. | |||
| // But this shouldn´t let the testcases fail, so I do the cleanup | |||
| // inside a try-block | |||
| // Jan | |||
| try { | |||
| executeTarget("cleanup"); | |||
| } catch (Exception e) { | |||
| e.printStackTrace(); | |||
| } | |||
| } | |||
| public void testFilterReaderNoArgs() throws IOException { | |||
| executeTarget("testFilterReaderNoArgs"); | |||
| File expected = getProject().resolveFile("input/concatfilter.test"); | |||
| File result = getProject().resolveFile("result/concat.filterReaderNoArgs.test"); | |||
| assertTrue("testFilterReaderNoArgs: Result not like expected", fu.contentEquals(expected, result)); | |||
| } | |||
| public void testFilterReaderBefore() throws IOException { | |||
| executeTarget("testFilterReaderBefore"); | |||
| File resultFile = getProject().resolveFile("result/concat.filterReaderBefore.test"); | |||
| String resultContent = fu.readFully(new java.io.FileReader(resultFile)); | |||
| assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING_WITH)); | |||
| assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING)); | |||
| } | |||
| public void testFilterReaderAfter() throws IOException { | |||
| executeTarget("testFilterReaderAfter"); | |||
| File resultFile = getProject().resolveFile("result/concat.filterReaderAfter.test"); | |||
| String resultContent = fu.readFully(new java.io.FileReader(resultFile)); | |||
| assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING)); | |||
| assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING_WITH)); | |||
| } | |||
| public void testFilterReaderBeforeAfter() throws IOException { | |||
| executeTarget("testFilterReaderBeforeAfter"); | |||
| File resultFile = getProject().resolveFile("result/concat.filterReaderBeforeAfter.test"); | |||
| String resultContent = fu.readFully(new java.io.FileReader(resultFile)); | |||
| assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING_WITH)); | |||
| assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING_WITH)); | |||
| } | |||
| public void testConcatFilter() throws IOException { | |||
| executeTarget("testConcatFilter"); | |||
| File resultFile = getProject().resolveFile("result/concat.concatfilter.test"); | |||
| String resultContent = fu.readFully(new java.io.FileReader(resultFile)); | |||
| assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING)); | |||
| assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING)); | |||
| } | |||
| public void testConcatFilterBefore() throws IOException { | |||
| executeTarget("testConcatFilterBefore"); | |||
| File resultFile = getProject().resolveFile("result/concat.concatfilterBefore.test"); | |||
| String resultContent = fu.readFully(new java.io.FileReader(resultFile)); | |||
| assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING_WITH)); | |||
| assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING)); | |||
| } | |||
| public void testConcatFilterAfter() throws IOException { | |||
| executeTarget("testConcatFilterAfter"); | |||
| File resultFile = getProject().resolveFile("result/concat.concatfilterAfter.test"); | |||
| String resultContent = fu.readFully(new java.io.FileReader(resultFile)); | |||
| assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING)); | |||
| assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING_WITH)); | |||
| } | |||
| public void testConcatFilterBeforeAfter() throws IOException { | |||
| executeTarget("testConcatFilterBeforeAfter"); | |||
| File resultFile = getProject().resolveFile("result/concat.concatfilterBeforeAfter.test"); | |||
| String resultContent = fu.readFully(new java.io.FileReader(resultFile)); | |||
| assertTrue("First 5 lines differs.", resultContent.startsWith(FILE_BEGINNING_WITH)); | |||
| assertTrue("Last 5 lines differs.", resultContent.endsWith(FILE_ENDING_WITH)); | |||
| } | |||
| } | |||