@@ -285,6 +285,7 @@ Matthew Watson | |||||
Matthew Yanos | Matthew Yanos | ||||
Matthias Bhend | Matthias Bhend | ||||
Matthias Gutheil | Matthias Gutheil | ||||
Matthias Johann Vill | |||||
Michael Bayne | Michael Bayne | ||||
Michael Clarke | Michael Clarke | ||||
Michael Davey | Michael Davey | ||||
@@ -1183,6 +1183,11 @@ | |||||
<first>Matthias</first> | <first>Matthias</first> | ||||
<last>Gutheil</last> | <last>Gutheil</last> | ||||
</name> | </name> | ||||
<name> | |||||
<first>Matthias</first> | |||||
<middle>Johann</middle> | |||||
<last>Vill</last> | |||||
</name> | |||||
<name> | <name> | ||||
<first>Michael</first> | <first>Michael</first> | ||||
<last>Bayne</last> | <last>Bayne</last> | ||||
@@ -1419,6 +1419,14 @@ of <a href="filelist.html"><code><filelist></code></a>.</p> | |||||
</td> | </td> | ||||
<td>No</td> | <td>No</td> | ||||
</tr> | </tr> | ||||
<tr> | |||||
<td>preserveduplicates</td> | |||||
<td>Makes this <code>resourcelist</code> return all resources as | |||||
many times as they are specified. Otherwise | |||||
<code>resourcelist</code> will only return each resource, in the | |||||
order they first appear. <em>Since Ant 1.10.10</em></td> | |||||
<td>No</td> | |||||
</tr> | |||||
<tr> | <tr> | ||||
<td>refid</td> | <td>refid</td> | ||||
<td>Makes this <code>resourcelist</code> | <td>Makes this <code>resourcelist</code> | ||||
@@ -0,0 +1,21 @@ | |||||
package org.apache.tools.ant.types.resources; | |||||
import org.apache.tools.ant.BuildException; | |||||
import org.apache.tools.ant.types.ResourceCollection; | |||||
/** | |||||
* Interface describing a collection of Resources, to which elements can be | |||||
* appended. | |||||
* | |||||
* @since Ant 1.10.10 | |||||
*/ | |||||
public interface AppendableResourceCollection extends ResourceCollection { | |||||
/** | |||||
Add a ResourceCollection to the container. | |||||
@param c the ResourceCollection to add. | |||||
@throws BuildException on error. | |||||
@since Ant 1.10.10 | |||||
*/ | |||||
void add(ResourceCollection c) throws BuildException; | |||||
} |
@@ -37,7 +37,7 @@ import org.apache.tools.ant.types.ResourceCollection; | |||||
* @since Ant 1.7 | * @since Ant 1.7 | ||||
*/ | */ | ||||
public abstract class BaseResourceCollectionContainer | public abstract class BaseResourceCollectionContainer | ||||
extends DataType implements ResourceCollection, Cloneable { | |||||
extends DataType implements AppendableResourceCollection, Cloneable { | |||||
private List<ResourceCollection> rc = new ArrayList<>(); | private List<ResourceCollection> rc = new ArrayList<>(); | ||||
private Collection<Resource> coll = null; | private Collection<Resource> coll = null; | ||||
private boolean cache = true; | private boolean cache = true; | ||||
@@ -92,6 +92,7 @@ public abstract class BaseResourceCollectionContainer | |||||
* @param c the ResourceCollection to add. | * @param c the ResourceCollection to add. | ||||
* @throws BuildException on error. | * @throws BuildException on error. | ||||
*/ | */ | ||||
@Override | |||||
public synchronized void add(ResourceCollection c) throws BuildException { | public synchronized void add(ResourceCollection c) throws BuildException { | ||||
if (isReference()) { | if (isReference()) { | ||||
throw noChildrenAllowed(); | throw noChildrenAllowed(); | ||||
@@ -47,14 +47,10 @@ import org.apache.tools.ant.types.ResourceCollection; | |||||
public class ResourceList extends DataType implements ResourceCollection { | public class ResourceList extends DataType implements ResourceCollection { | ||||
private final Vector<FilterChain> filterChains = new Vector<>(); | private final Vector<FilterChain> filterChains = new Vector<>(); | ||||
private final ArrayList<ResourceCollection> textDocuments = new ArrayList<>(); | private final ArrayList<ResourceCollection> textDocuments = new ArrayList<>(); | ||||
private final Union cachedResources = new Union(); | |||||
private volatile boolean cached = false; | |||||
private AppendableResourceCollection cachedResources = null; | |||||
private String encoding = null; | private String encoding = null; | ||||
private File baseDir; | private File baseDir; | ||||
public ResourceList() { | |||||
cachedResources.setCache(true); | |||||
} | |||||
private boolean preserveDuplicates = false; | |||||
/** | /** | ||||
* Adds a source. | * Adds a source. | ||||
@@ -116,6 +112,22 @@ public class ResourceList extends DataType implements ResourceCollection { | |||||
this.baseDir = baseDir; | this.baseDir = baseDir; | ||||
} | } | ||||
/** | |||||
* Makes this <code>resourcelist</code> return all resources as | |||||
* many times as they are specified. Otherwise | |||||
* <code>resourcelist</code> will only return each resource, in the | |||||
* order they first appear. | |||||
* | |||||
* @param preserveDuplicates boolean | |||||
* @since Ant 1.10.10 | |||||
*/ | |||||
public final void setPreserveDuplicates(boolean preserveDuplicates) { | |||||
if (isReference()) { | |||||
throw tooManyAttributes(); | |||||
} | |||||
this.preserveDuplicates = preserveDuplicates; | |||||
} | |||||
/** | /** | ||||
* Makes this instance in effect a reference to another ResourceList | * Makes this instance in effect a reference to another ResourceList | ||||
* instance. | * instance. | ||||
@@ -207,20 +219,31 @@ public class ResourceList extends DataType implements ResourceCollection { | |||||
return getCheckedRef(ResourceList.class); | return getCheckedRef(ResourceList.class); | ||||
} | } | ||||
private AppendableResourceCollection newResourceCollection() { | |||||
if (preserveDuplicates) { | |||||
final Resources resources = new Resources(); | |||||
resources.setCache(true); | |||||
return resources; | |||||
} else { | |||||
final Union union = new Union(); | |||||
union.setCache(true); | |||||
return union; | |||||
} | |||||
} | |||||
private synchronized ResourceCollection cache() { | private synchronized ResourceCollection cache() { | ||||
if (!cached) { | |||||
if (cachedResources == null) { | |||||
dieOnCircularReference(); | dieOnCircularReference(); | ||||
this.cachedResources = newResourceCollection(); | |||||
textDocuments.stream().flatMap(ResourceCollection::stream) | textDocuments.stream().flatMap(ResourceCollection::stream) | ||||
.map(this::read).forEach(cachedResources::add); | .map(this::read).forEach(cachedResources::add); | ||||
cached = true; | |||||
} | } | ||||
return cachedResources; | return cachedResources; | ||||
} | } | ||||
private ResourceCollection read(Resource r) { | private ResourceCollection read(Resource r) { | ||||
try (BufferedReader reader = new BufferedReader(open(r))) { | try (BufferedReader reader = new BufferedReader(open(r))) { | ||||
Union streamResources = new Union(); | |||||
streamResources.setCache(true); | |||||
final AppendableResourceCollection streamResources = newResourceCollection(); | |||||
reader.lines().map(this::parse).forEach(streamResources::add); | reader.lines().map(this::parse).forEach(streamResources::add); | ||||
return streamResources; | return streamResources; | ||||
} catch (final IOException ioe) { | } catch (final IOException ioe) { | ||||
@@ -40,7 +40,7 @@ import org.apache.tools.ant.types.ResourceCollection; | |||||
* making no attempt to remove duplicates, or references another ResourceCollection. | * making no attempt to remove duplicates, or references another ResourceCollection. | ||||
* @since Ant 1.7 | * @since Ant 1.7 | ||||
*/ | */ | ||||
public class Resources extends DataType implements ResourceCollection { | |||||
public class Resources extends DataType implements AppendableResourceCollection { | |||||
/** static empty ResourceCollection */ | /** static empty ResourceCollection */ | ||||
public static final ResourceCollection NONE = new ResourceCollection() { | public static final ResourceCollection NONE = new ResourceCollection() { | ||||
@Override | @Override | ||||
@@ -156,6 +156,7 @@ public class Resources extends DataType implements ResourceCollection { | |||||
* Add a ResourceCollection. | * Add a ResourceCollection. | ||||
* @param c the ResourceCollection to add. | * @param c the ResourceCollection to add. | ||||
*/ | */ | ||||
@Override | |||||
public synchronized void add(ResourceCollection c) { | public synchronized void add(ResourceCollection c) { | ||||
if (isReference()) { | if (isReference()) { | ||||
throw noChildrenAllowed(); | throw noChildrenAllowed(); | ||||
@@ -101,4 +101,41 @@ ${input}/c.txt</echo> | |||||
</copy> | </copy> | ||||
<au:assertFileExists file="${output}/antlib.xml"/> | <au:assertFileExists file="${output}/antlib.xml"/> | ||||
</target> | </target> | ||||
<target name="testDuplicatesRemoved" depends="setUp"> | |||||
<echo file="${input}/a.txt">${input}/b.txt | |||||
${input}/b.txt</echo> | |||||
<echo file="${input}/b.txt">Demo content</echo> | |||||
<echo file="${input}/c.txt">${input}/b.txt | |||||
${input}/b.txt</echo> | |||||
<pathconvert property="1b" pathsep="|" preserveduplicates="true"> | |||||
<flattenmapper/> | |||||
<resourcelist> | |||||
<resources> | |||||
<file file="${input}/a.txt"/> | |||||
<file file="${input}/c.txt"/> | |||||
</resources> | |||||
</resourcelist> | |||||
</pathconvert> | |||||
<au:assertPropertyEquals name="1b" value="b.txt"/> | |||||
</target> | |||||
<target name="testDuplicatesPreserved" depends="setUp"> | |||||
<echo file="${input}/a.txt">${input}/b.txt | |||||
${input}/b.txt</echo> | |||||
<echo file="${input}/b.txt">Demo content</echo> | |||||
<echo file="${input}/c.txt">${input}/b.txt | |||||
${input}/b.txt</echo> | |||||
<pathconvert property="4bs" pathsep="|" preserveduplicates="true"> | |||||
<flattenmapper/> | |||||
<resourcelist preserveduplicates="true"> | |||||
<resources> | |||||
<file file="${input}/a.txt"/> | |||||
<file file="${input}/a.txt"/> | |||||
<file file="${input}/c.txt"/> | |||||
</resources> | |||||
</resourcelist> | |||||
</pathconvert> | |||||
<au:assertPropertyEquals name="4bs" value="b.txt|b.txt|b.txt|b.txt|b.txt|b.txt"/> | |||||
</target> | |||||
</project> | </project> |