ASF Bugzilla – Attachment 1028 Details for
Bug 5907
ExecTask waits regardless of what you are executing
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
Execute.java
Execute.java (text/plain), 26.59 KB, created by
Kevin Ross
on 2002-01-17 10:53:41 UTC
(
hide
)
Description:
Execute.java
Filename:
MIME Type:
Creator:
Kevin Ross
Created:
2002-01-17 10:53:41 UTC
Size:
26.59 KB
patch
obsolete
>/* > * The Apache Software License, Version 1.1 > * > * Copyright (c) 2000 The Apache Software Foundation. All rights > * reserved. > * > * Redistribution and use in source and binary forms, with or without > * modification, are permitted provided that the following conditions > * are met: > * > * 1. Redistributions of source code must retain the above copyright > * notice, this list of conditions and the following disclaimer. > * > * 2. Redistributions in binary form must reproduce the above copyright > * notice, this list of conditions and the following disclaimer in > * the documentation and/or other materials provided with the > * distribution. > * > * 3. The end-user documentation included with the redistribution, if > * any, must include the following acknowlegement: > * "This product includes software developed by the > * Apache Software Foundation (http://www.apache.org/)." > * Alternately, this acknowlegement may appear in the software itself, > * if and wherever such third-party acknowlegements normally appear. > * > * 4. The names "The Jakarta Project", "Ant", and "Apache Software > * Foundation" must not be used to endorse or promote products derived > * from this software without prior written permission. For written > * permission, please contact apache@apache.org. > * > * 5. Products derived from this software may not be called "Apache" > * nor may "Apache" appear in their names without prior written > * permission of the Apache Group. > * > * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED > * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES > * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR > * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT > * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF > * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND > * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, > * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT > * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > * SUCH DAMAGE. > * ==================================================================== > * > * This software consists of voluntary contributions made by many > * individuals on behalf of the Apache Software Foundation. For more > * information on the Apache Software Foundation, please see > * <http://www.apache.org/>. > */ > >package org.apache.tools.ant.taskdefs; > >import org.apache.tools.ant.BuildException; >import org.apache.tools.ant.Project; >import org.apache.tools.ant.Task; >import org.apache.tools.ant.types.Commandline; > >import java.io.File; >import java.io.IOException; >import java.io.InputStream; >import java.io.OutputStream; >import java.io.BufferedReader; >import java.io.StringReader; >import java.io.ByteArrayOutputStream; >import java.lang.reflect.InvocationTargetException; >import java.lang.reflect.Method; >import java.util.Vector; > >/** > * Runs an external program. > * > * @author thomas.haas@softwired-inc.com > * @modification Charles Hudak <CHudak@arrowheadgrp.com> waitFor() > */ >public class Execute { > > /** Invalid exit code. **/ > public final static 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; > private boolean waitFor = true; > > > /** 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; > > /** > * Builds a command launcher for the OS and JVM we are running under > */ > static { > // Try using a JDK 1.3 launcher > try { > vmLauncher = new Java13CommandLauncher(); > } > catch ( NoSuchMethodException exc ) { > // Ignore and keep try > } > > String osname = System.getProperty("os.name").toLowerCase(); > if ( osname.indexOf("mac os") >= 0 ) { > // Mac > shellLauncher = new MacCommandLauncher(new CommandLauncher()); > } > else if ( osname.indexOf("os/2") >= 0 ) { > // OS/2 - use same mechanism as Windows 2000 > shellLauncher = new WinNTCommandLauncher(new CommandLauncher()); > } > else if ( osname.indexOf("windows") >= 0 ) { > // 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(); > } > > // Determine if we're running under 2000/NT or 98/95 > if ( osname.indexOf("nt") >= 0 || osname.indexOf("2000") >= 0 ) { > // Windows 2000/NT > shellLauncher = new WinNTCommandLauncher(baseLauncher); > } > else { > // Windows 98/95 - need to use an auxiliary script > shellLauncher = new ScriptCommandLauncher("bin/antRun.bat", baseLauncher); > } > } > else { > // Generic > shellLauncher = new ScriptCommandLauncher("bin/antRun", new CommandLauncher()); > } > } > > /** > * Find the list of environment variables for this process. > */ > 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(out.toString())); > 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. > procEnvironment.addElement(var); > } > catch (java.io.IOException exc) { > exc.printStackTrace(); > // Just try to see how much we got > } > return procEnvironment; > } > > private static String[] getProcEnvCommand() { > String osname = System.getProperty("os.name").toLowerCase(); > if ( osname.indexOf("mac os") >= 0 ) { > // Mac > // Determine if we are running under OS X > try { > String version = System.getProperty("os.version"); > int majorVersion = > Integer.parseInt(version.substring(0, version.indexOf('.'))); > > if (majorVersion >= 10) { > // OS X - just line UNIX > String[] cmd = {"/usr/bin/env"}; > return cmd; > } > } catch (NumberFormatException e) { > // fall through to OS 9 > } > // OS 9 and previous > // TODO: I have no idea how to get it, someone must fix it > String[] cmd = null; > return cmd; > } > else if ( osname.indexOf("os/2") >= 0 ) { > // OS/2 - use same mechanism as Windows 2000 > // Not sure > String[] cmd = {"cmd", "/c", "set" }; > return cmd; > } > else if ( osname.indexOf("indows") >= 0 ) { > // Determine if we're running under 2000/NT or 98/95 > if ( osname.indexOf("nt") >= 0 || osname.indexOf("2000") >= 0 ) { > // Windows 2000/NT > String[] cmd = {"cmd", "/c", "set" }; > return cmd; > } > else { > // Windows 98/95 - need to use an auxiliary script > String[] cmd = {"command.com", "/c", "set" }; > return cmd; > } > } > else { > // Generic UNIX > // Alternatively one could use: /bin/sh -c env > String[] cmd = {"/usr/bin/env"}; > return cmd; > } > } > > /** > * 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) { > this.streamHandler = streamHandler; > this.watchdog = watchdog; > } > > > /** > * 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 commandline 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. > */ > 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 vmLauncher true if exec should launch through thge VM, > * false if the shell should be used to launch the command. > */ > public void setVMLauncher(boolean useVMLauncher) { > this.useVMLauncher = useVMLauncher; > } > > /** > * 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.IOExcpetion The exception is thrown, if launching > * of the subprocess failed > */ > public int execute() throws IOException { > CommandLauncher launcher = vmLauncher != null ? vmLauncher : shellLauncher; > if (!useVMLauncher) { > launcher = shellLauncher; > } > > final Process process = launcher.exec(project, getCommandline(), getEnvironment(), workingDirectory); > try { > streamHandler.setProcessInputStream(process.getOutputStream()); > streamHandler.setProcessOutputStream(process.getInputStream()); > streamHandler.setProcessErrorStream(process.getErrorStream()); > } catch (IOException e) { > process.destroy(); > throw e; > } > streamHandler.start(); > > if (watchdog != null) > watchdog.start(process); > > waitFor(process); > > if (watchdog != null) > watchdog.stop(); > > streamHandler.stop(); > > if (watchdog != null) > watchdog.checkException(); > > return getExitValue(); > } > > /** > * @modification Charles Hudak <CHudak@arrowheadgrp.com> > */ > protected void waitFor(Process process) { > > if (waitFor) > { > try { > > if(project != null) project.log("Execute.waitFor()...", Project.MSG_DEBUG); > process.waitFor(); > if(project != null) project.log("Execute.waitFor()...done.", Project.MSG_DEBUG); > setExitValue(process.exitValue()); > } > catch (InterruptedException e) {} > } > else { > > setExitValue(0); > } > } > > public void setWaitfor(boolean wait) > { > this.waitFor = wait; > } > > protected void setExitValue(int value) { > exitValue = value; > } > > public int getExitValue() { > return exitValue; > } > > /** > * Patch the current environment with the new values from the user. > * @return the patched environment > */ > private String[] patchEnvironment() { > 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.toString(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 ( retval != 0 ) { > 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()); > } > } > > /** > * 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 proccess is used. > */ > public Process exec(Project project, String[] cmd, String[] env) throws IOException > { > if (project != null) { > project.log("Execute:CommandLauncher: " + > Commandline.toString(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 proccess is used. > * @param workingDir The directory to start the command in. If null, > * the current directory is used > */ > 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 > */ > 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.toString(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) > _execWithCWD = 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 > */ > public Process exec(Project project, String[] cmd, String[] env, File workingDir) > throws IOException > { > try { > if (project != null) { > project.log("Execute:Java13CommandLauncher: " + > Commandline.toString(cmd), Project.MSG_DEBUG); > } > Object[] arguments = { cmd, env, workingDir }; > return (Process)_execWithCWD.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 _execWithCWD; > } > > /** > * A command launcher that proxies another command launcher. > * > * Sub-classes override exec(args, env, workdir) > */ > private static class CommandLauncherProxy extends CommandLauncher > { > CommandLauncherProxy(CommandLauncher launcher) > { > _launcher = launcher; > } > > /** > * Launches the given command in a new process. Delegates this > * method to the proxied launcher > */ > public Process exec(Project project, String[] cmd, String[] env) throws IOException > { > return _launcher.exec(project, cmd, env); > } > > private CommandLauncher _launcher; > } > > /** > * A command launcher for Windows 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. > */ > 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 > */ > 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); > _script = 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 + _script).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 _script; > } >}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 5907
:
1027
| 1028 |
1029
|
6783