https://bz.apache.org/bugzilla/show_bug.cgi?id=62379master
| @@ -48,6 +48,11 @@ Other changes: | |||
| generated. | |||
| Bugzilla Report 62379 | |||
| * The <includesfile> and <excludesfile> nested elements of | |||
| <patternset> and <fileset> now support an encoding attribute that | |||
| can be used to specify the file's encoding. | |||
| Bugzilla Report 62379 | |||
| Changes from Ant 1.9.10 TO Ant 1.9.11 | |||
| ===================================== | |||
| @@ -125,6 +125,11 @@ you can use to test the existence of a property.</p> | |||
| <b>not</b> set</a>.</td> | |||
| <td align="center" valign="top">No</td> | |||
| </tr> | |||
| <tr> | |||
| <td valign="top">encoding</td> | |||
| <td valign="top">The encoding of the file. <em>Since Ant 1.9.12</em></td> | |||
| <td valign="top" align="center">No, default is platform default</td> | |||
| </tr> | |||
| </table> | |||
| <h4><code>patternset</code></h4> | |||
| <p>Patternsets may be nested within one another, adding the nested | |||
| @@ -0,0 +1,40 @@ | |||
| <?xml version="1.0"?> | |||
| <!-- | |||
| Licensed to the Apache Software Foundation (ASF) under one or more | |||
| contributor license agreements. See the NOTICE file distributed with | |||
| this work for additional information regarding copyright ownership. | |||
| The ASF licenses this file to You under the Apache License, Version 2.0 | |||
| (the "License"); you may not use this file except in compliance with | |||
| the License. You may obtain a copy of the License at | |||
| http://www.apache.org/licenses/LICENSE-2.0 | |||
| Unless required by applicable law or agreed to in writing, software | |||
| distributed under the License is distributed on an "AS IS" BASIS, | |||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
| See the License for the specific language governing permissions and | |||
| limitations under the License. | |||
| --> | |||
| <project name="test"> | |||
| <target name="no-encoding"> | |||
| <echo file="${java.io.tmpdir}/foo">fileset.xml</echo> | |||
| <pathconvert targetos="unix" property="property"> | |||
| <fileset dir="${basedir}"> | |||
| <includesfile name="${java.io.tmpdir}/foo"/> | |||
| </fileset> | |||
| <map from="${basedir}" to="/abc"/> | |||
| </pathconvert> | |||
| <echo>${property}</echo> | |||
| </target> | |||
| <target name="encoding"> | |||
| <echo file="${java.io.tmpdir}/foo" encoding="UTF-16LE">fileset.xml</echo> | |||
| <pathconvert targetos="unix" property="property"> | |||
| <fileset dir="${basedir}"> | |||
| <includesfile name="${java.io.tmpdir}/foo" encoding="UTF-16LE"/> | |||
| </fileset> | |||
| <map from="${basedir}" to="/abc"/> | |||
| </pathconvert> | |||
| <echo>${property}</echo> | |||
| </target> | |||
| </project> | |||
| @@ -247,7 +247,7 @@ public class Delete extends MatchingTask { | |||
| /** | |||
| * add a name entry on the include files list | |||
| * @return a NameEntry object to be configured | |||
| * @return a PatternFileNameEntry object to be configured | |||
| */ | |||
| public PatternSet.NameEntry createIncludesFile() { | |||
| usedMatchingTask = true; | |||
| @@ -265,7 +265,7 @@ public class Delete extends MatchingTask { | |||
| /** | |||
| * add a name entry on the include files list | |||
| * @return a NameEntry object to be configured | |||
| * @return a PatternFileNameEntry object to be configured | |||
| */ | |||
| public PatternSet.NameEntry createExcludesFile() { | |||
| usedMatchingTask = true; | |||
| @@ -77,7 +77,7 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||
| /** | |||
| * add a name entry on the include files list | |||
| * @return an NameEntry object to be configured | |||
| * @return an PatternFileNameEntry object to be configured | |||
| */ | |||
| public PatternSet.NameEntry createIncludesFile() { | |||
| return fileset.createIncludesFile(); | |||
| @@ -93,7 +93,7 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||
| /** | |||
| * add a name entry on the include files list | |||
| * @return an NameEntry object to be configured | |||
| * @return an PatternFileNameEntry object to be configured | |||
| */ | |||
| public PatternSet.NameEntry createExcludesFile() { | |||
| return fileset.createExcludesFile(); | |||
| @@ -189,7 +189,7 @@ public abstract class AbstractFileSet extends DataType | |||
| /** | |||
| * Add a name entry to the include files list. | |||
| * @return <code>PatternSet.NameEntry</code>. | |||
| * @return <code>PatternSet.PatternFileNameEntry</code>. | |||
| */ | |||
| public synchronized PatternSet.NameEntry createIncludesFile() { | |||
| if (isReference()) { | |||
| @@ -213,7 +213,7 @@ public abstract class AbstractFileSet extends DataType | |||
| /** | |||
| * Add a name entry to the excludes files list. | |||
| * @return <code>PatternSet.NameEntry</code>. | |||
| * @return <code>PatternSet.PatternFileNameEntry</code>. | |||
| */ | |||
| public synchronized PatternSet.NameEntry createExcludesFile() { | |||
| if (isReference()) { | |||
| @@ -19,8 +19,10 @@ package org.apache.tools.ant.types; | |||
| import java.io.BufferedReader; | |||
| import java.io.File; | |||
| import java.io.FileInputStream; | |||
| import java.io.FileReader; | |||
| import java.io.IOException; | |||
| import java.io.InputStreamReader; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import java.util.StringTokenizer; | |||
| @@ -40,8 +42,8 @@ import org.apache.tools.ant.util.FileUtils; | |||
| public class PatternSet extends DataType implements Cloneable { | |||
| private List<NameEntry> includeList = new ArrayList<NameEntry>(); | |||
| private List<NameEntry> excludeList = new ArrayList<NameEntry>(); | |||
| private List<NameEntry> includesFileList = new ArrayList<NameEntry>(); | |||
| private List<NameEntry> excludesFileList = new ArrayList<NameEntry>(); | |||
| private List<PatternFileNameEntry> includesFileList = new ArrayList<PatternFileNameEntry>(); | |||
| private List<PatternFileNameEntry> excludesFileList = new ArrayList<PatternFileNameEntry>(); | |||
| /** | |||
| * inner class to hold a name on list. "If" and "Unless" attributes | |||
| @@ -176,6 +178,45 @@ public class PatternSet extends DataType implements Cloneable { | |||
| } | |||
| } | |||
| /** | |||
| * Adds encoding support to {@link NameEntry}. | |||
| * @since Ant 1.9.12 | |||
| */ | |||
| public class PatternFileNameEntry extends NameEntry { | |||
| private String encoding; | |||
| /** | |||
| * Encoding to use when reading the file, defaults to the platform's default | |||
| * encoding. | |||
| * | |||
| * <p> | |||
| * For a list of possible values see | |||
| * <a href="https://docs.oracle.com/javase/1.5.0/docs/guide/intl/encoding.doc.html"> | |||
| * https://docs.oracle.com/javase/1.5.0/docs/guide/intl/encoding.doc.html</a>. | |||
| * </p> | |||
| * | |||
| * @param encoding String | |||
| */ | |||
| public final void setEncoding(String encoding) { | |||
| this.encoding = encoding; | |||
| } | |||
| /** | |||
| * Encoding to use when reading the file, defaults to the platform's default | |||
| * encoding. | |||
| */ | |||
| public final String getEncoding() { | |||
| return encoding; | |||
| } | |||
| @Override | |||
| public String toString() { | |||
| String baseString = super.toString(); | |||
| return encoding == null ? baseString | |||
| : new StringBuilder(baseString).append(";encoding->").append(encoding).toString(); | |||
| } | |||
| } | |||
| private static final class InvertedPatternSet extends PatternSet { | |||
| private InvertedPatternSet(PatternSet p) { | |||
| setProject(p.getProject()); | |||
| @@ -255,7 +296,7 @@ public class PatternSet extends DataType implements Cloneable { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| return addPatternToList(includesFileList); | |||
| return addPatternFileToList(includesFileList); | |||
| } | |||
| /** | |||
| @@ -277,7 +318,7 @@ public class PatternSet extends DataType implements Cloneable { | |||
| if (isReference()) { | |||
| throw noChildrenAllowed(); | |||
| } | |||
| return addPatternToList(excludesFileList); | |||
| return addPatternFileToList(excludesFileList); | |||
| } | |||
| /** | |||
| @@ -325,6 +366,15 @@ public class PatternSet extends DataType implements Cloneable { | |||
| return result; | |||
| } | |||
| /** | |||
| * add a pattern file name entry to the given list | |||
| */ | |||
| private PatternFileNameEntry addPatternFileToList(List<PatternFileNameEntry> list) { | |||
| PatternFileNameEntry result = new PatternFileNameEntry(); | |||
| list.add(result); | |||
| return result; | |||
| } | |||
| /** | |||
| * Sets the name of the file containing the includes patterns. | |||
| * | |||
| @@ -355,13 +405,17 @@ public class PatternSet extends DataType implements Cloneable { | |||
| * Reads path matching patterns from a file and adds them to the | |||
| * includes or excludes list (as appropriate). | |||
| */ | |||
| private void readPatterns(File patternfile, List<NameEntry> patternlist, Project p) | |||
| private void readPatterns(File patternfile, String encoding, List<NameEntry> patternlist, Project p) | |||
| throws BuildException { | |||
| BufferedReader patternReader = null; | |||
| try { | |||
| // Get a FileReader | |||
| patternReader = new BufferedReader(new FileReader(patternfile)); | |||
| if (encoding == null) { | |||
| patternReader = new BufferedReader(new FileReader(patternfile)); | |||
| } else { | |||
| patternReader = new BufferedReader(new InputStreamReader(new FileInputStream(patternfile), encoding)); | |||
| } | |||
| // Create one NameEntry in the appropriate pattern list for each | |||
| // line in the file. | |||
| @@ -478,7 +532,7 @@ public class PatternSet extends DataType implements Cloneable { | |||
| */ | |||
| private void readFiles(Project p) { | |||
| if (includesFileList.size() > 0) { | |||
| for (NameEntry ne : includesFileList) { | |||
| for (PatternFileNameEntry ne : includesFileList) { | |||
| String fileName = ne.evalName(p); | |||
| if (fileName != null) { | |||
| File inclFile = p.resolveFile(fileName); | |||
| @@ -486,13 +540,13 @@ public class PatternSet extends DataType implements Cloneable { | |||
| throw new BuildException("Includesfile " + inclFile.getAbsolutePath() | |||
| + " not found."); | |||
| } | |||
| readPatterns(inclFile, includeList, p); | |||
| readPatterns(inclFile, ne.getEncoding(), includeList, p); | |||
| } | |||
| } | |||
| includesFileList.clear(); | |||
| } | |||
| if (excludesFileList.size() > 0) { | |||
| for (NameEntry ne : excludesFileList) { | |||
| for (PatternFileNameEntry ne : excludesFileList) { | |||
| String fileName = ne.evalName(p); | |||
| if (fileName != null) { | |||
| File exclFile = p.resolveFile(fileName); | |||
| @@ -500,7 +554,7 @@ public class PatternSet extends DataType implements Cloneable { | |||
| throw new BuildException("Excludesfile " + exclFile.getAbsolutePath() | |||
| + " not found."); | |||
| } | |||
| readPatterns(exclFile, excludeList, p); | |||
| readPatterns(exclFile, ne.getEncoding(), excludeList, p); | |||
| } | |||
| } | |||
| excludesFileList.clear(); | |||
| @@ -523,8 +577,8 @@ public class PatternSet extends DataType implements Cloneable { | |||
| PatternSet ps = (PatternSet) super.clone(); | |||
| ps.includeList = new ArrayList<NameEntry>(includeList); | |||
| ps.excludeList = new ArrayList<NameEntry>(excludeList); | |||
| ps.includesFileList = new ArrayList<NameEntry>(includesFileList); | |||
| ps.excludesFileList = new ArrayList<NameEntry>(excludesFileList); | |||
| ps.includesFileList = new ArrayList<PatternFileNameEntry>(includesFileList); | |||
| ps.excludesFileList = new ArrayList<PatternFileNameEntry>(excludesFileList); | |||
| return ps; | |||
| } catch (CloneNotSupportedException e) { | |||
| throw new BuildException(e); | |||
| @@ -124,7 +124,7 @@ public class Files extends AbstractSelectorContainer | |||
| /** | |||
| * Add a name entry to the include files list. | |||
| * @return <code>PatternSet.NameEntry</code>. | |||
| * @return <code>PatternSet.PatternFileNameEntry</code>. | |||
| */ | |||
| public synchronized PatternSet.NameEntry createIncludesFile() { | |||
| if (isReference()) { | |||
| @@ -148,7 +148,7 @@ public class Files extends AbstractSelectorContainer | |||
| /** | |||
| * Add a name entry to the excludes files list. | |||
| * @return <code>PatternSet.NameEntry</code>. | |||
| * @return <code>PatternSet.PatternFileNameEntry</code>. | |||
| */ | |||
| public synchronized PatternSet.NameEntry createExcludesFile() { | |||
| if (isReference()) { | |||
| @@ -18,17 +18,41 @@ | |||
| package org.apache.tools.ant.types; | |||
| import org.apache.tools.ant.BuildFileRule; | |||
| import org.junit.Before; | |||
| import org.junit.Rule; | |||
| import org.junit.Test; | |||
| import static org.junit.Assert.assertEquals; | |||
| /** | |||
| * JUnit 4 testcases for org.apache.tools.ant.types.FileSet. | |||
| * | |||
| * <p>This doesn't actually test much, mainly reference handling.</p> | |||
| */ | |||
| public class FileSetTest extends AbstractFileSetTest { | |||
| @Rule | |||
| public BuildFileRule buildRule = new BuildFileRule(); | |||
| @Before | |||
| public void buildFileRuleSetUp() { | |||
| buildRule.configureProject("src/etc/testcases/types/fileset.xml"); | |||
| } | |||
| protected AbstractFileSet getInstance() { | |||
| return new FileSet(); | |||
| } | |||
| @Test | |||
| public void testNoEncoding() { | |||
| buildRule.executeTarget("no-encoding"); | |||
| assertEquals("/abc/fileset.xml", buildRule.getLog()); | |||
| } | |||
| @Test | |||
| public void testEncoding() { | |||
| buildRule.executeTarget("encoding"); | |||
| assertEquals("/abc/fileset.xml", buildRule.getLog()); | |||
| } | |||
| } | |||
| @@ -20,11 +20,18 @@ package org.apache.tools.ant.types; | |||
| import org.apache.tools.ant.BuildException; | |||
| import org.apache.tools.ant.Project; | |||
| import org.apache.tools.ant.util.FileUtils; | |||
| import org.junit.Before; | |||
| import org.junit.Test; | |||
| import java.io.File; | |||
| import java.io.FileOutputStream; | |||
| import java.io.IOException; | |||
| import java.io.OutputStream; | |||
| import java.io.OutputStreamWriter; | |||
| import java.io.Writer; | |||
| import static org.junit.Assert.assertArrayEquals; | |||
| import static org.junit.Assert.assertEquals; | |||
| import static org.junit.Assert.fail; | |||
| @@ -202,4 +209,26 @@ public class PatternSetTest { | |||
| assertEquals("Includes", "**/*.java", includes[0]); | |||
| assertEquals("Excludes", "**/*.class", excludes[0]); | |||
| } | |||
| @Test | |||
| public void testEncodingOfIncludesFile() throws IOException { | |||
| File testFile = File.createTempFile("ant-", ".pattern"); | |||
| testFile.deleteOnExit(); | |||
| OutputStream o = null; | |||
| Writer w = null; | |||
| try { | |||
| o = new FileOutputStream(testFile); | |||
| w = new OutputStreamWriter(o, "UTF-16LE"); | |||
| w.write("\u00e4\n"); | |||
| } finally { | |||
| FileUtils.close(w); | |||
| FileUtils.close(o); | |||
| } | |||
| PatternSet p = new PatternSet(); | |||
| PatternSet.PatternFileNameEntry ne = | |||
| (PatternSet.PatternFileNameEntry) p.createIncludesFile(); | |||
| ne.setName(testFile.getAbsolutePath()); | |||
| ne.setEncoding("UTF-16LE"); | |||
| assertArrayEquals(new String[] { "\u00e4" }, p.getIncludePatterns(project)); | |||
| } | |||
| } | |||