diff --git a/WHATSNEW b/WHATSNEW index 258a90a3c..d5f66eb2d 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -135,6 +135,11 @@ Other changes: * The task now explicitly accepts and supports the gzip content encoding. Bugzilla Report 49453 + * A new resourcecollection type acts like a union + of s and s that share the same configuration but + have different base directories. + Bugzilla Report 48621 + Changes from Ant 1.9.2 TO Ant 1.9.3 =================================== diff --git a/manual/Types/multirootfileset.html b/manual/Types/multirootfileset.html new file mode 100644 index 000000000..e11beb2d8 --- /dev/null +++ b/manual/Types/multirootfileset.html @@ -0,0 +1,173 @@ + + + + + + +MultiRooFileSet Type + + + + +

MultiRootFileSet

+ +

Since Ant 1.9.4

+ +

A MultiRootFileSet is a group of files or directories. These files +or drectories can be found in a directory forrest starting with a set +of base directories and are matched by patterns taken from a number of +PatternSets and Selectors.

+ +

MultiRootFileSet acts as a union of FileSets and DirSets +that share the same patterns and selectors.

+ +

MultiRootFileSet supports all attributes and nested elements of +FileSet and DirSet except for the "dir" attribute.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AttributeDescriptionRequired
basedirsComma separated list of directories that build + the roots of the MultiRootFileSet.No
cacheWhether to cache results; disabling + may seriously impact performanceNo, default true
typeThe type of file system entities which will be + included in this set. + Acceptable values are: +
    +
  • file - regular files
  • +
  • dir - directories
  • +
  • both - regular files and directories
  • +
+
No, defaults to file
includesA comma- or space-separated list of patterns of directories that + must be included; all directories are included when omitted.No
includesfileThe name of a file; each line of this file is + taken to be an include pattern.No
excludesA comma- or space-separated list of patterns of directories that + must be excluded; no directories are excluded when omitted.No
excludesfileThe name of a file; each line of this file is + taken to be an exclude pattern.No
casesensitiveSpecifies whether case-sensitivity should be applied + (true|yes|on or + false|no|off).No; defaults to true.
followsymlinksShall symbolic links be followed? Defaults to + true. See fileset's documentation.No
erroronmissingdir + Specify what happens if one of the base directories does not exist. + If true a build error will happen, if false, the subtree + will be ignored/empty. + Defaults to true. + No
+ +

Parameters specified as nested elements

+ +

PatternSets can be specified as nested +<patternset> elements. In addition, MultiRootFileSet holds +an implicit PatternSet and supports the nested +<include>, <includesfile>, +<exclude> and <excludesfile> +elements of <patternset> directly, as well as +<patternset>'s attributes.

+ +

Selectors are available as nested elements within the +MultiRootFileSet. If any of the selectors within the MultiRootFileSet +do not select the file or directory, it is not considered part of the +MultiRootFileSet. This makes a MultiRootFileSet equivalent to +an <and> selector container.

+ +

In addition basedirs for the MultiRootFileSet can be specified as + nested basedir elements that have a + single file attribute.

+ + +

Examples

+ +
+<multirootfileset basedirs="${build.dir},${other.project.dir}">
+  <include name="apps/**/classes"/>
+  <exclude name="apps/**/*Test*"/>
+</multirootfileset>
+
+

Groups all files inside classes found under the +apps subdirectory of ${build.dir} or +${other.project.dir}, except those that have the text +Test in their name.

+ +
+<multirootfileset>
+  <basedir file="${build.dir}"/>
+  <basedir file="${other.project.dir}"
+  <include name="apps/**/classes"/>
+  <exclude name="apps/**/*Test*"/>
+</multirootfileset>
+
+

Is equivalent to the first example but used + nested basedir elements. The nested elements and + the basedirs attribute can be used at the same time and + the will be merged.

