Submitted by: Mariusz Nowostawski <mariusz@marni.otago.ac.nz> git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@267834 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -66,116 +66,140 @@ import java.io.*; | |||||
| * @author rubys@us.ibm.com | * @author rubys@us.ibm.com | ||||
| * @author thomas.haas@softwired-inc.com | * @author thomas.haas@softwired-inc.com | ||||
| * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | ||||
| * @author <a href="mailto:mariusz@rakiura.org">Mariusz Nowostawski</a> | |||||
| */ | */ | ||||
| public class ExecTask extends Task { | public class ExecTask extends Task { | ||||
| private String os; | private String os; | ||||
| private File out; | private File out; | ||||
| private File dir; | private File dir; | ||||
| private boolean failOnError = false; | |||||
| protected boolean failOnError = false; | |||||
| private Integer timeout = null; | private Integer timeout = null; | ||||
| private Environment env = new Environment(); | private Environment env = new Environment(); | ||||
| private Commandline cmdl = new Commandline(); | |||||
| protected Commandline cmdl = new Commandline(); | |||||
| private FileOutputStream fos = null; | private FileOutputStream fos = null; | ||||
| /** | |||||
| * Timeout in milliseconds after which the process will be killed. | |||||
| */ | |||||
| public void setTimeout(Integer value) { | public void setTimeout(Integer value) { | ||||
| timeout = value; | timeout = value; | ||||
| } | } | ||||
| /** | |||||
| * The command to execute. | |||||
| */ | |||||
| public void setExecutable(String value) { | public void setExecutable(String value) { | ||||
| cmdl.setExecutable(value); | cmdl.setExecutable(value); | ||||
| } | } | ||||
| /** | |||||
| * The working directory of the process | |||||
| */ | |||||
| public void setDir(File d) { | public void setDir(File d) { | ||||
| this.dir = d; | this.dir = d; | ||||
| } | } | ||||
| /** | |||||
| * Only execute the process if <code>os.name</code> includes this string. | |||||
| */ | |||||
| public void setOs(String os) { | public void setOs(String os) { | ||||
| this.os = os; | this.os = os; | ||||
| } | } | ||||
| /** | |||||
| * The full commandline to execute, executable + arguments. | |||||
| */ | |||||
| public void setCommand(Commandline cmdl) { | public void setCommand(Commandline cmdl) { | ||||
| this.cmdl = cmdl; | this.cmdl = cmdl; | ||||
| } | } | ||||
| /** | |||||
| * File the output of the process is redirected to. | |||||
| */ | |||||
| public void setOutput(File out) { | public void setOutput(File out) { | ||||
| this.out = out; | this.out = out; | ||||
| } | } | ||||
| /** | |||||
| * Throw a BuildException if process returns non 0. | |||||
| */ | |||||
| public void setFailonerror(boolean fail) { | public void setFailonerror(boolean fail) { | ||||
| failOnError = fail; | failOnError = fail; | ||||
| } | } | ||||
| /** | |||||
| * Add a nested env element - an environment variable. | |||||
| */ | |||||
| public void addEnv(Environment.Variable var) { | public void addEnv(Environment.Variable var) { | ||||
| env.addVariable(var); | env.addVariable(var); | ||||
| } | } | ||||
| /** | |||||
| * Add a nested arg element - a command line argument. | |||||
| */ | |||||
| public Commandline.Argument createArg() { | public Commandline.Argument createArg() { | ||||
| return cmdl.createArgument(); | return cmdl.createArgument(); | ||||
| } | } | ||||
| /** | |||||
| * Do the work. | |||||
| */ | |||||
| public void execute() throws BuildException { | 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) { | if (cmdl.getExecutable() == null) { | ||||
| throw new BuildException("no executable specified", location); | throw new BuildException("no executable specified", location); | ||||
| } | } | ||||
| } | |||||
| String[] orig = cmdl.getCommandline(); | |||||
| int err = -1; // assume the worst | |||||
| /** | |||||
| * Is this the OS the user wanted? | |||||
| */ | |||||
| private boolean isValidOs() { | |||||
| // test if os match | // test if os match | ||||
| String myos = System.getProperty("os.name"); | String myos = System.getProperty("os.name"); | ||||
| log("Myos = " + myos, Project.MSG_VERBOSE); | log("Myos = " + myos, Project.MSG_VERBOSE); | ||||
| if ((os != null) && (os.indexOf(myos) < 0)){ | if ((os != null) && (os.indexOf(myos) < 0)){ | ||||
| // this command will be executed only on the specified OS | // this command will be executed only on the specified OS | ||||
| log("Not found in " + os, Project.MSG_VERBOSE); | log("Not found in " + os, Project.MSG_VERBOSE); | ||||
| return; | |||||
| return false; | |||||
| } | } | ||||
| return true; | |||||
| } | |||||
| /** | |||||
| * Create an Execute instance with the correct working directory set. | |||||
| */ | |||||
| protected Execute prepareExec() throws BuildException { | |||||
| // default directory to the project's base directory | // default directory to the project's base directory | ||||
| if (dir == null) dir = project.getBaseDir(); | 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.setEnvironment(env.getVariables()); | |||||
| return exe; | |||||
| } | |||||
| if (myos.toLowerCase().indexOf("windows") >= 0) { | |||||
| if (!dir.equals(project.resolveFile("."))) { | |||||
| if (myos.toLowerCase().indexOf("nt") >= 0) { | |||||
| cmdl = new Commandline(); | |||||
| cmdl.setExecutable("cmd"); | |||||
| cmdl.addValue("/c"); | |||||
| cmdl.addValue("cd"); | |||||
| cmdl.addValue(dir.getAbsolutePath()); | |||||
| cmdl.addValue("&&"); | |||||
| cmdl.addLine(orig); | |||||
| } else { | |||||
| String ant = project.getProperty("ant.home"); | |||||
| if (ant == null) { | |||||
| throw new BuildException("Property 'ant.home' not found", location); | |||||
| } | |||||
| String antRun = project.resolveFile(ant + "/bin/antRun.bat").toString(); | |||||
| cmdl = new Commandline(); | |||||
| cmdl.setExecutable(antRun); | |||||
| cmdl.addValue(dir.getAbsolutePath()); | |||||
| cmdl.addLine(orig); | |||||
| } | |||||
| } | |||||
| } else { | |||||
| String ant = project.getProperty("ant.home"); | |||||
| if (ant == null) throw new BuildException("Property 'ant.home' not found", location); | |||||
| String antRun = project.resolveFile(ant + "/bin/antRun").toString(); | |||||
| cmdl = new Commandline(); | |||||
| cmdl.setExecutable(antRun); | |||||
| cmdl.addValue(dir.getAbsolutePath()); | |||||
| cmdl.addLine(orig); | |||||
| } | |||||
| /** | |||||
| * Run the command using the given Execute instance. | |||||
| */ | |||||
| protected void runExec(Execute exe) throws BuildException { | |||||
| int err = -1; // assume the worst | |||||
| try { | try { | ||||
| // show the command | |||||
| log(cmdl.toString(), Project.MSG_VERBOSE); | |||||
| final Execute exe = new Execute(createHandler(), createWatchdog()); | |||||
| exe.setCommandline(cmdl.getCommandline()); | exe.setCommandline(cmdl.getCommandline()); | ||||
| exe.setEnvironment(env.getVariables()); | |||||
| err = exe.execute(); | err = exe.execute(); | ||||
| if (err != 0) { | if (err != 0) { | ||||
| if (failOnError) { | if (failOnError) { | ||||
| @@ -192,7 +216,9 @@ public class ExecTask extends Task { | |||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Create the StreamHandler to use with our Execute instance. | |||||
| */ | |||||
| protected ExecuteStreamHandler createHandler() throws BuildException { | protected ExecuteStreamHandler createHandler() throws BuildException { | ||||
| if(out!=null) { | if(out!=null) { | ||||
| try { | try { | ||||
| @@ -210,11 +236,17 @@ public class ExecTask extends Task { | |||||
| } | } | ||||
| } | } | ||||
| /** | |||||
| * Create the Watchdog to kill a runaway process. | |||||
| */ | |||||
| protected ExecuteWatchdog createWatchdog() throws BuildException { | protected ExecuteWatchdog createWatchdog() throws BuildException { | ||||
| if (timeout == null) return null; | if (timeout == null) return null; | ||||
| return new ExecuteWatchdog(timeout.intValue()); | return new ExecuteWatchdog(timeout.intValue()); | ||||
| } | } | ||||
| /** | |||||
| * Flush the output stream - if there is one. | |||||
| */ | |||||
| protected void logFlush() { | protected void logFlush() { | ||||
| try { | try { | ||||
| if (fos != null) fos.close(); | if (fos != null) fos.close(); | ||||
| @@ -54,6 +54,10 @@ | |||||
| package org.apache.tools.ant.taskdefs; | package org.apache.tools.ant.taskdefs; | ||||
| import org.apache.tools.ant.BuildException; | |||||
| import org.apache.tools.ant.Project; | |||||
| import java.io.File; | |||||
| import java.io.IOException; | import java.io.IOException; | ||||
| import java.io.InputStream; | import java.io.InputStream; | ||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||
| @@ -74,6 +78,12 @@ public class Execute { | |||||
| private int exitValue = INVALID; | private int exitValue = INVALID; | ||||
| private ExecuteStreamHandler streamHandler; | private ExecuteStreamHandler streamHandler; | ||||
| private ExecuteWatchdog watchdog; | private ExecuteWatchdog watchdog; | ||||
| private File workingDirectory; | |||||
| private String antRun; | |||||
| private static String antWorkingDirectory = | |||||
| (new File((new File(".")).getAbsolutePath())).getParent(); | |||||
| private static String myos = System.getProperty("os.name"); | |||||
| /** | /** | ||||
| * Creates a new execute object using <code>PumpStreamHandler</code> for | * Creates a new execute object using <code>PumpStreamHandler</code> for | ||||
| @@ -104,7 +114,31 @@ public class Execute { | |||||
| * @return the commandline used to create a subprocess | * @return the commandline used to create a subprocess | ||||
| */ | */ | ||||
| public String[] getCommandline() { | public String[] getCommandline() { | ||||
| return cmdl; | |||||
| String[] commandLine = cmdl; | |||||
| if (workingDirectory != null && | |||||
| !antWorkingDirectory.equals(workingDirectory.getAbsolutePath())) { | |||||
| if (myos.toLowerCase().indexOf("windows") >= 0 && | |||||
| myos.toLowerCase().indexOf("nt") >= 0) { | |||||
| commandLine = new String[cmdl.length+5]; | |||||
| commandLine[0] = "cmd"; | |||||
| commandLine[1] = "/c"; | |||||
| commandLine[2] = "cd"; | |||||
| commandLine[3] = workingDirectory.getAbsolutePath(); | |||||
| commandLine[4] = "&&"; | |||||
| System.arraycopy(cmdl, 0, commandLine, 5, cmdl.length); | |||||
| } else { | |||||
| commandLine = new String[cmdl.length+2]; | |||||
| commandLine[0] = antRun; | |||||
| commandLine[1] = workingDirectory.getAbsolutePath(); | |||||
| System.arraycopy(cmdl, 0, commandLine, 2, cmdl.length); | |||||
| } | |||||
| } | |||||
| return commandLine; | |||||
| } | } | ||||
| @@ -128,14 +162,44 @@ public class Execute { | |||||
| /** | /** | ||||
| * Sets the commandline of the subprocess to launch. | |||||
| * Sets the environment variables for the subprocess to launch. | |||||
| * | * | ||||
| * @param commandline the commandline of 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) { | public void setEnvironment(String[] env) { | ||||
| this.env = 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. | |||||
| * | |||||
| * @param wd the working directory of the process. | |||||
| */ | |||||
| public void setWorkingDirectory(File wd) { | |||||
| 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 { | |||||
| String ant = project.getProperty("ant.home"); | |||||
| if (ant == null) { | |||||
| throw new BuildException("Property 'ant.home' not found"); | |||||
| } | |||||
| if (myos.toLowerCase().indexOf("windows") >= 0) { | |||||
| antRun = project.resolveFile(ant + "/bin/antRun.bat").toString(); | |||||
| } else { | |||||
| antRun = project.resolveFile(ant + "/bin/antRun").toString(); | |||||
| } | |||||
| } | |||||
| /** | /** | ||||
| * Runs a process defined by the command line and returns its exit status. | * Runs a process defined by the command line and returns its exit status. | ||||
| @@ -65,14 +65,12 @@ import java.io.IOException; | |||||
| * Executes a given command, supplying a set of files as arguments. | * Executes a given command, supplying a set of files as arguments. | ||||
| * | * | ||||
| * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | * @author <a href="mailto:stefan.bodewig@megabit.net">Stefan Bodewig</a> | ||||
| * @author <a href="mailto:mariusz@rakiura.org">Mariusz Nowostawski</a> | |||||
| */ | */ | ||||
| public class ExecuteOn extends Task { | |||||
| public class ExecuteOn extends ExecTask { | |||||
| private Vector filesets = new Vector(); | private Vector filesets = new Vector(); | ||||
| private Commandline command = new Commandline(); | |||||
| private Environment env = new Environment(); | |||||
| private Integer timeout = null; | |||||
| private boolean failOnError = false; | |||||
| private boolean parallel = false; | |||||
| /** | /** | ||||
| * Adds a set of files (nested fileset attribute). | * Adds a set of files (nested fileset attribute). | ||||
| @@ -82,97 +80,79 @@ public class ExecuteOn extends Task { | |||||
| } | } | ||||
| /** | /** | ||||
| * The executable. | |||||
| * Shall the command work on all specified files in parallel? | |||||
| */ | */ | ||||
| public void setExecutable(String exe) { | |||||
| command.setExecutable(exe); | |||||
| public void setParallel(boolean parallel) { | |||||
| this.parallel = parallel; | |||||
| } | } | ||||
| /** | |||||
| * Adds an argument to the command (nested arg element) | |||||
| */ | |||||
| public Commandline.Argument createArg() { | |||||
| return command.createArgument(); | |||||
| } | |||||
| /** | |||||
| * Adds an environment variable (nested env element) | |||||
| */ | |||||
| public void addEnv(Environment.Variable var) { | |||||
| env.addVariable(var); | |||||
| protected void checkConfiguration() { | |||||
| super.checkConfiguration(); | |||||
| if (filesets.size() == 0) { | |||||
| throw new BuildException("no filesets specified", location); | |||||
| } | |||||
| } | } | ||||
| /** | |||||
| * Milliseconds we allow the process to run before we kill it. | |||||
| */ | |||||
| public void setTimeout(Integer value) { | |||||
| timeout = value; | |||||
| } | |||||
| protected void runExec(Execute exe) throws BuildException { | |||||
| try { | |||||
| /** | |||||
| * throw a build exception if process returns non 0? | |||||
| */ | |||||
| public void setFailonerror(boolean fail) { | |||||
| failOnError = fail; | |||||
| } | |||||
| Vector v = new Vector(); | |||||
| for (int i=0; i<filesets.size(); i++) { | |||||
| FileSet fs = (FileSet) filesets.elementAt(i); | |||||
| DirectoryScanner ds = fs.getDirectoryScanner(project); | |||||
| String[] s = ds.getIncludedFiles(); | |||||
| for (int j=0; j<s.length; j++) { | |||||
| v.addElement(new File(fs.getDir(), s[j]).getAbsolutePath()); | |||||
| } | |||||
| } | |||||
| public void execute() throws BuildException { | |||||
| if (command.getExecutable() == null) { | |||||
| throw new BuildException("no executable specified", location); | |||||
| } | |||||
| String[] s = new String[v.size()]; | |||||
| v.copyInto(s); | |||||
| if (filesets.size() == 0) { | |||||
| throw new BuildException("no filesets specified", location); | |||||
| } | |||||
| int err = -1; | |||||
| String myos = System.getProperty("os.name"); | |||||
| String[] orig = command.getCommandline(); | |||||
| String[] cmd = new String[orig.length+1]; | |||||
| System.arraycopy(orig, 0, cmd, 0, orig.length); | |||||
| Vector v = new Vector(); | |||||
| for (int i=0; i<filesets.size(); i++) { | |||||
| FileSet fs = (FileSet) filesets.elementAt(i); | |||||
| DirectoryScanner ds = fs.getDirectoryScanner(project); | |||||
| String[] s = ds.getIncludedFiles(); | |||||
| for (int j=0; j<s.length; j++) { | |||||
| v.addElement(new File(fs.getDir(), s[j]).getAbsolutePath()); | |||||
| } | |||||
| } | |||||
| String label = command.toString()+" "; | |||||
| String[] environment = env.getVariables(); | |||||
| for (int i=0; i<v.size(); i++) { | |||||
| try { | |||||
| // show the command | |||||
| String file = (String) v.elementAt(i); | |||||
| log(label+file, Project.MSG_VERBOSE); | |||||
| Execute exe = new Execute(createHandler(), createWatchdog()); | |||||
| cmd[orig.length] = file; | |||||
| exe.setCommandline(cmd); | |||||
| exe.setEnvironment(environment); | |||||
| int err = exe.execute(); | |||||
| // antRun.bat currently limits us to directory + executable | |||||
| // + 7 args | |||||
| if (parallel && | |||||
| (myos.toLowerCase().indexOf("windows") < 0 || s.length+cmdl.size() <= 8) | |||||
| ) { | |||||
| cmdl.addLine(s); | |||||
| exe.setCommandline(cmdl.getCommandline()); | |||||
| err = exe.execute(); | |||||
| if (err != 0) { | if (err != 0) { | ||||
| if (failOnError) { | if (failOnError) { | ||||
| throw new BuildException("Exec returned: "+err, location); | |||||
| throw new BuildException("Exec returned: "+err, | |||||
| location); | |||||
| } else { | } else { | ||||
| log("Result: " + err, Project.MSG_ERR); | log("Result: " + err, Project.MSG_ERR); | ||||
| } | } | ||||
| } | } | ||||
| } catch (IOException e) { | |||||
| throw new BuildException("Execute failed: " + e, e, location); | |||||
| } | |||||
| } | |||||
| } | |||||
| protected ExecuteStreamHandler createHandler() throws BuildException { | |||||
| return new LogStreamHandler(this, | |||||
| Project.MSG_INFO, Project.MSG_WARN); | |||||
| } | |||||
| } else { | |||||
| String[] cmd = new String[cmdl.size()+1]; | |||||
| System.arraycopy(cmdl.getCommandline(), 0, cmd, 0, cmdl.size()); | |||||
| for (int i=0; i<s.length; i++) { | |||||
| cmd[cmdl.size()] = s[i]; | |||||
| exe.setCommandline(cmd); | |||||
| err = exe.execute(); | |||||
| if (err != 0) { | |||||
| if (failOnError) { | |||||
| throw new BuildException("Exec returned: "+err, | |||||
| location); | |||||
| } else { | |||||
| log("Result: " + err, Project.MSG_ERR); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| protected ExecuteWatchdog createWatchdog() throws BuildException { | |||||
| if (timeout == null) return null; | |||||
| return new ExecuteWatchdog(timeout.intValue()); | |||||
| } catch (IOException e) { | |||||
| throw new BuildException("Execute failed: " + e, e, location); | |||||
| } finally { | |||||
| // close the output file if required | |||||
| logFlush(); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -36,7 +36,7 @@ style=org.apache.tools.ant.taskdefs.XSLTProcess | |||||
| touch=org.apache.tools.ant.taskdefs.Touch | touch=org.apache.tools.ant.taskdefs.Touch | ||||
| signjar=org.apache.tools.ant.taskdefs.SignJar | signjar=org.apache.tools.ant.taskdefs.SignJar | ||||
| antstructure=org.apache.tools.ant.taskdefs.AntStructure | antstructure=org.apache.tools.ant.taskdefs.AntStructure | ||||
| executeon=org.apache.tools.ant.taskdefs.ExecuteOn | |||||
| execon=org.apache.tools.ant.taskdefs.ExecuteOn | |||||
| antcall=org.apache.tools.ant.taskdefs.CallTarget | antcall=org.apache.tools.ant.taskdefs.CallTarget | ||||
| sql=org.apache.tools.ant.taskdefs.SQLExec | sql=org.apache.tools.ant.taskdefs.SQLExec | ||||