ant-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From David McTavish <dmctav...@sandvine.com>
Subject RE: Spawning processes
Date Tue, 29 Jul 2003 13:48:17 GMT
on behalf of Tom Gordon, once more for good measure...


-----Original Message-----
From: Tim Gordon [mailto:tim.gordon@allustra.com]
Sent: Friday, June 27, 2003 7:46 AM
To: Ant Users List
Subject: Spawning processes


Lots of people seem to ask how to spawn a process that will live beyond ANT.
There are other ways, but this works for me... Don't rely on any console
I/O, though - it's not piped in and whatever's piped out will cease to do so
once the ANT JVM exits. Generally intended for things that write logs, have
gui's, start their own shells, etc.

Ruthlessly hacked from ExecTask, so it's a bit untidy. Works, though.

eg:

  <taskdef name="spawn" classname="tools.ant.Spawn"/>

  <target name="startRmiRegistry">
    <spawn executable="rmiregistry">
      <arg value="${rmi.registry.port}"/>
    </spawn>
  </target>

Usual path considerations apply.

----------------------
import java.io.File;
import java.io.FileOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.StringReader;

import org.apache.tools.ant.Task;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.util.StringUtils;
import org.apache.tools.ant.taskdefs.Execute;
import org.apache.tools.ant.taskdefs.LogStreamHandler;
import org.apache.tools.ant.types.Environment;
import org.apache.tools.ant.types.Commandline;

/**
 * Spawns an asynchronous process from ANT
 *
 * @author Tim Gordon
 */
public class Spawn extends Task
{
  private String os;
  private File out;
  private File dir;
  protected boolean newEnvironment = false;
  private Environment env = new Environment();
  protected Commandline cmdl = new Commandline();
  private FileOutputStream fos = null;
  private ByteArrayOutputStream baos = null;
  private String outputprop;
  private boolean failIfExecFails = true;
  private boolean append = false;

  /**
   * Controls whether the VM (1.3 and above) is used to execute the
   * command
   */
  private boolean vmLauncher = true;

  /**
   * 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;
  }

  /**
   * List of operating systems on which the command may be executed.
   */
  public void setOs(String os)
  {
    this.os = os;
  }

  /**
   * @ant.attribute ignore="true"
   */
  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;
  }

  /**
   * Do not propagate old environment when new environment variables are
specified.
   */
  public void setNewenvironment(boolean newenv)
  {
    newEnvironment = newenv;
  }

  /**
   * Add an environment variable to the launched process.
   */
  public void addEnv(Environment.Variable var)
  {
    env.addVariable(var);
  }

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

  /**
   * Stop the build if program cannot be started. Defaults to true.
   *
   * @since Ant 1.5
   */
  public void setFailIfExecutionFails(boolean flag)
  {
    failIfExecFails = flag;
  }

  /**
   * Whether output should be appended to or overwrite an existing file.
   * Defaults to false.
   *
   * @since 1.30, Ant 1.5
   */
  public void setAppend(boolean append)
  {
    this.append = append;
  }

  /**
   * Do the work.
   */
  public void execute() throws BuildException
  {
    File savedDir = dir; // possibly altered in prepareExec
    checkConfiguration();
    if (isValidOs())
    {
      try
      {
        runExec(prepareExec());
      }
      finally
      {
        dir = savedDir;
      }
    }
  }

  /**
   * 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;
  }

  /**
   * If true, launch new process with VM, otherwise use the OS's shell.
   */
  public void setVMLauncher(boolean vmLauncher)
  {
    this.vmLauncher = vmLauncher;
  }

  /**
   * Create an Execute instance with the correct working directory set.
   */
  protected Execute prepareExec() throws BuildException
  {
    // default directory to the project's base directory
    if (dir == null)
    {
      dir = project.getBaseDir();
    }
    Execute exe = new Execute(
      new LogStreamHandler(this, Project.MSG_INFO, Project.MSG_WARN)
      {
        public void stop()
        {
          // Just let the daemon threads handle output for the lifetime of
this ANT invocation...
        }
      }
    )
    {
      protected void waitFor(Process process)
      {
        // Don't want to wait for a detached process...
      }
    };

    exe.setAntRun(getProject());
    exe.setWorkingDirectory(dir);
    exe.setVMLauncher(vmLauncher);
    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
  {
    exe.execute();

    if (baos != null)
    {
      BufferedReader in =
        new BufferedReader(new StringReader(Execute.toString(baos)));
      String line = null;
      StringBuffer val = new StringBuffer();
      while ((line = in.readLine()) != null)
      {
        if (val.length() != 0)
        {
          val.append(StringUtils.LINE_SEP);
        }
        val.append(line);
      }
      project.setNewProperty(outputprop, val.toString());
    }
  }

  /**
   * Run the command using the given Execute instance. This may be
   * overidden by subclasses
   */
  protected void runExec(Execute exe) throws BuildException
  {
    // show the command
    log(cmdl.describeCommand(), Project.MSG_VERBOSE);

    exe.setCommandline(cmdl.getCommandline());
    try
    {
      runExecute(exe);
    }
    catch (IOException e)
    {
      if (failIfExecFails)
      {
        throw new BuildException("Execute failed: " + e.toString(), e,
                                 location);
      }
      else
      {
        log("Execute failed: " + e.toString(), Project.MSG_ERR);
      }
    }
    finally
    {
      // close the output file if required
      logFlush();
    }
  }

  /**
   * 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)
    {
    }
  }
}
-----------------

Tim Gordon

Allustra Limited
1 Royal Exchange Avenue
London
EC3V 3LT
Tel 020 7464 4190
Tel 020 7464 4194
http://www.allustra.com/


---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@ant.apache.org
For additional commands, e-mail: user-help@ant.apache.org


Mime
View raw message