git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@275346 13f79535-47bb-0310-9956-ffa450edef68master
@@ -20,20 +20,27 @@ Windows executable and is not aware of Cygwin conventions. | |||||
</p> | </p> | ||||
<h4>OpenVMS Users</h4> | <h4>OpenVMS Users</h4> | ||||
<p>The command specified using <code>executable</code> and | <p>The command specified using <code>executable</code> and | ||||
<code><arg></code> elements is executed exactly as specified | <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> | |||||
inside a temporary DCL script. This has some implications: | |||||
<ul> | |||||
<li>paths have to be written in VMS style</li> | |||||
<li>if your <code>executable</code> points to a DCL script remember to | |||||
prefix it with an <code>@</code>-sign | |||||
(e.g. <code>executable="@[FOO]BAR.COM"</code>), just as you would in a | |||||
DCL script</li> | |||||
</ul> | |||||
For <code><exec></code> to work in an environment with a Java VM | |||||
older than version 1.4.1-2 it is also <i>required</i> that the logical | |||||
<code>JAVA$FORK_SUPPORT_CHDIR</code> is set to <code>TRUE</code> in | |||||
the job table (see the <i>JDK Release Notes</i>).</p> | |||||
<p>Please note that the Java VM provided by HP doesn't follow OpenVMS' | <p>Please note that the Java VM provided by HP doesn't follow OpenVMS' | ||||
conventions of exit codes. If you run a Java VM with this task, the | conventions of exit codes. If you run a Java VM with this task, the | ||||
task may falsely claim that an error occured (or silently ignore an | task may falsely claim that an error occured (or silently ignore an | ||||
error). Don't use this task to run <code>JAVA.EXE</code>, use a | error). Don't use this task to run <code>JAVA.EXE</code>, use a | ||||
<code><java></code> task with the <code>fork</code> attribute | <code><java></code> task with the <code>fork</code> attribute | ||||
set ti <code>true</code> instead as this task will follow the VM's | |||||
set to <code>true</code> instead as this task will follow the VM's | |||||
interpretation of exit codes.</p> | interpretation of exit codes.</p> | ||||
<h3>Parameters</h3> | <h3>Parameters</h3> | ||||
@@ -65,6 +65,7 @@ import java.util.Map; | |||||
import java.util.Set; | import java.util.Set; | ||||
import java.util.Vector; | import java.util.Vector; | ||||
import org.apache.tools.ant.taskdefs.condition.Os; | |||||
import org.apache.tools.ant.types.Resource; | import org.apache.tools.ant.types.Resource; | ||||
import org.apache.tools.ant.types.ResourceFactory; | import org.apache.tools.ant.types.ResourceFactory; | ||||
import org.apache.tools.ant.types.selectors.FileSelector; | import org.apache.tools.ant.types.selectors.FileSelector; | ||||
@@ -163,6 +164,8 @@ import org.apache.tools.ant.util.FileUtils; | |||||
public class DirectoryScanner | public class DirectoryScanner | ||||
implements FileScanner, SelectorScanner, ResourceFactory { | implements FileScanner, SelectorScanner, ResourceFactory { | ||||
/** Is OpenVMS the operating system we're running on? */ | |||||
private static final boolean ON_VMS = Os.isFamily("openvms"); | |||||
/** | /** | ||||
* Patterns which should be excluded by default. | * Patterns which should be excluded by default. | ||||
@@ -725,7 +728,7 @@ public class DirectoryScanner | |||||
File canonFile = myfile.getCanonicalFile(); | File canonFile = myfile.getCanonicalFile(); | ||||
String path = fileUtils.removeLeadingPath(canonBase, | String path = fileUtils.removeLeadingPath(canonBase, | ||||
canonFile); | canonFile); | ||||
if (!path.equals(currentelement)) { | |||||
if (!path.equals(currentelement) || ON_VMS) { | |||||
myfile = findFile(basedir, currentelement); | myfile = findFile(basedir, currentelement); | ||||
if (myfile != null) { | if (myfile != null) { | ||||
currentelement = | currentelement = | ||||
@@ -621,6 +621,13 @@ public class Execute { | |||||
* @return the patched environment | * @return the patched environment | ||||
*/ | */ | ||||
private String[] patchEnvironment() { | private String[] patchEnvironment() { | ||||
// On OpenVMS Runtime#exec() doesn't support the environment array, | |||||
// so we only return the new values which then will be set in | |||||
// the generated DCL script, inheriting the parent process environment | |||||
if (Os.isFamily("openvms")) { | |||||
return env; | |||||
} | |||||
Vector osEnv = (Vector) getProcEnvironment().clone(); | Vector osEnv = (Vector) getProcEnvironment().clone(); | ||||
for (int i = 0; i < env.length; i++) { | for (int i = 0; i < env.length; i++) { | ||||
int pos = env[i].indexOf('='); | int pos = env[i].indexOf('='); | ||||
@@ -1119,7 +1126,7 @@ public class Execute { | |||||
*/ | */ | ||||
public Process exec(Project project, String[] cmd, String[] env) | public Process exec(Project project, String[] cmd, String[] env) | ||||
throws IOException { | throws IOException { | ||||
String[] vmsCmd = {createCommandFile(cmd).getPath()}; | |||||
String[] vmsCmd = {createCommandFile(cmd, env).getPath()}; | |||||
return super.exec(project, vmsCmd, env); | return super.exec(project, vmsCmd, env); | ||||
} | } | ||||
@@ -1131,7 +1138,7 @@ public class Execute { | |||||
*/ | */ | ||||
public Process exec(Project project, String[] cmd, String[] env, | public Process exec(Project project, String[] cmd, String[] env, | ||||
File workingDir) throws IOException { | File workingDir) throws IOException { | ||||
String[] vmsCmd = {createCommandFile(cmd).getPath()}; | |||||
String[] vmsCmd = {createCommandFile(cmd, env).getPath()}; | |||||
return super.exec(project, vmsCmd, env, workingDir); | return super.exec(project, vmsCmd, env, workingDir); | ||||
} | } | ||||
@@ -1139,17 +1146,34 @@ public class Execute { | |||||
* Writes the command into a temporary DCL script and returns the | * Writes the command into a temporary DCL script and returns the | ||||
* corresponding File object. The script will be deleted on exit. | * corresponding File object. The script will be deleted on exit. | ||||
*/ | */ | ||||
private File createCommandFile(String[] cmd) throws IOException { | |||||
private File createCommandFile(String[] cmd, String[] env) | |||||
throws IOException { | |||||
File script = File.createTempFile("ANT", ".COM"); | File script = File.createTempFile("ANT", ".COM"); | ||||
script.deleteOnExit(); | script.deleteOnExit(); | ||||
PrintWriter out = null; | PrintWriter out = null; | ||||
try { | try { | ||||
out = new PrintWriter(new FileWriter(script)); | out = new PrintWriter(new FileWriter(script)); | ||||
StringBuffer dclCmd = new StringBuffer("$"); | |||||
for (int i = 0; i < cmd.length; i++) { | |||||
dclCmd.append(' ').append(cmd[i]); | |||||
// add the environment as logicals to the DCL script | |||||
if (env != null) { | |||||
int eqIndex; | |||||
for (int i = 1; i < env.length ; i++) { | |||||
eqIndex = env[i].indexOf('='); | |||||
if (eqIndex != -1) { | |||||
out.print("$ DEFINE/NOLOG "); | |||||
out.print(env[i].substring(0, eqIndex)); | |||||
out.print(" \""); | |||||
out.print(env[i].substring(eqIndex + 1)); | |||||
out.println('\"'); | |||||
} | |||||
} | |||||
} | |||||
out.print("$ " + cmd[0]); | |||||
for (int i = 1; i < cmd.length ; i++) { | |||||
out.println(" -"); | |||||
out.print(cmd[i]); | |||||
} | } | ||||
out.println(dclCmd.toString()); | |||||
} finally { | } finally { | ||||
if (out != null) { | if (out != null) { | ||||
out.close(); | out.close(); | ||||
@@ -824,6 +824,8 @@ public class FileUtils { | |||||
* <li>DOS style paths that start with a drive letter will have | * <li>DOS style paths that start with a drive letter will have | ||||
* \ as the separator.</li> | * \ as the separator.</li> | ||||
* </ul> | * </ul> | ||||
* Unlike <code>File#getCanonicalPath()</code> it specifically doesn't | |||||
* resolve symbolic links. | |||||
* | * | ||||
* @param path the path to be normalized | * @param path the path to be normalized | ||||
* @return the normalized version of the path. | * @return the normalized version of the path. | ||||
@@ -937,6 +939,65 @@ public class FileUtils { | |||||
return new File(path); | return new File(path); | ||||
} | } | ||||
/** | |||||
* Returns a VMS String representation of a <code>File</code> object. | |||||
* This is useful since the JVM by default internally converts VMS paths | |||||
* to Unix style. | |||||
* The returned String is always an absolute path. | |||||
* | |||||
* @param f The <code>File</code> to get the VMS path for. | |||||
* @return The absolute VMS path to <code>f</code>. | |||||
*/ | |||||
public String toVMSPath(File f) { | |||||
// format: "DEVICE:[DIR.SUBDIR]FILE" | |||||
String osPath; | |||||
String path = normalize(f.getAbsolutePath()).getPath(); | |||||
String name = f.getName(); | |||||
boolean isAbsolute = path.charAt(0) == File.separatorChar; | |||||
// treat directories specified using .DIR syntax as files | |||||
boolean isDirectory = f.isDirectory() && | |||||
!name.regionMatches(true, name.length() - 4, ".DIR", 0, 4); | |||||
String device = null; | |||||
StringBuffer directory = null; | |||||
String file = null; | |||||
int index = 0; | |||||
if (isAbsolute) { | |||||
index = path.indexOf(File.separatorChar, 1); | |||||
if (index == -1) { | |||||
return path.substring(1) + ":[000000]"; | |||||
} else { | |||||
device = path.substring(1, index++); | |||||
} | |||||
} | |||||
if (isDirectory) { | |||||
directory = new StringBuffer(path.substring(index). | |||||
replace(File.separatorChar, '.')); | |||||
} else { | |||||
int dirEnd = | |||||
path.lastIndexOf(File.separatorChar, path.length()); | |||||
if (dirEnd == -1 || dirEnd < index) { | |||||
file = path.substring(index); | |||||
} else { | |||||
directory = new StringBuffer(path.substring(index, dirEnd). | |||||
replace(File.separatorChar, '.')); | |||||
index = dirEnd + 1; | |||||
if (path.length() > index) { | |||||
file = path.substring(index); | |||||
} | |||||
} | |||||
} | |||||
if (!isAbsolute && directory != null) { | |||||
directory.insert(0, '.'); | |||||
} | |||||
osPath = ((device != null) ? device + ":" : "") + | |||||
((directory != null) ? "[" + directory + "]" : "") + | |||||
((file != null) ? file : ""); | |||||
return osPath; | |||||
} | |||||
/** | /** | ||||
* Create a temporary file in a given directory. | * Create a temporary file in a given directory. | ||||
* | * | ||||