diff --git a/WHATSNEW b/WHATSNEW index 0ee2b5a35..e2136c4f0 100644 --- a/WHATSNEW +++ b/WHATSNEW @@ -513,6 +513,9 @@ Other changes: mappings per source path. This behaviour is enabled by using an enablemultiplemapping attribute. Bugzilla Report 21320. +* will now work on OpenVMS (please read the notes in + 's manual page). Bugzilla Report 21877. + Changes from Ant 1.5.2 to Ant 1.5.3 =================================== diff --git a/docs/manual/CoreTasks/exec.html b/docs/manual/CoreTasks/exec.html index bc7916e32..93ffa84dc 100644 --- a/docs/manual/CoreTasks/exec.html +++ b/docs/manual/CoreTasks/exec.html @@ -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.

+

OpenVMS Users

+

The command specified using executable and <arg> +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 +JAVA$FORK_SUPPORT_CHDIR is set to TRUE (see the JDK Release +Notes). +

+

Parameters

@@ -108,7 +116,7 @@ Windows executable and is not aware of Cygwin conventions. + command should be stored. Only of interest if failonerror=false. @@ -120,7 +128,7 @@ Windows executable and is not aware of Cygwin conventions. + return code signaling failure. Defaults to false. @@ -204,15 +212,15 @@ system command via nested <env> elements.

Errors and return codes

By default the return code of a <exec> is ignored; when you set -failonerror="true" then any non zero response is treated as an -error. Alternatively, you can set resultproperty to the name -of a property and have it assigned to the result code (barring immutability, -of course). +failonerror="true" then any return code signaling failure +(OS specific) causes the build to fail. Alternatively, you can set +resultproperty to the name of a property and have it assigned to +the result code (barring immutability, of course).

If the attempt to start the program fails with an OS dependent error code, then <exec> halts the build unless failifexecutionfails -is set. You can use that to run a program if it exists, but otherwise -do nothing. +is set to false. You can use that to run a program if it exists, but +otherwise do nothing.

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; diff --git a/src/main/org/apache/tools/ant/taskdefs/ExecTask.java b/src/main/org/apache/tools/ant/taskdefs/ExecTask.java index 9e4bcabf7..dbd95f357 100644 --- a/src/main/org/apache/tools/ant/taskdefs/ExecTask.java +++ b/src/main/org/apache/tools/ant/taskdefs/ExecTask.java @@ -413,7 +413,7 @@ public class ExecTask extends Task { log("Timeout: killed the sub-process", Project.MSG_WARN); } maybeSetResultPropertyValue(returnCode); - if (returnCode != 0) { + if (Execute.isFailure(returnCode)) { if (failOnError) { throw new BuildException(getTaskType() + " returned: " + returnCode, getLocation()); diff --git a/src/main/org/apache/tools/ant/taskdefs/Execute.java b/src/main/org/apache/tools/ant/taskdefs/Execute.java index 8fba313d2..88e4eee00 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Execute.java +++ b/src/main/org/apache/tools/ant/taskdefs/Execute.java @@ -57,7 +57,9 @@ package org.apache.tools.ant.taskdefs; import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; +import java.io.FileWriter; import java.io.IOException; +import java.io.PrintWriter; import java.io.StringReader; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -109,7 +111,9 @@ public class Execute { static { // Try using a JDK 1.3 launcher try { - if (!Os.isFamily("os/2")) { + if (Os.isFamily("openvms")) { + vmLauncher = new VmsCommandLauncher(); + } else if (!Os.isFamily("os/2")) { vmLauncher = new Java13CommandLauncher(); } } catch (NoSuchMethodException exc) { @@ -155,6 +159,9 @@ public class Execute { shellLauncher = new PerlScriptCommandLauncher("bin/antRun.pl", baseLauncher); + } else if (Os.isFamily("openvms")) { + // the vmLauncher already uses the shell + shellLauncher = vmLauncher; } else { // Generic shellLauncher = new ScriptCommandLauncher("bin/antRun", @@ -249,6 +256,9 @@ public class Execute { // rely on PATH String[] cmd = {"env"}; return cmd; + } else if (Os.isFamily("openvms")) { + String[] cmd = {"show", "logical"}; + return cmd; } else { // MAC OS 9 and previous // 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, - * or Project.INVALID if no exit value has been received + * or Execute.INVALID if no exit value has been received */ public int getExitValue() { return exitValue; } + /** + * Checks whether exitValue signals a failure on the current + * system (OS specific). + * @param exitValue the exit value (return code) to be checked + * @return true if exitValue 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 * @return true iff a watchdog had to kill the process @@ -912,4 +938,61 @@ public class Execute { 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 workingDir 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; + } + + } }

resultproperty the name of a property in which the return code of the - command should be stored. Only of interest if failonerror=false No
failonerror Stop the buildprocess if the command exits with a - returncode other than 0. Defaults to false No