Browse Source

Add OpenVMS support to <exec>.

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-ffa450edef68
master
Stefan Bodewig 22 years ago
parent
commit
f30f3d21cb
4 changed files with 106 additions and 12 deletions
  1. +3
    -0
      WHATSNEW
  2. +16
    -8
      docs/manual/CoreTasks/exec.html
  3. +1
    -1
      src/main/org/apache/tools/ant/taskdefs/ExecTask.java
  4. +86
    -3
      src/main/org/apache/tools/ant/taskdefs/Execute.java

+ 3
- 0
WHATSNEW View File

@@ -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
=================================== ===================================




+ 16
- 8
docs/manual/CoreTasks/exec.html View File

@@ -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>&lt;arg&gt;</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>&lt;env&gt;</code> elements.</p>


<h3>Errors and return codes</h3> <h3>Errors and return codes</h3>
By default the return code of a &lt;exec&gt; is ignored; when you set By default the return code of a &lt;exec&gt; 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 &lt;exec&gt; halts the build unless <code>failifexecutionfails</code> then &lt;exec&gt; 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;


+ 1
- 1
src/main/org/apache/tools/ant/taskdefs/ExecTask.java View File

@@ -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());


+ 86
- 3
src/main/org/apache/tools/ant/taskdefs/Execute.java View File

@@ -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;
}

}
} }

Loading…
Cancel
Save