ant-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bugzi...@apache.org
Subject DO NOT REPLY [Bug 5907] New: - ExecTask waits regardless of what you are executing
Date Thu, 17 Jan 2002 18:52:07 GMT
DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5907>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://nagoya.apache.org/bugzilla/show_bug.cgi?id=5907

ExecTask waits regardless of what you are executing

           Summary: ExecTask waits regardless of what you are executing
           Product: Ant
           Version: 1.4.1
          Platform: All
        OS/Version: All
            Status: NEW
          Severity: Enhancement
          Priority: Other
         Component: Core tasks
        AssignedTo: ant-dev@jakarta.apache.org
        ReportedBy: kevin.ross@bredex.com


Code modified and works below on windows.  Non-OS specific changes.

Modified:
---------
1. 
org.apache.tools.ant.taskdefs.ExecTask - added setWaitfor()

2. 
org.apache.tools.ant.taskdefs.Execute - added setWaitfor(), enhanced waitFor()

3. 
org.apache.tools.ant.taskdefs.PumpStreamHandler - bug - stop() now stops 
instead of waiting indefinitely

look for tag @modification in code.  Submitted on behalf of Charles Hudak 
<CHudak@arrowheadgrp.com> by Kevin Ross <Kevin.Ross@Bredex.com>

==========================
Execute.java
==========================
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;
    }
}


=================================================
ExecTask.java
=================================================

package org.apache.tools.ant.taskdefs;

import org.apache.tools.ant.*;
import org.apache.tools.ant.types.*;

import java.io.*;

/**
 * Executes a given command if the os platform is appropriate.
 *
 * @author duncan@x180.com
 * @author rubys@us.ibm.com
 * @author thomas.haas@softwired-inc.com
 * @author <a href="mailto:stefan.bodewig@epost.de">Stefan Bodewig</a>
 * @author <a href="mailto:mariusz@rakiura.org">Mariusz Nowostawski</a> 
 * @modification Charles Hudak <CHudak@arrowheadgrp.com> setWaitFor()
 */
public class ExecTask extends Task {

    private static String lSep = System.getProperty("line.separator");

    private String os;
    private File out;
    private File dir;
    protected boolean failOnError = false;
    protected boolean newEnvironment = false;
    private Integer timeout = null;
    private Environment env = new Environment();
    protected Commandline cmdl = new Commandline();
    private FileOutputStream fos = null;
    private ByteArrayOutputStream baos = null;
    private String outputprop;
    private boolean waitFor = true;    

    /** Controls whether the VM (1.3 and above) is used to execute the command 
*/
    private boolean vmLauncher = true;
    
    /**
     * Controls whether or not to wait for the process to finish.
     *
     * @Author Charles Hudak <CHudak@arrowheadgrp.com>
     */
    public void setWaitfor(boolean wait)
    {
        this.waitFor = wait;
    }    
    
    /**
     * Timeout in milliseconds after which the process will be killed.
     */
    public void setTimeout(Integer value) {
        timeout = value;
    }

    /**
     * The command to execute.
     */
    public void setExecutable(String value) {
        cmdl.setExecutable(value);
    }

    /**
     * The working directory of the process
     */
    public void setDir(File d) {
        this.dir = d;
    }

    /**
     * Only execute the process if <code>os.name</code> is included in this 
string.
     */
    public void setOs(String os) {
        this.os = os;
    }

    /**
     * The full commandline to execute, executable + arguments.
     */
    public void setCommand(Commandline cmdl) {
        log("The command attribute is deprecated. " +
            "Please use the executable attribute and nested arg elements.",
            Project.MSG_WARN);
        this.cmdl = cmdl;
    }

    /**
     * File the output of the process is redirected to.
     */
    public void setOutput(File out) {
        this.out = out;
    }

    /**
     * Property name whose value should be set to the output of
     * the process
     */
    public void setOutputproperty(String outputprop) {
	this.outputprop = outputprop;
    }

