https://bz.apache.org/bugzilla/show_bug.cgi?id=62379master
@@ -48,6 +48,11 @@ Other changes: | |||||
generated. | generated. | ||||
Bugzilla Report 62379 | 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 | 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> | <b>not</b> set</a>.</td> | ||||
<td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
</tr> | </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> | </table> | ||||
<h4><code>patternset</code></h4> | <h4><code>patternset</code></h4> | ||||
<p>Patternsets may be nested within one another, adding the nested | <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 | * 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() { | public PatternSet.NameEntry createIncludesFile() { | ||||
usedMatchingTask = true; | usedMatchingTask = true; | ||||
@@ -265,7 +265,7 @@ public class Delete extends MatchingTask { | |||||
/** | /** | ||||
* add a name entry on the include files list | * 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() { | public PatternSet.NameEntry createExcludesFile() { | ||||
usedMatchingTask = true; | usedMatchingTask = true; | ||||
@@ -77,7 +77,7 @@ public abstract class MatchingTask extends Task implements SelectorContainer { | |||||
/** | /** | ||||
* add a name entry on the include files list | * 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() { | public PatternSet.NameEntry createIncludesFile() { | ||||
return fileset.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 | * 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() { | public PatternSet.NameEntry createExcludesFile() { | ||||
return fileset.createExcludesFile(); | return fileset.createExcludesFile(); | ||||
@@ -189,7 +189,7 @@ public abstract class AbstractFileSet extends DataType | |||||
/** | /** | ||||
* Add a name entry to the include files list. | * Add a name entry to the include files list. | ||||
* @return <code>PatternSet.NameEntry</code>. | |||||
* @return <code>PatternSet.PatternFileNameEntry</code>. | |||||
*/ | */ | ||||
public synchronized PatternSet.NameEntry createIncludesFile() { | public synchronized PatternSet.NameEntry createIncludesFile() { | ||||
if (isReference()) { | if (isReference()) { | ||||
@@ -213,7 +213,7 @@ public abstract class AbstractFileSet extends DataType | |||||
/** | /** | ||||
* Add a name entry to the excludes files list. | * Add a name entry to the excludes files list. | ||||
* @return <code>PatternSet.NameEntry</code>. | |||||
* @return <code>PatternSet.PatternFileNameEntry</code>. | |||||
*/ | */ | ||||
public synchronized PatternSet.NameEntry createExcludesFile() { | public synchronized PatternSet.NameEntry createExcludesFile() { | ||||
if (isReference()) { | if (isReference()) { | ||||
@@ -19,8 +19,10 @@ package org.apache.tools.ant.types; | |||||
import java.io.BufferedReader; | import java.io.BufferedReader; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileInputStream; | |||||
import java.io.FileReader; | import java.io.FileReader; | ||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStreamReader; | |||||
import java.util.ArrayList; | import java.util.ArrayList; | ||||
import java.util.List; | import java.util.List; | ||||
import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||
@@ -40,8 +42,8 @@ import org.apache.tools.ant.util.FileUtils; | |||||
public class PatternSet extends DataType implements Cloneable { | public class PatternSet extends DataType implements Cloneable { | ||||
private List<NameEntry> includeList = new ArrayList<NameEntry>(); | private List<NameEntry> includeList = new ArrayList<NameEntry>(); | ||||
private List<NameEntry> excludeList = 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 | * 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 static final class InvertedPatternSet extends PatternSet { | ||||
private InvertedPatternSet(PatternSet p) { | private InvertedPatternSet(PatternSet p) { | ||||
setProject(p.getProject()); | setProject(p.getProject()); | ||||
@@ -255,7 +296,7 @@ public class PatternSet extends DataType implements Cloneable { | |||||
if (isReference()) { | if (isReference()) { | ||||
throw noChildrenAllowed(); | throw noChildrenAllowed(); | ||||
} | } | ||||
return addPatternToList(includesFileList); | |||||
return addPatternFileToList(includesFileList); | |||||
} | } | ||||
/** | /** | ||||
@@ -277,7 +318,7 @@ public class PatternSet extends DataType implements Cloneable { | |||||
if (isReference()) { | if (isReference()) { | ||||
throw noChildrenAllowed(); | throw noChildrenAllowed(); | ||||
} | } | ||||
return addPatternToList(excludesFileList); | |||||
return addPatternFileToList(excludesFileList); | |||||
} | } | ||||
/** | /** | ||||
@@ -325,6 +366,15 @@ public class PatternSet extends DataType implements Cloneable { | |||||
return result; | 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. | * 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 | * Reads path matching patterns from a file and adds them to the | ||||
* includes or excludes list (as appropriate). | * 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 { | throws BuildException { | ||||
BufferedReader patternReader = null; | BufferedReader patternReader = null; | ||||
try { | try { | ||||
// Get a FileReader | // 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 | // Create one NameEntry in the appropriate pattern list for each | ||||
// line in the file. | // line in the file. | ||||
@@ -478,7 +532,7 @@ public class PatternSet extends DataType implements Cloneable { | |||||
*/ | */ | ||||
private void readFiles(Project p) { | private void readFiles(Project p) { | ||||
if (includesFileList.size() > 0) { | if (includesFileList.size() > 0) { | ||||
for (NameEntry ne : includesFileList) { | |||||
for (PatternFileNameEntry ne : includesFileList) { | |||||
String fileName = ne.evalName(p); | String fileName = ne.evalName(p); | ||||
if (fileName != null) { | if (fileName != null) { | ||||
File inclFile = p.resolveFile(fileName); | File inclFile = p.resolveFile(fileName); | ||||
@@ -486,13 +540,13 @@ public class PatternSet extends DataType implements Cloneable { | |||||
throw new BuildException("Includesfile " + inclFile.getAbsolutePath() | throw new BuildException("Includesfile " + inclFile.getAbsolutePath() | ||||
+ " not found."); | + " not found."); | ||||
} | } | ||||
readPatterns(inclFile, includeList, p); | |||||
readPatterns(inclFile, ne.getEncoding(), includeList, p); | |||||
} | } | ||||
} | } | ||||
includesFileList.clear(); | includesFileList.clear(); | ||||
} | } | ||||
if (excludesFileList.size() > 0) { | if (excludesFileList.size() > 0) { | ||||
for (NameEntry ne : excludesFileList) { | |||||
for (PatternFileNameEntry ne : excludesFileList) { | |||||
String fileName = ne.evalName(p); | String fileName = ne.evalName(p); | ||||
if (fileName != null) { | if (fileName != null) { | ||||
File exclFile = p.resolveFile(fileName); | File exclFile = p.resolveFile(fileName); | ||||
@@ -500,7 +554,7 @@ public class PatternSet extends DataType implements Cloneable { | |||||
throw new BuildException("Excludesfile " + exclFile.getAbsolutePath() | throw new BuildException("Excludesfile " + exclFile.getAbsolutePath() | ||||
+ " not found."); | + " not found."); | ||||
} | } | ||||
readPatterns(exclFile, excludeList, p); | |||||
readPatterns(exclFile, ne.getEncoding(), excludeList, p); | |||||
} | } | ||||
} | } | ||||
excludesFileList.clear(); | excludesFileList.clear(); | ||||
@@ -523,8 +577,8 @@ public class PatternSet extends DataType implements Cloneable { | |||||
PatternSet ps = (PatternSet) super.clone(); | PatternSet ps = (PatternSet) super.clone(); | ||||
ps.includeList = new ArrayList<NameEntry>(includeList); | ps.includeList = new ArrayList<NameEntry>(includeList); | ||||
ps.excludeList = new ArrayList<NameEntry>(excludeList); | 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; | return ps; | ||||
} catch (CloneNotSupportedException e) { | } catch (CloneNotSupportedException e) { | ||||
throw new BuildException(e); | throw new BuildException(e); | ||||
@@ -124,7 +124,7 @@ public class Files extends AbstractSelectorContainer | |||||
/** | /** | ||||
* Add a name entry to the include files list. | * Add a name entry to the include files list. | ||||
* @return <code>PatternSet.NameEntry</code>. | |||||
* @return <code>PatternSet.PatternFileNameEntry</code>. | |||||
*/ | */ | ||||
public synchronized PatternSet.NameEntry createIncludesFile() { | public synchronized PatternSet.NameEntry createIncludesFile() { | ||||
if (isReference()) { | if (isReference()) { | ||||
@@ -148,7 +148,7 @@ public class Files extends AbstractSelectorContainer | |||||
/** | /** | ||||
* Add a name entry to the excludes files list. | * Add a name entry to the excludes files list. | ||||
* @return <code>PatternSet.NameEntry</code>. | |||||
* @return <code>PatternSet.PatternFileNameEntry</code>. | |||||
*/ | */ | ||||
public synchronized PatternSet.NameEntry createExcludesFile() { | public synchronized PatternSet.NameEntry createExcludesFile() { | ||||
if (isReference()) { | if (isReference()) { | ||||
@@ -18,17 +18,41 @@ | |||||
package org.apache.tools.ant.types; | 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. | * 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 { | 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() { | protected AbstractFileSet getInstance() { | ||||
return new FileSet(); | 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.BuildException; | ||||
import org.apache.tools.ant.Project; | import org.apache.tools.ant.Project; | ||||
import org.apache.tools.ant.util.FileUtils; | |||||
import org.junit.Before; | import org.junit.Before; | ||||
import org.junit.Test; | import org.junit.Test; | ||||
import java.io.File; | 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.assertEquals; | ||||
import static org.junit.Assert.fail; | import static org.junit.Assert.fail; | ||||
@@ -202,4 +209,26 @@ public class PatternSetTest { | |||||
assertEquals("Includes", "**/*.java", includes[0]); | assertEquals("Includes", "**/*.java", includes[0]); | ||||
assertEquals("Excludes", "**/*.class", excludes[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)); | |||||
} | |||||
} | } |