From c31f5ae25766b6bab90b1d0ac86eab2c7f66b804 Mon Sep 17 00:00:00 2001 From: Steve Loughran Date: Wed, 6 Oct 2004 22:41:52 +0000 Subject: [PATCH] Somewhat reworked patch for bug# 31106, submitted by Isao Yanagimachi. Took the opportunity to clean up the tasks slightly, such as removing duplication in various methods. We need a unit test for long command line java, and many parameter java, just to see what breaks. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@276922 13f79535-47bb-0310-9956-ffa450edef68 --- .../apache/tools/ant/taskdefs/Execute.java | 40 +++--- .../org/apache/tools/ant/taskdefs/Java.java | 121 +++++++++++++----- .../compilers/DefaultCompilerAdapter.java | 14 +- .../ant/taskdefs/compilers/JavacExternal.java | 43 ++++++- .../org/apache/tools/ant/util/FileUtils.java | 10 ++ .../apache/tools/ant/util/JavaEnvUtils.java | 34 ++++- 6 files changed, 197 insertions(+), 65 deletions(-) diff --git a/src/main/org/apache/tools/ant/taskdefs/Execute.java b/src/main/org/apache/tools/ant/taskdefs/Execute.java index 258763d2d..89cf7dfbc 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Execute.java +++ b/src/main/org/apache/tools/ant/taskdefs/Execute.java @@ -33,6 +33,7 @@ import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.Task; +import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.taskdefs.condition.Os; import org.apache.tools.ant.types.Commandline; @@ -56,6 +57,9 @@ public class Execute { private File workingDirectory = null; private Project project = null; private boolean newEnvironment = false; + //TODO: nothing appears to read this. + private boolean spawn = false; + /** Controls whether the VM is used to launch commands, where possible */ private boolean useVMLauncher = true; @@ -64,7 +68,6 @@ public class Execute { private static CommandLauncher vmLauncher = null; private static CommandLauncher shellLauncher = null; private static Vector procEnvironment = null; - private boolean spawn = false; /** Used to destroy processes when the VM exits. */ private static ProcessDestroyer processDestroyer = new ProcessDestroyer(); @@ -75,9 +78,7 @@ public class Execute { static { // Try using a JDK 1.3 launcher try { - if (Os.isFamily("openvms")) { - vmLauncher = new VmsCommandLauncher(); - } else if (!Os.isFamily("os/2")) { + if (!Os.isFamily("os/2")) { vmLauncher = new Java13CommandLauncher(); } } catch (NoSuchMethodException exc) { @@ -124,8 +125,12 @@ public class Execute { shellLauncher = new PerlScriptCommandLauncher("bin/antRun.pl", baseLauncher); } else if (Os.isFamily("openvms")) { - // the vmLauncher already uses the shell - shellLauncher = vmLauncher; + // OpenVMS + try { + shellLauncher = new VmsCommandLauncher(); + } catch (NoSuchMethodException exc) { + // Ignore and keep trying + } } else { // Generic shellLauncher = new ScriptCommandLauncher("bin/antRun", @@ -304,6 +309,11 @@ public class Execute { ExecuteWatchdog watchdog) { setStreamHandler(streamHandler); this.watchdog = watchdog; + //By default, use the shell launcher for VMS + // + if (Os.isFamily("openvms")) { + useVMLauncher = false; + } } /** @@ -666,18 +676,9 @@ public class Execute { * @param process the Process. */ public static void closeStreams(Process process) { - try { - process.getInputStream().close(); - } catch (IOException eyeOhEx) { - } - try { - process.getOutputStream().close(); - } catch (IOException eyeOhEx) { - } - try { - process.getErrorStream().close(); - } catch (IOException eyeOhEx) { - } + FileUtils.close(process.getInputStream()); + FileUtils.close(process.getOutputStream()); + FileUtils.close(process.getErrorStream()); } /** @@ -1151,7 +1152,8 @@ public class Execute { */ private File createCommandFile(String[] cmd, String[] env) throws IOException { - File script = File.createTempFile("ANT", ".COM"); + File script = FileUtils.newFileUtils().createTempFile("ANT", ".COM",null); + //TODO: bind the longevity of the file to the exe script.deleteOnExit(); PrintWriter out = null; try { diff --git a/src/main/org/apache/tools/ant/taskdefs/Java.java b/src/main/org/apache/tools/ant/taskdefs/Java.java index b36cb40d5..68b6e591d 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Java.java +++ b/src/main/org/apache/tools/ant/taskdefs/Java.java @@ -35,6 +35,8 @@ import org.apache.tools.ant.types.Reference; import org.apache.tools.ant.types.Assertions; import org.apache.tools.ant.types.Permissions; import org.apache.tools.ant.types.RedirectorElement; +import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.util.JavaEnvUtils; /** * Launcher for Java applications. Allows use of @@ -732,29 +734,8 @@ public class Java extends Task { Execute exe = new Execute(redirector.createHandler(), createWatchdog()); - exe.setAntRun(getProject()); - - if (dir == null) { - dir = getProject().getBaseDir(); - } else if (!dir.exists() || !dir.isDirectory()) { - throw new BuildException(dir.getAbsolutePath() - + " is not a valid directory", - getLocation()); - } - - exe.setWorkingDirectory(dir); - - String[] environment = env.getVariables(); - if (environment != null) { - for (int i = 0; i < environment.length; i++) { - log("Setting environment variable: " + environment[i], - Project.MSG_VERBOSE); - } - } - exe.setNewenvironment(newEnvironment); - exe.setEnvironment(environment); + setupExecutable(exe, command); - exe.setCommandline(command); try { int rc = exe.execute(); redirector.complete(); @@ -767,6 +748,8 @@ public class Java extends Task { } } + + /** * Executes the given classname with the given arguments in a separate VM. */ @@ -774,18 +757,33 @@ public class Java extends Task { Execute exe = new Execute(); - exe.setAntRun(getProject()); - - if (dir == null) { - dir = getProject().getBaseDir(); - } else if (!dir.exists() || !dir.isDirectory()) { - throw new BuildException(dir.getAbsolutePath() - + " is not a valid directory", - getLocation()); + setupExecutable(exe, command); + try { + exe.spawn(); + } catch (IOException e) { + throw new BuildException(e, getLocation()); } + } - exe.setWorkingDirectory(dir); + /** + * Do all configuration for an executable that + * is common across the {@link #fork(String[])} and + * {@link #spawn(String[])} methods + * @param exe executable + * @param command command to execute + */ + private void setupExecutable(Execute exe, String[] command) { + exe.setAntRun(getProject()); + setupWorkingDir(exe); + setupEnvironment(exe); + setupCommandLine(exe, command); + } + /** + * set up our environment variables + * @param exe + */ + private void setupEnvironment(Execute exe) { String[] environment = env.getVariables(); if (environment != null) { for (int i = 0; i < environment.length; i++) { @@ -795,14 +793,69 @@ public class Java extends Task { } exe.setNewenvironment(newEnvironment); exe.setEnvironment(environment); + } + + /** + * set the working dir of the new process + * @param exe + * @throws BuildException if the dir doesn't exist. + */ + private void setupWorkingDir(Execute exe) { + if (dir == null) { + dir = getProject().getBaseDir(); + } else if (!dir.exists() || !dir.isDirectory()) { + throw new BuildException(dir.getAbsolutePath() + + " is not a valid directory", + getLocation()); + } + exe.setWorkingDirectory(dir); + } - exe.setCommandline(command); + /** + * set the command line for the exe. + * On VMS, hands off to {@link #setupCommandLineForVMS(Execute, String[])} + * @param exe + * @param command + */ + private void setupCommandLine(Execute exe, String[] command) { + //On VMS platform, we need to create a special java options file + //containing the arguments and classpath for the java command. + //The special file is supported by the "-V" switch on the VMS JVM. + if (Os.isFamily("openvms")) { + setupCommandLineForVMS(exe, command); + } else { + exe.setCommandline(command); + } + } + + /** + * On VMS platform, we need to create a special java options file + * containing the arguments and classpath for the java command. + * The special file is supported by the "-V" switch on the VMS JVM. + * + * @param exe + * @param command + */ + private void setupCommandLineForVMS(Execute exe, String[] command) { + //Use the VM launcher instead of shell launcher on VMS + exe.setVMLauncher(true); + File vmsJavaOptionFile=null; try { - exe.spawn(); + String [] args = new String[command.length-1]; + System.arraycopy(command, 1, args, 0, command.length-1); + vmsJavaOptionFile = JavaEnvUtils.createVmsJavaOptionFile(args); + //we mark the file to be deleted on exit. + //the alternative would be to cache the filename and delete + //after execution finished, which is much better for long-lived runtimes + //though spawning complicates things... + vmsJavaOptionFile.deleteOnExit(); + String [] vmsCmd = {command[0], "-V", vmsJavaOptionFile.getPath()}; + exe.setCommandline(vmsCmd); } catch (IOException e) { - throw new BuildException(e, getLocation()); + throw new BuildException("Failed to create a temporary file for \"-V\" switch"); } } + /** * Executes the given classname with the given arguments as it * was a command line application. diff --git a/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java b/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java index eae0a305a..1a4edbf76 100644 --- a/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java +++ b/src/main/org/apache/tools/ant/taskdefs/compilers/DefaultCompilerAdapter.java @@ -31,6 +31,7 @@ import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.util.FileUtils; import org.apache.tools.ant.util.JavaEnvUtils; +import org.apache.tools.ant.taskdefs.condition.Os; /** * This is the default implementation for the CompilerAdapter interface. @@ -416,13 +417,7 @@ public abstract class DefaultCompilerAdapter implements CompilerAdapter { throw new BuildException("Error creating temporary file", e, location); } finally { - if (out != null) { - try { - out.close(); - } catch (Throwable t) { - // ignore - } - } + FileUtils.close(out); } } else { commandArray = args; @@ -433,6 +428,11 @@ public abstract class DefaultCompilerAdapter implements CompilerAdapter { new LogStreamHandler(attributes, Project.MSG_INFO, Project.MSG_WARN)); + if (Os.isFamily("openvms")) { + //Use the VM launcher instead of shell launcher on VMS + //for java + exe.setVMLauncher(true); + } exe.setAntRun(project); exe.setWorkingDirectory(project.getBaseDir()); exe.setCommandline(commandArray); diff --git a/src/main/org/apache/tools/ant/taskdefs/compilers/JavacExternal.java b/src/main/org/apache/tools/ant/taskdefs/compilers/JavacExternal.java index 2aba3a8f0..9059f4bfa 100644 --- a/src/main/org/apache/tools/ant/taskdefs/compilers/JavacExternal.java +++ b/src/main/org/apache/tools/ant/taskdefs/compilers/JavacExternal.java @@ -17,9 +17,15 @@ package org.apache.tools.ant.taskdefs.compilers; +import java.io.IOException; +import java.io.File; + import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Project; import org.apache.tools.ant.types.Commandline; +import org.apache.tools.ant.taskdefs.condition.Os; +import org.apache.tools.ant.util.JavaEnvUtils; +import org.apache.tools.ant.util.FileUtils; /** * Performs a compile using javac externally. @@ -39,11 +45,40 @@ public class JavacExternal extends DefaultCompilerAdapter { setupModernJavacCommandlineSwitches(cmd); int firstFileName = assumeJava11() ? -1 : cmd.size(); logAndAddFilesToCompile(cmd); - + //On VMS platform, we need to create a special java options file + //containing the arguments and classpath for the javac command. + //The special file is supported by the "-V" switch on the VMS JVM. + if (Os.isFamily("openvms")) { + return execOnVMS(cmd, firstFileName); + } return - executeExternalCompile(cmd.getCommandline(), firstFileName, - true) - == 0; + executeExternalCompile(cmd.getCommandline(), firstFileName, + true) + == 0; + } + + /** + * helper method to execute our command on VMS. + * @param cmd + * @param firstFileName + * @return + */ + private boolean execOnVMS(Commandline cmd, int firstFileName) { + File vmsFile=null; + try { + vmsFile = JavaEnvUtils.createVmsJavaOptionFile(cmd.getArguments()); + String[] commandLine = {cmd.getExecutable(), + "-V", + vmsFile.getPath()}; + return 0==executeExternalCompile(commandLine, + firstFileName, + true); + + } catch (IOException e) { + throw new BuildException("Failed to create a temporary file for \"-V\" switch"); + } finally { + FileUtils.delete(vmsFile); + } } } diff --git a/src/main/org/apache/tools/ant/util/FileUtils.java b/src/main/org/apache/tools/ant/util/FileUtils.java index fc8bb47a6..05fcb91f8 100644 --- a/src/main/org/apache/tools/ant/util/FileUtils.java +++ b/src/main/org/apache/tools/ant/util/FileUtils.java @@ -1449,5 +1449,15 @@ public class FileUtils { } } + /** + * Delete the file with {@link File#delete()} if the argument is not null. + * Do nothing on a null argument + * @param file file to delete + */ + public static void delete(File file) { + if(file!=null) { + file.delete(); + } + } } diff --git a/src/main/org/apache/tools/ant/util/JavaEnvUtils.java b/src/main/org/apache/tools/ant/util/JavaEnvUtils.java index f914417bc..be5e99b62 100644 --- a/src/main/org/apache/tools/ant/util/JavaEnvUtils.java +++ b/src/main/org/apache/tools/ant/util/JavaEnvUtils.java @@ -17,6 +17,10 @@ package org.apache.tools.ant.util; import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.FileWriter; +import java.io.BufferedWriter; import java.util.Vector; import org.apache.tools.ant.taskdefs.condition.Os; @@ -28,6 +32,9 @@ import org.apache.tools.ant.taskdefs.condition.Os; */ public class JavaEnvUtils { + private JavaEnvUtils() { + } + /** Are we on a DOS-based system */ private static final boolean isDos = Os.isFamily("dos"); /** Are we on Novell NetWare */ @@ -115,7 +122,7 @@ public class JavaEnvUtils { * @since Ant 1.5 */ public static boolean isJavaVersion(String version) { - return javaVersion == version; + return javaVersion.equals(version); } /** @@ -332,4 +339,29 @@ public class JavaEnvUtils { } return jrePackages; } + + /** + * + * Writes the command into a temporary DCL script and returns the + * corresponding File object. + * It is the job of the caller to delete the file on exit. + * @param cmd + * @return + * @throws IOException + */ + public static File createVmsJavaOptionFile(String[] cmd) + throws IOException { + File script = FileUtils.newFileUtils() + .createTempFile("ANT", ".JAVA_OPTS", null); + PrintWriter out = null; + try { + out = new PrintWriter(new BufferedWriter(new FileWriter(script))); + for (int i = 0; i < cmd.length; i++) { + out.println(cmd[i]); + } + } finally { + FileUtils.close(out); + } + return script; + } }