diff --git a/docs/index.html b/docs/index.html index 87c1d70cc..2f437bc82 100644 --- a/docs/index.html +++ b/docs/index.html @@ -465,6 +465,23 @@ you can define them with a <path> element at the same level as targets and reference them via their id attribute - see References for an example.

+

A PATH like structure can include a reference to another PATH like +structure via a nested <path> elements.

+
+    <path id="base.path">
+      <pathelement path="${classpath}" />
+      <fileset dir="lib">
+        <include name="**/*.jar" />
+      </fileset;>
+      <pathelement location="classes" />
+    </path>
+
+    <path id="tests.path">
+      <path refid="base.path" />
+      <pathelement location="testclasses" />
+    </path>
+
+

Command line arguments

Several tasks take arguments that shall be passed to another diff --git a/src/main/org/apache/tools/ant/types/Path.java b/src/main/org/apache/tools/ant/types/Path.java index 565abfdff..d564fb61e 100644 --- a/src/main/org/apache/tools/ant/types/Path.java +++ b/src/main/org/apache/tools/ant/types/Path.java @@ -60,8 +60,10 @@ import org.apache.tools.ant.Project; import org.apache.tools.ant.PathTokenizer; import java.io.File; -import java.util.Vector; +import java.util.Enumeration; import java.util.StringTokenizer; +import java.util.Stack; +import java.util.Vector; import java.text.CharacterIterator; import java.text.StringCharacterIterator; @@ -97,6 +99,11 @@ public class Path implements Cloneable { private Vector elements; private Project project; + private boolean isReference = false; + /** + * Are we sure we don't hold circular references? + */ + private boolean checked = true; public static Path systemClasspath = new Path(null, System.getProperty("java.class.path")); @@ -140,7 +147,10 @@ public class Path implements Cloneable { * @param location the location of the element to add (must not be * null nor empty. */ - public void setLocation(File location) { + public void setLocation(File location) throws BuildException { + if (isReference) { + throw tooManyAttributes(); + } createPathElement().setLocation(location); } @@ -149,15 +159,35 @@ public class Path implements Cloneable { * Parses a path definition and creates single PathElements. * @param path the path definition. */ - public void setPath(String path) { + public void setPath(String path) throws BuildException { + if (isReference) { + throw tooManyAttributes(); + } createPathElement().setPath(path); } + /** + * Makes this instance in effect a reference too another Path instance. + * + *

You must not set another attribute or nest elements inside + * this element if you make it a reference. + */ + public void setRefid(Reference r) throws BuildException { + isReference = true; + if (!elements.isEmpty()) { + throw tooManyAttributes(); + } + elements.addElement(r); + checked = false; + } /** - * Created the nested element. + * Creates the nested element. */ - public PathElement createPathElement() { + public PathElement createPathElement() throws BuildException { + if (isReference) { + throw noChildrenAllowed(); + } PathElement pe = new PathElement(); elements.addElement(pe); return pe; @@ -166,17 +196,36 @@ public class Path implements Cloneable { /** * Adds a nested element. */ - public void addFileset(FileSet fs) { + public void addFileset(FileSet fs) throws BuildException { + if (isReference) { + throw noChildrenAllowed(); + } elements.addElement(fs); } /** * Adds a nested element. */ - public void addFilesetRef(Reference r) { + public void addFilesetRef(Reference r) throws BuildException { + if (isReference) { + throw noChildrenAllowed(); + } elements.addElement(r); } + /** + * Creates a nested element. + */ + public Path createPath() throws BuildException { + if (isReference) { + throw noChildrenAllowed(); + } + Path p = new Path(project); + elements.add(p); + checked = false; + return p; + } + /** * Append the contents of the other Path instance to this. */ @@ -214,19 +263,26 @@ public class Path implements Cloneable { } /** - * Returns all path elements defined by this and netsed path objects. + * Returns all path elements defined by this and nested path objects. * @return list of path elements. */ public String[] list() { + if (!checked) { + // make sure we don't have a circular reference here + Stack stk = new Stack(); + stk.push(this); + bailOnCircularReference(stk); + } + Vector result = new Vector(2*elements.size()); for (int i=0; i dummy2 --> dummy3 --> dummy1 + Path p1 = new Path(project); + project.addReference("dummy1", p1); + Path p2 = p1.createPath(); + project.addReference("dummy2", p2); + Path p3 = p2.createPath(); + project.addReference("dummy3", p3); + p3.setRefid(new Reference("dummy1")); + try { + p1.list(); + fail("Can make circular reference."); + } catch (BuildException be) { + assertEquals("This path contains a circular reference.", + be.getMessage()); + } + + // dummy1 --> dummy2 --> dummy3 (with Path "/a") + p1 = new Path(project); + project.addReference("dummy1", p1); + p2 = p1.createPath(); + project.addReference("dummy2", p2); + p3 = p2.createPath(); + project.addReference("dummy3", p3); + p3.setLocation(new File("/a")); + String[] l = p1.list(); + assertEquals("One element burried deep inside a nested path structure", + 1, l.length); + if (isUnixStyle) { + assertEquals("/a", l[0]); + } else { + assertEquals("\\a", l[0]); + } } }