- /*
- * Copyright 2000-2004 The Apache Software Foundation
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
- package org.apache.tools.ant.taskdefs;
-
- import java.io.OutputStream;
- 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;
- import java.util.HashMap;
- import java.util.Iterator;
- 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.taskdefs.condition.Os;
- import org.apache.tools.ant.types.Commandline;
-
- /**
- * Runs an external program.
- *
- * @since Ant 1.2
- *
- * @version $Revision: 1.68.2.9 $
- */
- public class Execute {
-
- /** Invalid exit code. **/
- public static final int INVALID = Integer.MAX_VALUE;
-
- private String[] cmdl = null;
- private String[] env = null;
- private int exitValue = INVALID;
- private ExecuteStreamHandler streamHandler;
- private ExecuteWatchdog watchdog;
- private File workingDirectory = null;
- private Project project = null;
- private boolean newEnvironment = false;
-
- /** Controls whether the VM is used to launch commands, where possible */
- private boolean useVMLauncher = true;
-
- private static String antWorkingDirectory = System.getProperty("user.dir");
- 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();
-
- /**
- * Builds a command launcher for the OS and JVM we are running under
- */
- static {
- // Try using a JDK 1.3 launcher
- try {
- if (Os.isFamily("openvms")) {
- vmLauncher = new VmsCommandLauncher();
- } else if (!Os.isFamily("os/2")) {
- vmLauncher = new Java13CommandLauncher();
- }
- } catch (NoSuchMethodException exc) {
- // Ignore and keep trying
- }
-
- if (Os.isFamily("mac") && !Os.isFamily("unix")) {
- // Mac
- shellLauncher = new MacCommandLauncher(new CommandLauncher());
- } else if (Os.isFamily("os/2")) {
- // OS/2
- shellLauncher = new OS2CommandLauncher(new CommandLauncher());
- } else if (Os.isFamily("windows")) {
- // Windows. Need to determine which JDK we're running in
-
- CommandLauncher baseLauncher;
- if (System.getProperty("java.version").startsWith("1.1")) {
- // JDK 1.1
- baseLauncher = new Java11CommandLauncher();
- } else {
- // JDK 1.2
- baseLauncher = new CommandLauncher();
- }
-
- if (!Os.isFamily("win9x")) {
- // Windows XP/2000/NT
- shellLauncher = new WinNTCommandLauncher(baseLauncher);
- } else {
- // Windows 98/95 - need to use an auxiliary script
- shellLauncher
- = new ScriptCommandLauncher("bin/antRun.bat", baseLauncher);
- }
- } else if (Os.isFamily("netware")) {
- // NetWare. Need to determine which JDK we're running in
- CommandLauncher baseLauncher;
- if (System.getProperty("java.version").startsWith("1.1")) {
- // JDK 1.1
- baseLauncher = new Java11CommandLauncher();
- } else {
- // JDK 1.2
- baseLauncher = new CommandLauncher();
- }
-
- 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",
- new CommandLauncher());
- }
- }
-
- /**
- * set whether or not you want the process to be spawned
- * default is not spawned
- *
- * @param spawn if true you do not want ant to wait for the end of the process
- *
- * @since ant 1.6
- */
- public void setSpawn(boolean spawn) {
- this.spawn = spawn;
- }
-
- /**
- * Find the list of environment variables for this process.
- *
- * @return a vector containing the environment variables
- * the vector elements are strings formatted like variable = value
- */
- public static synchronized Vector getProcEnvironment() {
- if (procEnvironment != null) {
- return procEnvironment;
- }
-
- procEnvironment = new Vector();
- try {
- ByteArrayOutputStream out = new ByteArrayOutputStream();
- Execute exe = new Execute(new PumpStreamHandler(out));
- exe.setCommandline(getProcEnvCommand());
- // Make sure we do not recurse forever
- exe.setNewenvironment(true);
- int retval = exe.execute();
- if (retval != 0) {
- // Just try to use what we got
- }
-
- BufferedReader in =
- new BufferedReader(new StringReader(toString(out)));
-
- if (Os.isFamily("openvms")) {
- procEnvironment = addVMSLogicals(procEnvironment, in);
- return procEnvironment;
- }
-
- String var = null;
- String line, lineSep = System.getProperty("line.separator");
- while ((line = in.readLine()) != null) {
- if (line.indexOf('=') == -1) {
- // Chunk part of previous env var (UNIX env vars can
- // contain embedded new lines).
- if (var == null) {
- var = lineSep + line;
- } else {
- var += lineSep + line;
- }
- } else {
- // New env var...append the previous one if we have it.
- if (var != null) {
- procEnvironment.addElement(var);
- }
- var = line;
- }
- }
- // Since we "look ahead" before adding, there's one last env var.
- if (var != null) {
- procEnvironment.addElement(var);
- }
- } catch (java.io.IOException exc) {
- exc.printStackTrace();
- // Just try to see how much we got
- }
- return procEnvironment;
- }
-
- private static String[] getProcEnvCommand() {
- if (Os.isFamily("os/2")) {
- // OS/2 - use same mechanism as Windows 2000
- return new String[] {"cmd", "/c", "set" };
- } else if (Os.isFamily("windows")) {
- // Determine if we're running under XP/2000/NT or 98/95
- if (Os.isFamily("win9x")) {
- // Windows 98/95
- return new String[] {"command.com", "/c", "set" };
- } else {
- // Windows XP/2000/NT/2003
- return new String[] {"cmd", "/c", "set" };
- }
- } else if (Os.isFamily("z/os") || Os.isFamily("unix")) {
- // On most systems one could use: /bin/sh -c env
-
- // Some systems have /bin/env, others /usr/bin/env, just try
- String[] cmd = new String[1];
- if (new File("/bin/env").canRead()) {
- cmd[0] = "/bin/env";
- } else if (new File("/usr/bin/env").canRead()) {
- cmd[0] = "/usr/bin/env";
- } else {
- // rely on PATH
- cmd[0] = "env";
- }
- return cmd;
- } else if (Os.isFamily("netware") || Os.isFamily("os/400")) {
- // rely on PATH
- return new String[] {"env"};
- } else if (Os.isFamily("openvms")) {
- return new String[] {"show", "logical"};
- } else {
- // MAC OS 9 and previous
- //TODO: I have no idea how to get it, someone must fix it
- return null;
- }
- }
-
- /**
- * ByteArrayOutputStream#toString doesn't seem to work reliably on
- * OS/390, at least not the way we use it in the execution
- * context.
- *
- * @param bos the output stream that one wants to read
- * @return the output stream as a string, read with
- * special encodings in the case of z/os and os/400
- *
- * @since Ant 1.5
- */
- public static String toString(ByteArrayOutputStream bos) {
- if (Os.isFamily("z/os")) {
- try {
- return bos.toString("Cp1047");
- } catch (java.io.UnsupportedEncodingException e) {
- //noop default encoding used
- }
- } else if (Os.isFamily("os/400")) {
- try {
- return bos.toString("Cp500");
- } catch (java.io.UnsupportedEncodingException e) {
- //noop default encoding used
- }
- }
- return bos.toString();
- }
-
- /**
- * Creates a new execute object using <code>PumpStreamHandler</code> for
- * stream handling.
- */
- public Execute() {
- this(new PumpStreamHandler(), null);
- }
-
-
- /**
- * Creates a new execute object.
- *
- * @param streamHandler the stream handler used to handle the input and
- * output streams of the subprocess.
- */
- public Execute(ExecuteStreamHandler streamHandler) {
- this(streamHandler, null);
- }
-
- /**
- * Creates a new execute object.
- *
- * @param streamHandler the stream handler used to handle the input and
- * output streams of the subprocess.
- * @param watchdog a watchdog for the subprocess or <code>null</code> to
- * to disable a timeout for the subprocess.
- */
- public Execute(ExecuteStreamHandler streamHandler,
- ExecuteWatchdog watchdog) {
- setStreamHandler(streamHandler);
- this.watchdog = watchdog;
- }
-
- /**
- * @since Ant 1.6
- */
- public void setStreamHandler(ExecuteStreamHandler streamHandler) {
- this.streamHandler = streamHandler;
- }
-
- /**
- * Returns the commandline used to create a subprocess.
- *
- * @return the commandline used to create a subprocess
- */
- public String[] getCommandline() {
- return cmdl;
- }
-
-
- /**
- * Sets the commandline of the subprocess to launch.
- *
- * @param commandline the commandline of the subprocess to launch
- */
- public void setCommandline(String[] commandline) {
- cmdl = commandline;
- }
-
- /**
- * Set whether to propagate the default environment or not.
- *
- * @param newenv whether to propagate the process environment.
- */
- public void setNewenvironment(boolean newenv) {
- newEnvironment = newenv;
- }
-
- /**
- * Returns the environment used to create a subprocess.
- *
- * @return the environment used to create a subprocess
- */
- public String[] getEnvironment() {
- if (env == null || newEnvironment) {
- return env;
- }
- return patchEnvironment();
- }
-
-
- /**
- * Sets the environment variables for the subprocess to launch.
- *
- * @param env array of Strings, each element of which has
- * an environment variable settings in format <em>key=value</em>
- */
- public void setEnvironment(String[] env) {
- this.env = env;
- }
-
- /**
- * Sets the working directory of the process to execute.
- *
- * <p>This is emulated using the antRun scripts unless the OS is
- * Windows NT in which case a cmd.exe is spawned,
- * or MRJ and setting user.dir works, or JDK 1.3 and there is
- * official support in java.lang.Runtime.
- *
- * @param wd the working directory of the process.
- */
- public void setWorkingDirectory(File wd) {
- if (wd == null || wd.getAbsolutePath().equals(antWorkingDirectory)) {
- workingDirectory = null;
- } else {
- workingDirectory = wd;
- }
- }
-
- /**
- * Set the name of the antRun script using the project's value.
- *
- * @param project the current project.
- *
- * @throws BuildException not clear when it is going to throw an exception, but
- * it is the method's signature
- */
- public void setAntRun(Project project) throws BuildException {
- this.project = project;
- }
-
- /**
- * Launch this execution through the VM, where possible, rather than through
- * the OS's shell. In some cases and operating systems using the shell will
- * allow the shell to perform additional processing such as associating an
- * executable with a script, etc
- *
- * @param useVMLauncher true if exec should launch through the VM,
- * false if the shell should be used to launch the
- * command.
- */
- public void setVMLauncher(boolean useVMLauncher) {
- this.useVMLauncher = useVMLauncher;
- }
-
- /**
- * Creates a process that runs a command.
- *
- * @param project the Project, only used for logging purposes, may be null.
- * @param command the command to run
- * @param env the environment for the command
- * @param dir the working directory for the command
- * @param useVM use the built-in exec command for JDK 1.3 if available.
- * @return the process started
- * @throws IOException forwarded from the particular launcher used
- *
- * @since Ant 1.5
- */
- public static Process launch(Project project, String[] command,
- String[] env, File dir, boolean useVM)
- throws IOException {
- CommandLauncher launcher
- = vmLauncher != null ? vmLauncher : shellLauncher;
- if (!useVM) {
- launcher = shellLauncher;
- }
-
- if (dir != null && !dir.exists()) {
- throw new BuildException(dir + " doesn't exist.");
- }
- return launcher.exec(project, command, env, dir);
- }
-
- /**
- * Runs a process defined by the command line and returns its exit status.
- *
- * @return the exit status of the subprocess or <code>INVALID</code>
- * @exception java.io.IOException The exception is thrown, if launching
- * of the subprocess failed
- */
- public int execute() throws IOException {
- if (workingDirectory != null && !workingDirectory.exists()) {
- throw new BuildException(workingDirectory + " doesn't exist.");
- }
- final Process process = launch(project, getCommandline(),
- getEnvironment(), workingDirectory,
- useVMLauncher);
-
- try {
- streamHandler.setProcessInputStream(process.getOutputStream());
- streamHandler.setProcessOutputStream(process.getInputStream());
- streamHandler.setProcessErrorStream(process.getErrorStream());
- } catch (IOException e) {
- process.destroy();
- throw e;
- }
- streamHandler.start();
-
- try {
- // add the process to the list of those to destroy if the VM exits
- //
- processDestroyer.add(process);
-
- if (watchdog != null) {
- watchdog.start(process);
- }
- waitFor(process);
-
- if (watchdog != null) {
- watchdog.stop();
- }
- streamHandler.stop();
- closeStreams(process);
-
- if (watchdog != null) {
- watchdog.checkException();
- }
- return getExitValue();
- } finally {
- // remove the process to the list of those to destroy if the VM exits
- //
- processDestroyer.remove(process);
- }
- }
-
- /**
- * Starts a process defined by the command line.
- * Ant will not wait for this process, nor log its output
- *
- * @throws java.io.IOException The exception is thrown, if launching
- * of the subprocess failed
- * @since ant 1.6
- */
- public void spawn() throws IOException {
- if (workingDirectory != null && !workingDirectory.exists()) {
- throw new BuildException(workingDirectory + " doesn't exist.");
- }
- final Process process = launch(project, getCommandline(),
- getEnvironment(), workingDirectory,
- useVMLauncher);
- if (Os.isFamily("windows")) {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- project.log("interruption in the sleep after having spawned a process",
- Project.MSG_VERBOSE);
- }
- }
-
- OutputStream dummyOut = new OutputStream() {
- public void write(int b) throws IOException {
- }
- };
-
- ExecuteStreamHandler streamHandler = new PumpStreamHandler(dummyOut);
- streamHandler.setProcessErrorStream(process.getErrorStream());
- streamHandler.setProcessOutputStream(process.getInputStream());
- streamHandler.start();
- process.getOutputStream().close();
-
- project.log("spawned process " + process.toString(), Project.MSG_VERBOSE);
- }
-
- /**
- * wait for a given process
- *
- * @param process the process one wants to wait for
- */
- protected void waitFor(Process process) {
- try {
- process.waitFor();
- setExitValue(process.exitValue());
- } catch (InterruptedException e) {
- process.destroy();
- }
- }
-
- /**
- * set the exit value
- *
- * @param value exit value of the process
- */
- protected void setExitValue(int value) {
- exitValue = value;
- }
-
- /**
- * Query the exit value of the process.
- * @return the exit value or Execute.INVALID if no exit value has
- * been received
- */
- public int getExitValue() {
- return exitValue;
- }
-
- /**
- * Checks whether <code>exitValue</code> signals a failure on the current
- * system (OS specific).
- *
- * <p><b>Note</b> that this method relies on the conventions of
- * the OS, it will return false results if the application you are
- * running doesn't follow these conventions. One notable
- * exception is the Java VM provided by HP for OpenVMS - it will
- * return 0 if successful (like on any other platform), but this
- * signals a failure on OpenVMS. So if you execute a new Java VM
- * on OpenVMS, you cannot trust this method.</p>
- *
- * @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")) {
- // even 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 if a watchdog had to kill the process
- * @since Ant 1.5
- */
- public boolean killedProcess() {
- return watchdog != null && watchdog.killedProcess();
- }
-
- /**
- * Patch the current environment with the new values from the user.
- * @return the patched environment
- */
- 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();
- for (int i = 0; i < env.length; i++) {
- int pos = env[i].indexOf('=');
- // Get key including "="
- String key = env[i].substring(0, pos + 1);
- int size = osEnv.size();
- for (int j = 0; j < size; j++) {
- if (((String) osEnv.elementAt(j)).startsWith(key)) {
- osEnv.removeElementAt(j);
- break;
- }
- }
- osEnv.addElement(env[i]);
- }
- String[] result = new String[osEnv.size()];
- osEnv.copyInto(result);
- return result;
- }
-
- /**
- * A utility method that runs an external command. Writes the output and
- * error streams of the command to the project log.
- *
- * @param task The task that the command is part of. Used for logging
- * @param cmdline The command to execute.
- *
- * @throws BuildException if the command does not return 0.
- */
- public static void runCommand(Task task, String[] cmdline)
- throws BuildException {
- try {
- task.log(Commandline.describeCommand(cmdline),
- Project.MSG_VERBOSE);
- Execute exe = new Execute(new LogStreamHandler(task,
- Project.MSG_INFO,
- Project.MSG_ERR));
- exe.setAntRun(task.getProject());
- exe.setCommandline(cmdline);
- int retval = exe.execute();
- if (isFailure(retval)) {
- throw new BuildException(cmdline[0]
- + " failed with return code " + retval, task.getLocation());
- }
- } catch (java.io.IOException exc) {
- throw new BuildException("Could not launch " + cmdline[0] + ": "
- + exc, task.getLocation());
- }
- }
-
- /**
- * Close the streams belonging to the given Process.
- * @param process the <CODE>Process</CODE>.
- */
- 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) {
- }
- }
-
- /**
- * This method is VMS specific and used by getProcEnvironment().
- *
- * Parses VMS logicals from <code>in</code> and adds them to
- * <code>environment</code>. <code>in</code> is expected to be the
- * output of "SHOW LOGICAL". The method takes care of parsing the output
- * correctly as well as making sure that a logical defined in multiple
- * tables only gets added from the highest order table. Logicals with
- * multiple equivalence names are mapped to a variable with multiple
- * values separated by a comma (,).
- */
- private static Vector addVMSLogicals(Vector environment, BufferedReader in)
- throws IOException {
- HashMap logicals = new HashMap();
- String logName = null, logValue = null, newLogName;
- String line = null;
- while ((line = in.readLine()) != null) {
- // parse the VMS logicals into required format ("VAR=VAL[,VAL2]")
- if (line.startsWith("\t=")) {
- // further equivalence name of previous logical
- if (logName != null) {
- logValue += "," + line.substring(4, line.length() - 1);
- }
- } else if (line.startsWith(" \"")) {
- // new logical?
- if (logName != null) {
- logicals.put(logName, logValue);
- }
- int eqIndex = line.indexOf('=');
- newLogName = line.substring(3, eqIndex - 2);
- if (logicals.containsKey(newLogName)) {
- // already got this logical from a higher order table
- logName = null;
- } else {
- logName = newLogName;
- logValue = line.substring(eqIndex + 3, line.length() - 1);
- }
- }
- }
- // Since we "look ahead" before adding, there's one last env var.
- if (logName != null) {
- logicals.put(logName, logValue);
- }
-
- for (Iterator i = logicals.keySet().iterator(); i.hasNext();) {
- String logical = (String) i.next();
- environment.add(logical + "=" + logicals.get(logical));
- }
- return environment;
- }
-
- /**
- * A command launcher for a particular JVM/OS platform. This class is
- * a general purpose command launcher which can only launch commands in
- * the current working directory.
- */
- private static class CommandLauncher {
- /**
- * Launches the given command in a new process.
- *
- * @param project The project that the command is part of
- * @param cmd The command to execute
- * @param env The environment for the new process. If null,
- * the environment of the current process is used.
- * @throws IOException if attempting to run a command in a specific directory
- */
- public Process exec(Project project, String[] cmd, String[] env)
- throws IOException {
- if (project != null) {
- project.log("Execute:CommandLauncher: "
- + Commandline.describeCommand(cmd), Project.MSG_DEBUG);
- }
- return Runtime.getRuntime().exec(cmd, env);
- }
-
- /**
- * Launches the given command in a new process, in the given working
- * directory.
- *
- * @param project The project that the command is part of
- * @param cmd The command to execute
- * @param env The environment for the new process. If null,
- * the environment of the current process is used.
- * @param workingDir The directory to start the command in. If null,
- * the current directory is used
- * @throws IOException if trying to change directory
- */
- public Process exec(Project project, String[] cmd, String[] env,
- File workingDir) throws IOException {
- if (workingDir == null) {
- return exec(project, cmd, env);
- }
- throw new IOException("Cannot execute a process in different "
- + "directory under this JVM");
- }
- }
-
- /**
- * A command launcher for JDK/JRE 1.1 under Windows. Fixes quoting problems
- * in Runtime.exec(). Can only launch commands in the current working
- * directory
- */
- private static class Java11CommandLauncher extends CommandLauncher {
- /**
- * Launches the given command in a new process. Needs to quote
- * arguments
- * @param project the ant project
- * @param cmd the command line to execute as an array of strings
- * @param env the environment to set as an array of strings
- * @throws IOException probably forwarded from Runtime#exec
- */
- public Process exec(Project project, String[] cmd, String[] env)
- throws IOException {
- // Need to quote arguments with spaces, and to escape
- // quote characters
- String[] newcmd = new String[cmd.length];
- for (int i = 0; i < cmd.length; i++) {
- newcmd[i] = Commandline.quoteArgument(cmd[i]);
- }
- if (project != null) {
- project.log("Execute:Java11CommandLauncher: "
- + Commandline.describeCommand(newcmd), Project.MSG_DEBUG);
- }
- return Runtime.getRuntime().exec(newcmd, env);
- }
- }
-
- /**
- * A command launcher for JDK/JRE 1.3 (and higher). Uses the built-in
- * Runtime.exec() command
- */
- private static class Java13CommandLauncher extends CommandLauncher {
- public Java13CommandLauncher() throws NoSuchMethodException {
- // Locate method Runtime.exec(String[] cmdarray,
- // String[] envp, File dir)
- myExecWithCWD = Runtime.class.getMethod("exec",
- new Class[] {String[].class, String[].class, File.class});
- }
-
- /**
- * Launches the given command in a new process, in the given working
- * directory
- * @param project the ant project
- * @param cmd the command line to execute as an array of strings
- * @param env the environment to set as an array of strings
- * @param workingDir the working directory where the command should run
- * @throws IOException probably forwarded from Runtime#exec
- */
- public Process exec(Project project, String[] cmd, String[] env,
- File workingDir) throws IOException {
- try {
- if (project != null) {
- project.log("Execute:Java13CommandLauncher: "
- + Commandline.describeCommand(cmd), Project.MSG_DEBUG);
- }
- Object[] arguments = {cmd, env, workingDir};
- return (Process) myExecWithCWD.invoke(Runtime.getRuntime(),
- arguments);
- } catch (InvocationTargetException exc) {
- Throwable realexc = exc.getTargetException();
- if (realexc instanceof ThreadDeath) {
- throw (ThreadDeath) realexc;
- } else if (realexc instanceof IOException) {
- throw (IOException) realexc;
- } else {
- throw new BuildException("Unable to execute command",
- realexc);
- }
- } catch (Exception exc) {
- // IllegalAccess, IllegalArgument, ClassCast
- throw new BuildException("Unable to execute command", exc);
- }
- }
-
- private Method myExecWithCWD;
- }
-
- /**
- * A command launcher that proxies another command launcher.
- *
- * Sub-classes override exec(args, env, workdir)
- */
- private static class CommandLauncherProxy extends CommandLauncher {
- CommandLauncherProxy(CommandLauncher launcher) {
- myLauncher = launcher;
- }
-
- /**
- * Launches the given command in a new process. Delegates this
- * method to the proxied launcher
- * @param project the ant project
- * @param cmd the command line to execute as an array of strings
- * @param env the environment to set as an array of strings
- * @throws IOException forwarded from the exec method of the command launcher
- */
- public Process exec(Project project, String[] cmd, String[] env)
- throws IOException {
- return myLauncher.exec(project, cmd, env);
- }
-
- private CommandLauncher myLauncher;
- }
-
- /**
- * A command launcher for OS/2 that uses 'cmd.exe' when launching
- * commands in directories other than the current working
- * directory.
- *
- * <p>Unlike Windows NT and friends, OS/2's cd doesn't support the
- * /d switch to change drives and directories in one go.</p>
- */
- private static class OS2CommandLauncher extends CommandLauncherProxy {
- OS2CommandLauncher(CommandLauncher launcher) {
- super(launcher);
- }
-
- /**
- * Launches the given command in a new process, in the given working
- * directory.
- * @param project the ant project
- * @param cmd the command line to execute as an array of strings
- * @param env the environment to set as an array of strings
- * @param workingDir working directory where the command should run
- * @throws IOException forwarded from the exec method of the command launcher
- */
- public Process exec(Project project, String[] cmd, String[] env,
- File workingDir) throws IOException {
- File commandDir = workingDir;
- if (workingDir == null) {
- if (project != null) {
- commandDir = project.getBaseDir();
- } else {
- return exec(project, cmd, env);
- }
- }
-
- // Use cmd.exe to change to the specified drive and
- // directory before running the command
- final int preCmdLength = 7;
- final String cmdDir = commandDir.getAbsolutePath();
- String[] newcmd = new String[cmd.length + preCmdLength];
- newcmd[0] = "cmd";
- newcmd[1] = "/c";
- newcmd[2] = cmdDir.substring(0, 2);
- newcmd[3] = "&&";
- newcmd[4] = "cd";
- newcmd[5] = cmdDir.substring(2);
- newcmd[6] = "&&";
- System.arraycopy(cmd, 0, newcmd, preCmdLength, cmd.length);
-
- return exec(project, newcmd, env);
- }
- }
-
- /**
- * A command launcher for Windows XP/2000/NT that uses 'cmd.exe' when
- * launching commands in directories other than the current working
- * directory.
- */
- private static class WinNTCommandLauncher extends CommandLauncherProxy {
- WinNTCommandLauncher(CommandLauncher launcher) {
- super(launcher);
- }
-
- /**
- * Launches the given command in a new process, in the given working
- * directory.
- * @param project the ant project
- * @param cmd the command line to execute as an array of strings
- * @param env the environment to set as an array of strings
- * @param workingDir working directory where the command should run
- * @throws IOException forwarded from the exec method of the command launcher
- */
- public Process exec(Project project, String[] cmd, String[] env,
- File workingDir) throws IOException {
- File commandDir = workingDir;
- if (workingDir == null) {
- if (project != null) {
- commandDir = project.getBaseDir();
- } else {
- return exec(project, cmd, env);
- }
- }
-
- // Use cmd.exe to change to the specified directory before running
- // the command
- final int preCmdLength = 6;
- String[] newcmd = new String[cmd.length + preCmdLength];
- newcmd[0] = "cmd";
- newcmd[1] = "/c";
- newcmd[2] = "cd";
- newcmd[3] = "/d";
- newcmd[4] = commandDir.getAbsolutePath();
- newcmd[5] = "&&";
- System.arraycopy(cmd, 0, newcmd, preCmdLength, cmd.length);
-
- return exec(project, newcmd, env);
- }
- }
-
- /**
- * A command launcher for Mac that uses a dodgy mechanism to change
- * working directory before launching commands.
- */
- private static class MacCommandLauncher extends CommandLauncherProxy {
- MacCommandLauncher(CommandLauncher launcher) {
- super(launcher);
- }
-
- /**
- * Launches the given command in a new process, in the given working
- * directory
- * @param project the ant project
- * @param cmd the command line to execute as an array of strings
- * @param env the environment to set as an array of strings
- * @param workingDir working directory where the command should run
- * @throws IOException forwarded from the exec method of the command launcher
- */
- public Process exec(Project project, String[] cmd, String[] env,
- File workingDir) throws IOException {
- if (workingDir == null) {
- return exec(project, cmd, env);
- }
-
- System.getProperties().put("user.dir", workingDir.getAbsolutePath());
- try {
- return exec(project, cmd, env);
- } finally {
- System.getProperties().put("user.dir", antWorkingDirectory);
- }
- }
- }
-
- /**
- * A command launcher that uses an auxiliary script to launch commands
- * in directories other than the current working directory.
- */
- private static class ScriptCommandLauncher extends CommandLauncherProxy {
- ScriptCommandLauncher(String script, CommandLauncher launcher) {
- super(launcher);
- myScript = script;
- }
-
- /**
- * Launches the given command in a new process, in the given working
- * directory
- */
- public Process exec(Project project, String[] cmd, String[] env,
- File workingDir) throws IOException {
- if (project == null) {
- if (workingDir == null) {
- return exec(project, cmd, env);
- }
- throw new IOException("Cannot locate antRun script: "
- + "No project provided");
- }
-
- // Locate the auxiliary script
- String antHome = project.getProperty("ant.home");
- if (antHome == null) {
- throw new IOException("Cannot locate antRun script: "
- + "Property 'ant.home' not found");
- }
- String antRun = project.resolveFile(antHome + File.separator + myScript).toString();
-
- // Build the command
- File commandDir = workingDir;
- if (workingDir == null && project != null) {
- commandDir = project.getBaseDir();
- }
-
- String[] newcmd = new String[cmd.length + 2];
- newcmd[0] = antRun;
- newcmd[1] = commandDir.getAbsolutePath();
- System.arraycopy(cmd, 0, newcmd, 2, cmd.length);
-
- return exec(project, newcmd, env);
- }
-
- private String myScript;
- }
-
- /**
- * A command launcher that uses an auxiliary perl script to launch commands
- * in directories other than the current working directory.
- */
- private static class PerlScriptCommandLauncher
- extends CommandLauncherProxy {
- PerlScriptCommandLauncher(String script, CommandLauncher launcher) {
- super(launcher);
- myScript = script;
- }
-
- /**
- * Launches the given command in a new process, in the given working
- * directory
- */
- public Process exec(Project project, String[] cmd, String[] env,
- File workingDir) throws IOException {
- if (project == null) {
- if (workingDir == null) {
- return exec(project, cmd, env);
- }
- throw new IOException("Cannot locate antRun script: "
- + "No project provided");
- }
-
- // Locate the auxiliary script
- String antHome = project.getProperty("ant.home");
- if (antHome == null) {
- throw new IOException("Cannot locate antRun script: "
- + "Property 'ant.home' not found");
- }
- String antRun = project.resolveFile(antHome + File.separator + myScript).toString();
-
- // Build the command
- File commandDir = workingDir;
- if (workingDir == null && project != null) {
- commandDir = project.getBaseDir();
- }
-
- String[] newcmd = new String[cmd.length + 3];
- newcmd[0] = "perl";
- newcmd[1] = antRun;
- newcmd[2] = commandDir.getAbsolutePath();
- System.arraycopy(cmd, 0, newcmd, 3, cmd.length);
-
- return exec(project, newcmd, env);
- }
-
- private String myScript;
- }
-
- /**
- * 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, env).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, env).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, String[] env)
- throws IOException {
- File script = File.createTempFile("ANT", ".COM");
- script.deleteOnExit();
- PrintWriter out = null;
- try {
- out = new PrintWriter(new FileWriter(script));
-
- // 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]);
- }
- } finally {
- if (out != null) {
- out.close();
- }
- }
- return script;
- }
-
- }
- }