PR: 19220 git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276425 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -34,6 +34,8 @@ Other changes: | |||||
| * <loadproperties> supports loading from a resource. | * <loadproperties> supports loading from a resource. | ||||
| * <fail> accepts nested conditions. | |||||
| Changes from Ant 1.6.1 to current Ant 1.6 CVS version | Changes from Ant 1.6.1 to current Ant 1.6 CVS version | ||||
| ============================================= | ============================================= | ||||
| @@ -37,6 +37,16 @@ or character data nested into the element.</p> | |||||
| <td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
| </tr> | </tr> | ||||
| </table> | </table> | ||||
| <h3>Parameters specified as nested elements</h3> | |||||
| <p>As an alternative to the <i>if</i>/<i>unless</i> attributes, | |||||
| conditional failure can be achieved using a single nested condition. | |||||
| For a complete list of core conditions, as well as information | |||||
| about custom conditions, see <a href="conditions.html">here</a>.<br /> | |||||
| <b>Since Ant 1.6.2</b> | |||||
| </p> | |||||
| <h3>Examples</h3> | <h3>Examples</h3> | ||||
| <pre> <fail/></pre> | <pre> <fail/></pre> | ||||
| <p>will exit the current build with no further information given.</p> | <p>will exit the current build with no further information given.</p> | ||||
| @@ -47,8 +57,9 @@ build.xml:4: No message | |||||
| </pre> | </pre> | ||||
| <pre> <fail message="Something wrong here."/></pre> | <pre> <fail message="Something wrong here."/></pre> | ||||
| <p>will exit the current build and print something like the following to wherever | |||||
| your output goes:</p> | |||||
| <p>will exit the current build and print something | |||||
| like the following to wherever your output goes: | |||||
| </p> | |||||
| <pre> | <pre> | ||||
| BUILD FAILED | BUILD FAILED | ||||
| @@ -58,6 +69,32 @@ build.xml:4: Something wrong here. | |||||
| <pre> <fail>Something wrong here.</fail></pre> | <pre> <fail>Something wrong here.</fail></pre> | ||||
| <p>will give the same result as above.</p> | <p>will give the same result as above.</p> | ||||
| <pre> <fail unless="thisdoesnotexist"/></pre> | |||||
| <p>will exit the current build and print something | |||||
| like the following to wherever your output goes: | |||||
| </p> | |||||
| <pre> | |||||
| BUILD FAILED | |||||
| build.xml:2: unless=thisdoesnotexist | |||||
| </pre> | |||||
| A simple example using conditions to achieve the same effect: | |||||
| <pre> | |||||
| <fail> | |||||
| <not> | |||||
| <isset property="thisdoesnotexist"/> | |||||
| </not> | |||||
| </fail> | |||||
| </pre> | |||||
| <p>Output:</p> | |||||
| <pre> | |||||
| BUILD FAILED | |||||
| build.xml:2: condition satisfied | |||||
| </pre> | |||||
| <hr> | <hr> | ||||
| <p align="center">Copyright © 2000-2001,2004 The Apache Software Foundation. All rights | <p align="center">Copyright © 2000-2001,2004 The Apache Software Foundation. All rights | ||||
| Reserved.</p> | Reserved.</p> | ||||
| @@ -25,5 +25,57 @@ | |||||
| <target name="testIfAndUnless"> | <target name="testIfAndUnless"> | ||||
| <fail unless="unless" if="if"/> | <fail unless="unless" if="if"/> | ||||
| </target> | </target> | ||||
| <target name="testNested1" description="should fail with default message"> | |||||
| <fail> | |||||
| <and /> | |||||
| </fail> | |||||
| </target> | |||||
| <target name="testNested2" description="should pass"> | |||||
| <fail> | |||||
| <or /> | |||||
| </fail> | |||||
| </target> | |||||
| <target name="testNested3" description="should fail"> | |||||
| <fail message="testNested3"> | |||||
| <and /> | |||||
| </fail> | |||||
| </target> | |||||
| <target name="testNested4a" description="should error"> | |||||
| <fail if="if"> | |||||
| <and /> | |||||
| </fail> | |||||
| </target> | |||||
| <target name="testNested4b" description="should error"> | |||||
| <fail unless="unless"> | |||||
| <and /> | |||||
| </fail> | |||||
| </target> | |||||
| <target name="testNested4c" description="should error"> | |||||
| <fail if="if" unless="unless"> | |||||
| <and /> | |||||
| </fail> | |||||
| </target> | |||||
| <target name="testNested5" description="should error"> | |||||
| <fail> | |||||
| <and /> | |||||
| <or /> | |||||
| </fail> | |||||
| </target> | |||||
| <target name="testNested6" description="should fail with message"> | |||||
| <fail> | |||||
| <and /> | |||||
| testNested6 | |||||
| testNested6 | |||||
| testNested6 | |||||
| </fail> | |||||
| </target> | |||||
| </project> | </project> | ||||
| @@ -18,8 +18,8 @@ | |||||
| package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.Task; | |||||
| import org.apache.tools.ant.taskdefs.condition.Condition; | |||||
| import org.apache.tools.ant.taskdefs.condition.ConditionBase; | |||||
| /** | /** | ||||
| * Exits the active build, giving an additional message | * Exits the active build, giving an additional message | ||||
| @@ -34,11 +34,15 @@ import org.apache.tools.ant.Task; | |||||
| * are true. i.e. | * are true. i.e. | ||||
| * <pre>fail := defined(ifProperty) && !defined(unlessProperty)</pre> | * <pre>fail := defined(ifProperty) && !defined(unlessProperty)</pre> | ||||
| * | * | ||||
| * A single nested<CODE><condition></CODE> element can be specified | |||||
| * instead of using <CODE>if</CODE>/<CODE>unless</CODE> (a combined | |||||
| * effect can be achieved using <CODE>isset</CODE> conditions). | |||||
| * | |||||
| * @since Ant 1.2 | * @since Ant 1.2 | ||||
| * | * | ||||
| * @ant.task name="fail" category="control" | * @ant.task name="fail" category="control" | ||||
| */ | */ | ||||
| public class Exit extends Task { | |||||
| public class Exit extends ConditionBase { | |||||
| private String message; | private String message; | ||||
| private String ifCondition, unlessCondition; | private String ifCondition, unlessCondition; | ||||
| @@ -69,31 +73,40 @@ public class Exit extends Task { | |||||
| } | } | ||||
| /** | /** | ||||
| * evaluate both if and unless conditions, and if | |||||
| * ifCondition is true or unlessCondition is false, throw a | |||||
| * build exception to exit the build. | |||||
| * The error message is constructed from the text fields, or from | |||||
| * Throw a <CODE>BuildException</CODE> to exit (fail) the build. | |||||
| * If specified, evaluate conditions: | |||||
| * A single nested condition is accepted, but requires that the | |||||
| * <CODE>if</CODE>/<code>unless</code> attributes be omitted. | |||||
| * If the nested condition evaluates to true, or the | |||||
| * ifCondition is true or unlessCondition is false, the build will exit. | |||||
| * The error message is constructed from the text fields, from | |||||
| * the nested condition (if specified), or finally from | |||||
| * the if and unless parameters (if present). | * the if and unless parameters (if present). | ||||
| * @throws BuildException | * @throws BuildException | ||||
| */ | */ | ||||
| public void execute() throws BuildException { | public void execute() throws BuildException { | ||||
| if (testIfCondition() && testUnlessCondition()) { | |||||
| boolean fail = (nestedConditionPresent()) ? testNestedCondition() | |||||
| : (testIfCondition() && testUnlessCondition()); | |||||
| if (fail) { | |||||
| String text = null; | String text = null; | ||||
| if (message != null && message.length() > 0) { | |||||
| text = message; | |||||
| if (message != null && message.trim().length() > 0) { | |||||
| text = message.trim(); | |||||
| } else { | } else { | ||||
| if (getProject().getProperty(ifCondition) != null) { | |||||
| if (ifCondition != null && ifCondition.length() > 0 | |||||
| && getProject().getProperty(ifCondition) != null) { | |||||
| text = "if=" + ifCondition; | text = "if=" + ifCondition; | ||||
| } | } | ||||
| if (unlessCondition != null && unlessCondition.length() > 0 | if (unlessCondition != null && unlessCondition.length() > 0 | ||||
| && getProject().getProperty(unlessCondition) == null) { | |||||
| && getProject().getProperty(unlessCondition) == null) { | |||||
| if (text == null) { | if (text == null) { | ||||
| text = ""; | text = ""; | ||||
| } else { | } else { | ||||
| text += " and "; | text += " and "; | ||||
| } | } | ||||
| text += "unless=" + unlessCondition; | text += "unless=" + unlessCondition; | ||||
| } | |||||
| if (nestedConditionPresent()) { | |||||
| text = "condition satisfied"; | |||||
| } else { | } else { | ||||
| if (text == null) { | if (text == null) { | ||||
| text = "No message"; | text = "No message"; | ||||
| @@ -138,4 +151,26 @@ public class Exit extends Task { | |||||
| return getProject().getProperty(unlessCondition) == null; | return getProject().getProperty(unlessCondition) == null; | ||||
| } | } | ||||
| /** | |||||
| * test the nested condition | |||||
| * @return true if there is none, or it evaluates to true | |||||
| */ | |||||
| private boolean testNestedCondition() { | |||||
| if (ifCondition != null || unlessCondition != null) { | |||||
| throw new BuildException("Nested conditions " | |||||
| + "not permitted in conjunction with if/unless attributes"); | |||||
| } | |||||
| int count = countConditions(); | |||||
| if (count > 1) { | |||||
| throw new BuildException("Too many conditions: " + count); | |||||
| } | |||||
| return (count == 0) ? true | |||||
| : (((Condition)(getConditions().nextElement())).eval()); | |||||
| } | |||||
| private boolean nestedConditionPresent() { | |||||
| return (countConditions() > 0); | |||||
| } | |||||
| } | } | ||||
| @@ -101,4 +101,50 @@ public class FailTest extends BuildFileTest { | |||||
| } | } | ||||
| } | } | ||||
| } | |||||
| public void testNested1() { | |||||
| expectSpecificBuildException("testNested1", | |||||
| "it is required to fail :-)", | |||||
| "condition satisfied"); | |||||
| } | |||||
| public void testNested2() { | |||||
| try { | |||||
| executeTarget("testNested2"); | |||||
| } catch (BuildException be) { | |||||
| fail("condition not satisfied; testNested2 must not fail"); | |||||
| } | |||||
| } | |||||
| public void testNested3() { | |||||
| expectSpecificBuildException("testNested3", | |||||
| "it is required to fail :-)", | |||||
| "testNested3"); | |||||
| } | |||||
| public void testNested4() { | |||||
| String specificMessage = "Nested conditions " | |||||
| + "not permitted in conjunction with if/unless attributes"; | |||||
| char[] c = {'a', 'b', 'c'}; | |||||
| StringBuffer target = new StringBuffer("testNested4x"); | |||||
| for (int i = 0; i < c.length; i++) { | |||||
| target.setCharAt(target.length() - 1, c[i]); | |||||
| expectSpecificBuildException(target.toString(), | |||||
| "it is required to fail :-)", specificMessage); | |||||
| } | |||||
| } | |||||
| public void testNested5() { | |||||
| expectSpecificBuildException("testNested5", | |||||
| "it is required to fail :-)", | |||||
| "Too many conditions: 2"); | |||||
| } | |||||
| public void testNested6() { | |||||
| expectSpecificBuildException("testNested6", | |||||
| "it is required to fail :-)", | |||||
| "testNested6\ntestNested6\ntestNested6"); | |||||
| } | |||||
| } | |||||