+ + + + diff --git a/manual/Types/resources.html b/manual/Types/resources.html index 7a0fe9ef9..1c398560d 100644 --- a/manual/Types/resources.html +++ b/manual/Types/resources.html @@ -320,6 +320,7 @@ Ant's "legacy" datatypes have been modified to behave as Resource Collections:
  • fileset, dirset, + multirootfileset, filelist, and path (and derivative types) expose file resources diff --git a/manual/conceptstypeslist.html b/manual/conceptstypeslist.html index e4f3c1869..ae6ca1a85 100644 --- a/manual/conceptstypeslist.html +++ b/manual/conceptstypeslist.html @@ -51,6 +51,7 @@
  • File Mappers
  • FilterChains and FilterReaders
  • FilterSet
  • +
  • MultiRootFileSet
  • PatternSet
  • Path-like Structures
  • Permissions
  • diff --git a/src/main/org/apache/tools/ant/types/defaults.properties b/src/main/org/apache/tools/ant/types/defaults.properties index e85109cb3..903f5f014 100644 --- a/src/main/org/apache/tools/ant/types/defaults.properties +++ b/src/main/org/apache/tools/ant/types/defaults.properties @@ -90,6 +90,7 @@ tarentry=org.apache.tools.ant.types.resources.TarResource gzipresource=org.apache.tools.ant.types.resources.GZipResource bzip2resource=org.apache.tools.ant.types.resources.BZip2Resource javaresource=org.apache.tools.ant.types.resources.JavaResource +multirootfileset=org.apache.tools.ant.types.resources.MultiRootFileSet #tokenizer implementations linetokenizer=org.apache.tools.ant.util.LineTokenizer diff --git a/src/main/org/apache/tools/ant/types/resources/MultiRootFileSet.java b/src/main/org/apache/tools/ant/types/resources/MultiRootFileSet.java new file mode 100644 index 000000000..74a586d73 --- /dev/null +++ b/src/main/org/apache/tools/ant/types/resources/MultiRootFileSet.java @@ -0,0 +1,232 @@ +/* + * 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. + * + */ + +package org.apache.tools.ant.types.resources; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.types.AbstractFileSet; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.types.Resource; +import org.apache.tools.ant.types.ResourceCollection; + +/** + * Union of file/dirsets that share the same patterns and selectors + * but have different roots. + * @since Ant 1.9.4 + */ +public class MultiRootFileSet extends AbstractFileSet + implements ResourceCollection { + + private SetType type = SetType.file; + private boolean cache = true; + private List baseDirs = new ArrayList(); + private Union union; + + public void setDir(File dir) { + throw new BuildException(getDataTypeName() + + " doesn't support the dir attribute"); + } + + /** + * Determines the types of resources to return. + * @param type the types of resources to return + */ + public void setType(SetType type) { + if (isReference()) { + throw tooManyAttributes(); + } + this.type = type; + } + + /** + * Set whether to cache collections. + * @param b boolean cache flag. + */ + public synchronized void setCache(boolean b) { + if (isReference()) { + throw tooManyAttributes(); + } + cache = b; + } + + /** + * Adds basedirs as a comman separated list. + * @param b boolean cache flag. + */ + public void setBaseDirs(String dirs) { + if (isReference()) { + throw tooManyAttributes(); + } + if (dirs != null && dirs.length() > 0) { + String[] ds = dirs.split(","); + for (String d : ds) { + baseDirs.add(getProject().resolveFile(d)); + } + } + } + + /** + * Adds a basedir as nested element. + */ + public void addConfiguredBaseDir(FileResource r) { + if (isReference()) { + throw noChildrenAllowed(); + } + baseDirs.add(r.getFile()); + } + + public void setRefid(Reference r) { + if (!baseDirs.isEmpty()) { + throw tooManyAttributes(); + } + super.setRefid(r); + } + + /** + * Return a MultiRootFileSet that has the same basedirs and same patternsets + * as this one. + * @return the cloned MultiRootFileSet. + */ + public Object clone() { + if (isReference()) { + return ((MultiRootFileSet) getRef(getProject())).clone(); + } else { + MultiRootFileSet fs = (MultiRootFileSet) super.clone(); + fs.baseDirs = new ArrayList(baseDirs); + fs.union = null; + return fs; + } + } + + /** + * Fulfill the ResourceCollection contract. + * @return an Iterator of Resources. + */ + public Iterator iterator() { + if (isReference()) { + return ((MultiRootFileSet) getRef(getProject())).iterator(); + } + return merge().iterator(); + } + + /** + * Fulfill the ResourceCollection contract. + * @return number of elements as int. + */ + public int size() { + if (isReference()) { + return ((MultiRootFileSet) getRef(getProject())).size(); + } + return merge().size(); + } + + /** + * Always returns true. + * @return true indicating that all elements will be FileResources. + */ + public boolean isFilesystemOnly() { + return true; + } + + /** + * Returns included directories as a list of semicolon-separated paths. + * + * @return a String of included directories. + */ + public String toString() { + if (isReference()) { + return ((MultiRootFileSet) getRef(getProject())).toString(); + } + return merge().toString(); + } + + private synchronized Union merge() { + if (cache && union != null) { + return union; + } + Union u = new Union(); + setup(u); + if (cache) { + union = u; + } + return u; + } + + private void setup(Union u) { + for (File d : baseDirs) { + u.add(new Worker(this, type, d)); + } + } + + /** + * What to return from the set: files, directories or both. + */ + public static enum SetType { + file, dir, both + } + + private static class Worker extends AbstractFileSet + implements ResourceCollection { + + private final SetType type; + + private Worker(MultiRootFileSet fs, SetType type, File dir) { + super(fs); + this.type = type; + setDir(dir); + } + + public boolean isFilesystemOnly() { + return true; + } + + public Iterator iterator() { + DirectoryScanner ds = getDirectoryScanner(getProject()); + String[] names = type == SetType.file + ? ds.getIncludedFiles() + : ds.getIncludedDirectories(); + if (type == SetType.both) { + String[] files = ds.getIncludedFiles(); + String[] merged = new String[names.length + files.length]; + System.arraycopy(names, 0, merged, 0, names.length); + System.arraycopy(files, 0, merged, names.length, files.length); + names = merged; + } + return new FileResourceIterator(getProject(), getDir(getProject()), + names); + } + + public int size() { + DirectoryScanner ds = getDirectoryScanner(getProject()); + int count = type == SetType.file + ? ds.getIncludedFilesCount() + : ds.getIncludedDirs Count(); + if (type == SetType.both) { + count += ds.getIncludedFilesCount(); + } + return count; + } + } + +} diff --git a/src/tests/antunit/types/resources/multirootfileset-test.xml b/src/tests/antunit/types/resources/multirootfileset-test.xml new file mode 100644 index 000000000..3a2a6a06c --- /dev/null +++ b/src/tests/antunit/types/resources/multirootfileset-test.xml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/tests/junit/org/apache/tools/ant/types/resources/MultiRootFileSetTest.java b/src/tests/junit/org/apache/tools/ant/types/resources/MultiRootFileSetTest.java new file mode 100644 index 000000000..a0e2a00d9 --- /dev/null +++ b/src/tests/junit/org/apache/tools/ant/types/resources/MultiRootFileSetTest.java @@ -0,0 +1,127 @@ +/* + * 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. + * + */ + +package org.apache.tools.ant.types.resources; + +import java.io.File; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.types.AbstractFileSet; +import org.apache.tools.ant.types.AbstractFileSetTest; +import org.apache.tools.ant.types.Reference; + +/** + * This doesn't actually test much, mainly reference handling. + */ +public class MultiRootFileSetTest extends AbstractFileSetTest { + + public MultiRootFileSetTest(String name) { + super(name); + } + + protected AbstractFileSet getInstance() { + return new MultiRootFileSet() { + // overriding so set/getDir works as expected by the base test class + private File dir; + public void setDir(File dir) { + if (isReference()) { + throw tooManyAttributes(); + } + this.dir = dir; + } + + public synchronized File getDir(Project p) { + if (isReference()) { + return getRef(p).getDir(p); + } + dieOnCircularReference(); + return dir; + } + }; + } + + public void testEmptyElementIfIsReferenceAdditionalAttributes() { + MultiRootFileSet f = new MultiRootFileSet(); + f.setProject(getProject()); + f.setBaseDirs("a"); + try { + f.setRefid(new Reference(getProject(), "dummyref")); + fail("Can add reference to multirootfileset " + + " with elements from setBasedirs"); + } catch (BuildException be) { + assertEquals("You must not specify more than one attribute " + + "when using refid", be.getMessage()); + } + f = new MultiRootFileSet(); + f.addConfiguredBaseDir(new FileResource(new File("."))); + try { + f.setRefid(new Reference(getProject(), "dummyref")); + fail("Can add reference to multirootfileset" + + " with elements from addConfiguredBaseDir"); + } catch (BuildException be) { + assertEquals("You must not specify more than one attribute " + + "when using refid", be.getMessage()); + } + + f = new MultiRootFileSet(); + f.setRefid(new Reference(getProject(), "dummyref")); + try { + f.setBaseDirs("a"); + fail("Can set basedirs in multirootfileset" + + " that is a reference."); + } catch (BuildException be) { + assertEquals("You must not specify more than one attribute " + + "when using refid", be.getMessage()); + } + try { + f.setCache(true); + fail("Can set cache in multirootfileset" + + " that is a reference."); + } catch (BuildException be) { + assertEquals("You must not specify more than one attribute " + + "when using refid", be.getMessage()); + } + try { + f.setType(MultiRootFileSet.SetType.file); + fail("Can set type in multirootfileset" + + " that is a reference."); + } catch (BuildException be) { + assertEquals("You must not specify more than one attribute " + + "when using refid", be.getMessage()); + } + try { + f.addConfiguredBaseDir(new FileResource(new File("."))); + fail("Can add nested basedir in multirootfileset " + + " that is a reference."); + } catch (BuildException be) { + assertEquals("You must not specify nested elements when using " + + "refid", be.getMessage()); + } + } + + public void testDirCannotBeSet() { + try { + new MultiRootFileSet().setDir(new File(".")); + fail("Can set dir in a multirootfileset"); + } catch (BuildException e) { + assertTrue(e.getMessage() + .endsWith(" doesn't support the dir attribute")); + } + } +}