    /**
     * Throw a BuildException if process returns non 0.
     */
    public void setFailonerror(boolean fail) {
        failOnError = fail;
    }

    /**
     * Use a completely new environment
     */
    public void setNewenvironment(boolean newenv) {
        newEnvironment = newenv;
    }

    /**
     * Add a nested env element - an environment variable.
     */
    public void addEnv(Environment.Variable var) {
        env.addVariable(var);
    }

    /**
     * Add a nested arg element - a command line argument.
     */
    public Commandline.Argument createArg() {
        return cmdl.createArgument();
    }

    /**
     * Do the work.
     */
    public void execute() throws BuildException {
        checkConfiguration();
        if (isValidOs()) {
            runExec(prepareExec());
        }
    }

    /**
     * Has the user set all necessary attributes?
     */
    protected void checkConfiguration() throws BuildException {
        if (cmdl.getExecutable() == null) {
            throw new BuildException("no executable specified", location);
        }
        if (dir != null && !dir.exists()) {
        	throw new BuildException("The directory you specified does not 
exist");
        }
        if (dir != null && !dir.isDirectory()) {
        	throw new BuildException("The directory you specified is not a 
directory");
        }
    }

    /**
     * Is this the OS the user wanted?
     */
    protected boolean isValidOs() {
        // test if os match
        String myos = System.getProperty("os.name");
        log("Current OS is " + myos, Project.MSG_VERBOSE);
        if ((os != null) && (os.indexOf(myos) < 0)){
            // this command will be executed only on the specified OS
            log("This OS, " + myos + " was not found in the specified list of 
valid OSes: " + os, Project.MSG_VERBOSE);
            return false;
        }
        return true;
    }

    /**
     * Control whether the VM is used to launch the new process or
     * whether the OS's shell is used.
     */
    public void setVMLauncher(boolean vmLauncher) {
        this.vmLauncher = vmLauncher;
    }
    
    /**
     * Create an Execute instance with the correct working directory set.
     * @modification Charles Hudak <CHudak@arrowheadgrp.com> setWaitFor()
     */
    protected Execute prepareExec() throws BuildException {
        // default directory to the project's base directory
        if (dir == null) dir = project.getBaseDir();
        // show the command
        log(cmdl.toString(), Project.MSG_VERBOSE);
        
        Execute exe = new Execute(createHandler(), createWatchdog());
        exe.setAntRun(project);
        exe.setWorkingDirectory(dir);
        exe.setVMLauncher(vmLauncher);
        exe.setWaitfor(this.waitFor);
        if(this.waitFor){
         
            log("Waiting for process to complete...", Project.MSG_INFO);
        }
        else{
            
            log("Spawning process without waiting to complete.", 
Project.MSG_INFO); 
        }
        
        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);
        return exe;
    }

    /**
     * A Utility method for this classes and subclasses to run an Execute 
instance (an external command).
     */
    protected final void runExecute(Execute exe) throws IOException {
        int err = -1; // assume the worst

        err = exe.execute();
        if (err != 0) {
            if (failOnError) {
                throw new BuildException(taskType + " returned: "+err, 
location);
            } else {
                log("Result: " + err, Project.MSG_ERR);
            }
        }
        if (baos != null) {
            BufferedReader in = 
                new BufferedReader(new StringReader(baos.toString()));
            String line = null;
            StringBuffer val = new StringBuffer();
            while ((line = in.readLine()) != null) {
                if (val.length() != 0) {
                    val.append(lSep);
                }
                val.append(line);
            }
            project.setProperty(outputprop, val.toString());
        }
    }
    
    /**
     * Run the command using the given Execute instance. This may be overidden 
by subclasses
     */
    protected void runExec(Execute exe) throws BuildException {
        exe.setCommandline(cmdl.getCommandline());
        try {
            runExecute(exe);
        } catch (IOException e) {
            throw new BuildException("Execute failed: " + e, e, location);
        } finally {
            // close the output file if required
            logFlush();
        }
    }

    /**
     * Create the StreamHandler to use with our Execute instance.
     */
    protected ExecuteStreamHandler createHandler() throws BuildException {
        if(out!=null)  {
            try {
                fos = new FileOutputStream(out);
                log("Output redirected to " + out, Project.MSG_VERBOSE);
                return new PumpStreamHandler(fos);
            } catch (FileNotFoundException fne) {
                throw new BuildException("Cannot write to "+out, fne, location);
            } catch (IOException ioe) {
                throw new BuildException("Cannot write to "+out, ioe, location);
            }
        } else if (outputprop != null) {
	    //	    try {
	    baos = new ByteArrayOutputStream();
	    log("Output redirected to ByteArray", Project.MSG_VERBOSE);
	    return new PumpStreamHandler(baos);
        } else {
            return new LogStreamHandler(this,
                                        Project.MSG_INFO, Project.MSG_WARN);
        }
    }

    /**
     * Create the Watchdog to kill a runaway process.
     */
    protected ExecuteWatchdog createWatchdog() throws BuildException {
        if (timeout == null) return null;
        return new ExecuteWatchdog(timeout.intValue());
    }

    /**
     * Flush the output stream - if there is one.
     */
    protected void logFlush() {
        try {
            if (fos != null) fos.close();
            if (baos != null) baos.close();
        } catch (IOException io) {}
    }

}


=================================================
PumpStreamHandler.java
=================================================

package org.apache.tools.ant.taskdefs;

import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Copies standard output and error of subprocesses to standard output and
 * error of the parent process.
 *
 * TODO: standard input of the subprocess is not implemented.
 *
 * @author thomas.haas@softwired-inc.com
 * @modification Charles Hudak <CHudak@arrowheadgrp.com> stop()
 */
public class PumpStreamHandler implements ExecuteStreamHandler {

    private Thread inputThread;
    private Thread errorThread;

    private OutputStream out, err;

    public PumpStreamHandler(OutputStream out, OutputStream err) {
        this.out = out;
        this.err = err;
    }

    public PumpStreamHandler(OutputStream outAndErr) {
        this(outAndErr, outAndErr);
    }

    public PumpStreamHandler() {
        this(System.out, System.err);
    }

    public void setProcessOutputStream(InputStream is) {
        createProcessOutputPump(is, out);
    }


    public void setProcessErrorStream(InputStream is) {
        createProcessErrorPump(is, err);
    }


    public void setProcessInputStream(OutputStream os) {
    }


    public void start() {
        inputThread.start();
        errorThread.start();
    }


    /**
     * When stop() is called, stop listening and move on.  Thread.join() will 
wait,
     *  therefore, put a short timeout on it.
     *
     *  @modification Charles Hudak <CHudak@arrowheadgrp.com>
     */
    public void stop() {
        try {
            inputThread.join(500);
        } catch(InterruptedException e) {}
        try {
            errorThread.join(500);
        } catch(InterruptedException e) {}
        try {
            err.flush();
        } catch (IOException e) {}
        try {
            out.flush();
        } catch (IOException e) {}
    }
    
    protected OutputStream getErr() {
        return err;
    }

    protected OutputStream getOut() {
        return out;
    }

    protected void createProcessOutputPump(InputStream is, OutputStream os) {
        inputThread = createPump(is, os);
    }

    protected void createProcessErrorPump(InputStream is, OutputStream os) {
        errorThread = createPump(is, os);
    }


    /**
     * Creates a stream pumper to copy the given input stream to the given 
output stream.
     */
    protected Thread createPump(InputStream is, OutputStream os) {
        final Thread result = new Thread(new StreamPumper(is, os));
        result.setDaemon(true);
        return result;
    }

}

--
To unsubscribe, e-mail:   <mailto:ant-dev-unsubscribe@jakarta.apache.org>
For additional commands, e-mail: <mailto:ant-dev-help@jakarta.apache.org>


Mime
View raw message