PR: 21877 Submitted by: Knut Wannheden <knut at paranor dot ch> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@274949 13f79535-47bb-0310-9956-ffa450edef68master
@@ -513,6 +513,9 @@ Other changes: | |||||
mappings per source path. This behaviour is enabled by using | mappings per source path. This behaviour is enabled by using | ||||
an enablemultiplemapping attribute. Bugzilla Report 21320. | an enablemultiplemapping attribute. Bugzilla Report 21320. | ||||
* <exec> will now work on OpenVMS (please read the notes in | |||||
<exec>'s manual page). Bugzilla Report 21877. | |||||
Changes from Ant 1.5.2 to Ant 1.5.3 | Changes from Ant 1.5.2 to Ant 1.5.3 | ||||
=================================== | =================================== | ||||
@@ -19,6 +19,14 @@ the executable parameter. This is because the Java VM in which Ant is running is | |||||
Windows executable and is not aware of Cygwin conventions. | Windows executable and is not aware of Cygwin conventions. | ||||
</p> | </p> | ||||
<h4>OpenVMS Users</h4> | |||||
<p>The command specified using <code>executable</code> and <code><arg></code> | |||||
elements is executed exactly as specified inside a temporary DCL script. This means | |||||
that paths have to be written in VMS style. It is also required that the logical | |||||
<code>JAVA$FORK_SUPPORT_CHDIR</code> is set to <code>TRUE</code> (see the <i>JDK Release | |||||
Notes</i>). | |||||
</p> | |||||
<h3>Parameters</h3> | <h3>Parameters</h3> | ||||
<table border="1" cellpadding="2" cellspacing="0"> | <table border="1" cellpadding="2" cellspacing="0"> | ||||
<tr> | <tr> | ||||
@@ -108,7 +116,7 @@ Windows executable and is not aware of Cygwin conventions. | |||||
<tr> | <tr> | ||||
<td valign="top">resultproperty</td> | <td valign="top">resultproperty</td> | ||||
<td valign="top">the name of a property in which the return code of the | <td valign="top">the name of a property in which the return code of the | ||||
command should be stored. Only of interest if failonerror=false</td> | |||||
command should be stored. Only of interest if failonerror=false.</td> | |||||
<td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
@@ -120,7 +128,7 @@ Windows executable and is not aware of Cygwin conventions. | |||||
<tr> | <tr> | ||||
<td valign="top">failonerror</td> | <td valign="top">failonerror</td> | ||||
<td valign="top">Stop the buildprocess if the command exits with a | <td valign="top">Stop the buildprocess if the command exits with a | ||||
returncode other than 0. Defaults to false</td> | |||||
return code signaling failure. Defaults to false.</td> | |||||
<td align="center" valign="top">No</td> | <td align="center" valign="top">No</td> | ||||
</tr> | </tr> | ||||
<tr> | <tr> | ||||
@@ -204,15 +212,15 @@ system command via nested <code><env></code> elements.</p> | |||||
<h3>Errors and return codes</h3> | <h3>Errors and return codes</h3> | ||||
By default the return code of a <exec> is ignored; when you set | By default the return code of a <exec> is ignored; when you set | ||||
<code>failonerror="true"</code> then any non zero response is treated as an | |||||
error. Alternatively, you can set <code>resultproperty</code> to the name | |||||
of a property and have it assigned to the result code (barring immutability, | |||||
of course). | |||||
<code>failonerror="true"</code> then any return code signaling failure | |||||
(OS specific) causes the build to fail. Alternatively, you can set | |||||
<code>resultproperty</code> to the name of a property and have it assigned to | |||||
the result code (barring immutability, of course). | |||||
<p> | <p> | ||||
If the attempt to start the program fails with an OS dependent error code, | If the attempt to start the program fails with an OS dependent error code, | ||||
then <exec> halts the build unless <code>failifexecutionfails</code> | then <exec> halts the build unless <code>failifexecutionfails</code> | ||||
is set. You can use that to run a program if it exists, but otherwise | |||||
do nothing. | |||||
is set to <code>false</code>. You can use that to run a program if it exists, but | |||||
otherwise do nothing. | |||||
<p> | <p> | ||||
What do those error codes mean? Well, they are OS dependent. On Windows | What do those error codes mean? Well, they are OS dependent. On Windows | ||||
boxes you have to look in include\error.h in your windows compiler or wine files; | boxes you have to look in include\error.h in your windows compiler or wine files; | ||||
@@ -413,7 +413,7 @@ public class ExecTask extends Task { | |||||
log("Timeout: killed the sub-process", Project.MSG_WARN); | log("Timeout: killed the sub-process", Project.MSG_WARN); | ||||
} | } | ||||
maybeSetResultPropertyValue(returnCode); | maybeSetResultPropertyValue(returnCode); | ||||
if (returnCode != 0) { | |||||
if (Execute.isFailure(returnCode)) { | |||||
if (failOnError) { | if (failOnError) { | ||||
throw new BuildException(getTaskType() + " returned: " | throw new BuildException(getTaskType() + " returned: " | ||||
+ returnCode, getLocation()); | + returnCode, getLocation()); | ||||
@@ -57,7 +57,9 @@ package org.apache.tools.ant.taskdefs; | |||||
import java.io.BufferedReader; | import java.io.BufferedReader; | ||||
import java.io.ByteArrayOutputStream; | import java.io.ByteArrayOutputStream; | ||||
import java.io.File; | import java.io.File; | ||||
import java.io.FileWriter; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.PrintWriter; | |||||
import java.io.StringReader; | import java.io.StringReader; | ||||
import java.lang.reflect.InvocationTargetException; | import java.lang.reflect.InvocationTargetException; | ||||
import java.lang.reflect.Method; | import java.lang.reflect.Method; | ||||
@@ -109,7 +111,9 @@ public class Execute { | |||||
static { | static { | ||||
// Try using a JDK 1.3 launcher | // Try using a JDK 1.3 launcher | ||||
try { | try { | ||||
if (!Os.isFamily("os/2")) { | |||||
if (Os.isFamily("openvms")) { | |||||
vmLauncher = new VmsCommandLauncher(); | |||||
} else if (!Os.isFamily("os/2")) { | |||||
vmLauncher = new Java13CommandLauncher(); | vmLauncher = new Java13CommandLauncher(); | ||||
} | } | ||||
} catch (NoSuchMethodException exc) { | } catch (NoSuchMethodException exc) { | ||||
@@ -155,6 +159,9 @@ public class Execute { | |||||
shellLauncher | shellLauncher | ||||
= new PerlScriptCommandLauncher("bin/antRun.pl", baseLauncher); | = new PerlScriptCommandLauncher("bin/antRun.pl", baseLauncher); | ||||
} else if (Os.isFamily("openvms")) { | |||||
// the vmLauncher already uses the shell | |||||
shellLauncher = vmLauncher; | |||||
} else { | } else { | ||||
// Generic | // Generic | ||||
shellLauncher = new ScriptCommandLauncher("bin/antRun", | shellLauncher = new ScriptCommandLauncher("bin/antRun", | ||||
@@ -249,6 +256,9 @@ public class Execute { | |||||
// rely on PATH | // rely on PATH | ||||
String[] cmd = {"env"}; | String[] cmd = {"env"}; | ||||
return cmd; | return cmd; | ||||
} else if (Os.isFamily("openvms")) { | |||||
String[] cmd = {"show", "logical"}; | |||||
return cmd; | |||||
} else { | } else { | ||||
// MAC OS 9 and previous | // MAC OS 9 and previous | ||||
// TODO: I have no idea how to get it, someone must fix it | // TODO: I have no idea how to get it, someone must fix it | ||||
@@ -490,14 +500,30 @@ public class Execute { | |||||
} | } | ||||
/** | /** | ||||
* query the exit value of the process. | |||||
* Query the exit value of the process. | |||||
* @return the exit value, 1 if the process was killed, | * @return the exit value, 1 if the process was killed, | ||||
* or Project.INVALID if no exit value has been received | |||||
* or Execute.INVALID if no exit value has been received | |||||
*/ | */ | ||||
public int getExitValue() { | public int getExitValue() { | ||||
return exitValue; | return exitValue; | ||||
} | } | ||||
/** | |||||
* Checks whether <code>exitValue</code> signals a failure on the current | |||||
* system (OS specific). | |||||
* @param exitValue the exit value (return code) to be checked | |||||
* @return <code>true</code> if <code>exitValue</code> signals a failure | |||||
*/ | |||||
public static boolean isFailure(int exitValue) { | |||||
if (Os.isFamily("openvms")) { | |||||
// odd exit value signals failure | |||||
return (exitValue % 2) == 0; | |||||
} else { | |||||
// non zero exit value signals failure | |||||
return exitValue != 0; | |||||
} | |||||
} | |||||
/** | /** | ||||
* test for an untimely death of the process | * test for an untimely death of the process | ||||
* @return true iff a watchdog had to kill the process | * @return true iff a watchdog had to kill the process | ||||
@@ -912,4 +938,61 @@ public class Execute { | |||||
private String _script; | private String _script; | ||||
} | } | ||||
/** | |||||
* A command launcher for VMS that writes the command to a temporary DCL | |||||
* script before launching commands. This is due to limitations of both | |||||
* the DCL interpreter and the Java VM implementation. | |||||
*/ | |||||
private static class VmsCommandLauncher extends Java13CommandLauncher { | |||||
public VmsCommandLauncher() throws NoSuchMethodException { | |||||
super(); | |||||
} | |||||
/** | |||||
* Launches the given command in a new process. | |||||
*/ | |||||
public Process exec(Project project, String[] cmd, String[] env) | |||||
throws IOException { | |||||
String[] vmsCmd = { createCommandFile(cmd).getPath() }; | |||||
return super.exec(project, vmsCmd, env); | |||||
} | |||||
/** | |||||
* Launches the given command in a new process, in the given working | |||||
* directory. Note that under Java 1.3.1, 1.4.0 and 1.4.1 on VMS this | |||||
* method only works if <code>workingDir</code> is null or the logical | |||||
* JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE. | |||||
*/ | |||||
public Process exec(Project project, String[] cmd, String[] env, | |||||
File workingDir) throws IOException { | |||||
String[] vmsCmd = { createCommandFile(cmd).getPath() }; | |||||
return super.exec(project, vmsCmd, env, workingDir); | |||||
} | |||||
/* | |||||
* Writes the command into a temporary DCL script and returns the | |||||
* corresponding File object. The script will be deleted on exit. | |||||
*/ | |||||
private File createCommandFile(String[] cmd) throws IOException { | |||||
File script = File.createTempFile("ANT", ".COM"); | |||||
script.deleteOnExit(); | |||||
PrintWriter out = null; | |||||
try { | |||||
out = new PrintWriter(new FileWriter(script)); | |||||
StringBuffer dclCmd = new StringBuffer("$"); | |||||
for (int i = 0; i < cmd.length; i++) { | |||||
dclCmd.append(' ').append(cmd[i]); | |||||
} | |||||
out.println(dclCmd.toString()); | |||||
} finally { | |||||
if (out != null) { | |||||
out.close(); | |||||
} | |||||
} | |||||
return script; | |||||
} | |||||
} | |||||
} | } |