Summary: | exec task doesn't handle error conditions well | ||
---|---|---|---|
Product: | Ant | Reporter: | Eric Safern <eric> |
Component: | Core tasks | Assignee: | Ant Notifications List <notifications> |
Status: | NEW --- | ||
Severity: | enhancement | CC: | taffy-tyler6464 |
Priority: | P3 | ||
Version: | 1.6.0 | ||
Target Milestone: | --- | ||
Hardware: | All | ||
OS: | Linux |
Description
Eric Safern
2003-11-21 04:04:16 UTC
What about using the resultproperty to cache the return code, then probing that for being non-zero? It would be a workaround. Out of curiosity, what it the contents of the errorText property after the exec? an empty string? We really ought to consider leaving it unset in such a case. I'm not sure it is better to leave this unset if there is no output. It is possible but does it make sense? Should it apply to output properties as well. What about people who output the properties after a run <echo message="errors: ${erroroutput}"/> The results for that would be the string ${erroroutput} if it is not set. Maybe not that desirable. I argree with Conor. Eric is trying to overload the meaning of the errorproperty. There is a resultProperty in exec which can be used to see if the exec returned a non zero value. (This also always gets set) One can also use ant-contrib's trycatch. (fun with beanshelldef : see http://marc.theaimsgroup.com/?l=ant-dev&m=106577547220771&w=2 Opps I did a send by accidient: One could extend ExecTask with an onerror nested element: <target name="init"> <bsh:beanshelldef name="exec2" classname="Exec2"> import org.apache.tools.ant.taskdefs.condition.Condition; import org.apache.tools.ant.taskdefs.ExecTask; import org.apache.tools.ant.taskdefs.Sequential; public class Exec2 extends ExecTask implements Condition { private boolean runOk = false; private Sequential onError; protected void maybeSetResultPropertyValue(int result) { super.maybeSetResultPropertyValue(result); runOk = (result == 0); } public void addOnError(Sequential onError) { this.onError = onError; } public boolean eval() { execute(); return runOk; } public void execute() { super.execute(); if (!runOk && onError != null) { onError.perform(); } } } </bsh:beanshelldef> </target> and use it like so: <target name="onerror" depends="init"> <exec2 executable="sh" errorproperty="sh.error.output" failonerror="false"> <arg value="error.sh"/> <onError> <echo>exec failed with error output: ${sh.error.output}</echo> </onError> </exec2> </target> Well, I like the OnError idea. Checking the return value works, but a) it's an ugly block of code needed after each and every exec and b) The ant documentation goes out of it's way to say that the definition of 'return code specifying failure' is OS-specific. This makes my code OS dependent, by making explicit that a non-zero return specifies failure. In answer to Steve, yes - the errorText property is an empty string but set. Finally, no one picked up on my first suggestion (perhaps not very clear). If you set failonerror="yes", the errror message returned should quote the error message returned by the sub-program, and return the error code - rather than just telling me the error code as it does now. OK, here's an update: the suggestion to set a property based on the return value doesn't work when you're execing more than one sub-program. Why? Because of the way Ant properties work - they're immutable. So after the first exec call, execError and errorText are both set and can't be changed! I suppose I could bury each exec call in an ant task that I <antcall> - but where does the ugliness end?? I do not think that this is a bug. If the command generates output on the error stream, ant will display this output. The user/build script author may suppress this output by using the "outputproperty" or the "errorproperty" attributes. (if "outputproperty" is sprecified by itself, it will have contain error and std output). Displaying the error output despite the user specifing otherwise would in my opinion be an error. You could say the same thing about the resultproperty, which *is* displayed when the failonerror is enabled (despite the user's setting or non-setting of this property). That's why the manual says "Only of interest if failonerror=false." If we did the same thing with errorproperty, we could add the same line to the manual by errorproperty as well. The bottom line is that I need some reasonable way to display the error message when the execed subprogram fails! I have yet to hear any way to do this, short of having a dedicated property and a dedicated target for *each* call to exec: <exec executable="perl" failonerror="no" errorproperty="eP1" resultproperty="rP1"> <arg line="Prog1.pl" /> </exec> <condition property="execFailed1"> <not> <equals arg1="${rp1}" arg2="0" /> </not> </condition> <antcall target="failOnError1" /> <target name="failOnError1" if="execFailed1"> <fail message="Error: an executed program has returned the following error: '${eP1}'. Please contact your site administrator for further help." /> </target> <!-- failOnError1 --> <exec executable="perl" failonerror="no" errorproperty="eP2" resultproperty="rP2"> <arg line="Prog2.pl" /> </exec> <condition property="execFailed2"> <not> <equals arg1="${rp2}" arg2="0" /> </not> </condition> <antcall target="failOnError2" /> <target name="failOnError2" if="execFailed2"> <fail message="Error: an executed program has returned the following error: '${eP2}'. Please contact your site administrator for further help." /> </target> <!-- failOnError2 --> repeated again and again. That's 12 lines of noise to 3 lines of useful code. And talk about subtle bugs - what do you think will happen if the programmer screws up his cut-and-paste and leaves a '3' when he needed a '4?' Good luck catching that in the testing process!!! |