aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/ExecTask.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/ExecTask.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/ExecTask.java726
1 files changed, 726 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/ExecTask.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/ExecTask.java
new file mode 100644
index 00000000..dd93978f
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/ExecTask.java
@@ -0,0 +1,726 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.File;
+import java.io.IOException;
+import java.util.Locale;
+import java.util.Map;
+
+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;
+import org.apache.tools.ant.types.Environment;
+import org.apache.tools.ant.types.Path;
+import org.apache.tools.ant.types.RedirectorElement;
+import org.apache.tools.ant.util.FileUtils;
+
+/**
+ * Executes a given command if the os platform is appropriate.
+ *
+ * @since Ant 1.2
+ *
+ * @ant.task category="control"
+ */
+public class ExecTask extends Task {
+
+ private static final FileUtils FILE_UTILS = FileUtils.getFileUtils();
+
+ private String os;
+ private String osFamily;
+
+ private File dir;
+ // CheckStyle:VisibilityModifier OFF - bc
+ protected boolean failOnError = false;
+ protected boolean newEnvironment = false;
+ private Long timeout = null;
+ private Environment env = new Environment();
+ protected Commandline cmdl = new Commandline();
+ private String resultProperty;
+ private boolean failIfExecFails = true;
+ private String executable;
+ private boolean resolveExecutable = false;
+ private boolean searchPath = false;
+ private boolean spawn = false;
+ private boolean incompatibleWithSpawn = false;
+
+ //include locally for screening purposes
+ private String inputString;
+ private File input;
+ private File output;
+ private File error;
+
+ protected Redirector redirector = new Redirector(this);
+ protected RedirectorElement redirectorElement;
+ // CheckStyle:VisibilityModifier ON
+
+ /**
+ * Controls whether the VM (1.3 and above) is used to execute the
+ * command
+ */
+ private boolean vmLauncher = true;
+
+
+ /**
+ * Create an instance.
+ * Needs to be configured by binding to a project.
+ */
+ public ExecTask() {
+ }
+
+ /**
+ * create an instance that is helping another task.
+ * Project, OwningTarget, TaskName and description are all
+ * pulled out
+ * @param owner task that we belong to
+ */
+ public ExecTask(Task owner) {
+ bindToOwner(owner);
+ }
+
+ /**
+ * Set whether or not you want the process to be spawned.
+ * Default is false.
+ * @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;
+ }
+
+ /**
+ * Set the timeout in milliseconds after which the process will be killed.
+ *
+ * @param value timeout in milliseconds.
+ *
+ * @since Ant 1.5
+ */
+ public void setTimeout(Long value) {
+ timeout = value;
+ incompatibleWithSpawn |= timeout != null;
+ }
+
+ /**
+ * Set the timeout in milliseconds after which the process will be killed.
+ *
+ * @param value timeout in milliseconds.
+ */
+ public void setTimeout(Integer value) {
+ setTimeout(
+ (Long) ((value == null) ? null : new Long(value.intValue())));
+ }
+
+ /**
+ * Set the name of the executable program.
+ * @param value the name of the executable program.
+ */
+ public void setExecutable(String value) {
+ this.executable = value;
+ cmdl.setExecutable(value);
+ }
+
+ /**
+ * Set the working directory of the process.
+ * @param d 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.
+ * @param os list of operating systems on which the command may be executed.
+ */
+ public void setOs(String os) {
+ this.os = os;
+ }
+
+ /**
+ * List of operating systems on which the command may be executed.
+ * @since Ant 1.8.0
+ */
+ public final String getOs() {
+ return os;
+ }
+
+ /**
+ * Sets a command line.
+ * @param cmdl command line.
+ * @ant.attribute ignore="true"
+ */
+ public void setCommand(Commandline cmdl) {
+ log("The command attribute is deprecated.\n"
+ + "Please use the executable attribute and nested arg elements.",
+ Project.MSG_WARN);
+ this.cmdl = cmdl;
+ }
+
+ /**
+ * File the output of the process is redirected to. If error is not
+ * redirected, it too will appear in the output.
+ *
+ * @param out name of a file to which output should be sent.
+ */
+ public void setOutput(File out) {
+ this.output = out;
+ incompatibleWithSpawn = true;
+ }
+
+ /**
+ * Set the input file to use for the task.
+ *
+ * @param input name of a file from which to get input.
+ */
+ public void setInput(File input) {
+ if (inputString != null) {
+ throw new BuildException("The \"input\" and \"inputstring\" "
+ + "attributes cannot both be specified");
+ }
+ this.input = input;
+ incompatibleWithSpawn = true;
+ }
+
+ /**
+ * Set the string to use as input.
+ *
+ * @param inputString the string which is used as the input source.
+ */
+ public void setInputString(String inputString) {
+ if (input != null) {
+ throw new BuildException("The \"input\" and \"inputstring\" "
+ + "attributes cannot both be specified");
+ }
+ this.inputString = inputString;
+ incompatibleWithSpawn = true;
+ }
+
+ /**
+ * Controls whether error output of exec is logged. This is only useful when
+ * output is being redirected and error output is desired in the Ant log.
+ *
+ * @param logError set to true to log error output in the normal ant log.
+ */
+ public void setLogError(boolean logError) {
+ redirector.setLogError(logError);
+ incompatibleWithSpawn |= logError;
+ }
+
+ /**
+ * Set the File to which the error stream of the process should be redirected.
+ *
+ * @param error a file to which stderr should be sent.
+ *
+ * @since Ant 1.6
+ */
+ public void setError(File error) {
+ this.error = error;
+ incompatibleWithSpawn = true;
+ }
+
+ /**
+ * Sets the property name whose value should be set to the output of
+ * the process.
+ *
+ * @param outputProp name of property.
+ */
+ public void setOutputproperty(String outputProp) {
+ redirector.setOutputProperty(outputProp);
+ incompatibleWithSpawn = true;
+ }
+
+ /**
+ * Sets the name of the property whose value should be set to the error of
+ * the process.
+ *
+ * @param errorProperty name of property.
+ *
+ * @since Ant 1.6
+ */
+ public void setErrorProperty(String errorProperty) {
+ redirector.setErrorProperty(errorProperty);
+ incompatibleWithSpawn = true;
+ }
+
+ /**
+ * Fail if the command exits with a non-zero return code.
+ *
+ * @param fail if true fail the command on non-zero return code.
+ */
+ public void setFailonerror(boolean fail) {
+ failOnError = fail;
+ incompatibleWithSpawn |= fail;
+ }
+
+ /**
+ * Do not propagate old environment when new environment variables are specified.
+ *
+ * @param newenv if true, do not propagate old environment
+ * when new environment variables are specified.
+ */
+ public void setNewenvironment(boolean newenv) {
+ newEnvironment = newenv;
+ }
+
+ /**
+ * Set whether to attempt to resolve the executable to a file.
+ *
+ * @param resolveExecutable if true, attempt to resolve the
+ * path of the executable.
+ */
+ public void setResolveExecutable(boolean resolveExecutable) {
+ this.resolveExecutable = resolveExecutable;
+ }
+
+ /**
+ * Set whether to search nested, then
+ * system PATH environment variables for the executable.
+ *
+ * @param searchPath if true, search PATHs.
+ */
+ public void setSearchPath(boolean searchPath) {
+ this.searchPath = searchPath;
+ }
+
+ /**
+ * Indicates whether to attempt to resolve the executable to a
+ * file.
+ * @return the resolveExecutable flag
+ *
+ * @since Ant 1.6
+ */
+ public boolean getResolveExecutable() {
+ return resolveExecutable;
+ }
+
+ /**
+ * Add an environment variable to the launched process.
+ *
+ * @param var new environment variable.
+ */
+ public void addEnv(Environment.Variable var) {
+ env.addVariable(var);
+ }
+
+ /**
+ * Adds a command-line argument.
+ *
+ * @return new command line argument created.
+ */
+ public Commandline.Argument createArg() {
+ return cmdl.createArgument();
+ }
+
+ /**
+ * Sets the name of a property in which the return code of the
+ * command should be stored. Only of interest if failonerror=false.
+ *
+ * @since Ant 1.5
+ *
+ * @param resultProperty name of property.
+ */
+ public void setResultProperty(String resultProperty) {
+ this.resultProperty = resultProperty;
+ incompatibleWithSpawn = true;
+ }
+
+ /**
+ * Helper method to set result property to the
+ * passed in value if appropriate.
+ *
+ * @param result value desired for the result property value.
+ */
+ protected void maybeSetResultPropertyValue(int result) {
+ if (resultProperty != null) {
+ String res = Integer.toString(result);
+ getProject().setNewProperty(resultProperty, res);
+ }
+ }
+
+ /**
+ * Set whether to stop the build if program cannot be started.
+ * Defaults to true.
+ *
+ * @param flag stop the build if program cannot be started.
+ *
+ * @since Ant 1.5
+ */
+ public void setFailIfExecutionFails(boolean flag) {
+ failIfExecFails = flag;
+ incompatibleWithSpawn |= flag;
+ }
+
+ /**
+ * Set whether output should be appended to or overwrite an existing file.
+ * Defaults to false.
+ *
+ * @param append if true append is desired.
+ *
+ * @since 1.30, Ant 1.5
+ */
+ public void setAppend(boolean append) {
+ redirector.setAppend(append);
+ incompatibleWithSpawn |= append;
+ }
+
+ /**
+ * Add a <code>RedirectorElement</code> to this task.
+ *
+ * @param redirectorElement <code>RedirectorElement</code>.
+ * @since Ant 1.6.2
+ */
+ public void addConfiguredRedirector(RedirectorElement redirectorElement) {
+ if (this.redirectorElement != null) {
+ throw new BuildException("cannot have > 1 nested <redirector>s");
+ }
+ this.redirectorElement = redirectorElement;
+ incompatibleWithSpawn = true;
+ }
+
+
+ /**
+ * Restrict this execution to a single OS Family
+ * @param osFamily the family to restrict to.
+ */
+ public void setOsFamily(String osFamily) {
+ this.osFamily = osFamily.toLowerCase(Locale.ENGLISH);
+ }
+
+ /**
+ * Restrict this execution to a single OS Family
+ * @since Ant 1.8.0
+ */
+ public final String getOsFamily() {
+ return osFamily;
+ }
+
+ /**
+ * The method attempts to figure out where the executable is so that we can feed
+ * the full path. We first try basedir, then the exec dir, and then
+ * fallback to the straight executable name (i.e. on the path).
+ *
+ * @param exec the name of the executable.
+ * @param mustSearchPath if true, the executable will be looked up in
+ * the PATH environment and the absolute path is returned.
+ *
+ * @return the executable as a full path if it can be determined.
+ *
+ * @since Ant 1.6
+ */
+ protected String resolveExecutable(String exec, boolean mustSearchPath) {
+ if (!resolveExecutable) {
+ return exec;
+ }
+ // try to find the executable
+ File executableFile = getProject().resolveFile(exec);
+ if (executableFile.exists()) {
+ return executableFile.getAbsolutePath();
+ }
+ // now try to resolve against the dir if given
+ if (dir != null) {
+ executableFile = FILE_UTILS.resolveFile(dir, exec);
+ if (executableFile.exists()) {
+ return executableFile.getAbsolutePath();
+ }
+ }
+ // couldn't find it - must be on path
+ if (mustSearchPath) {
+ Path p = null;
+ String[] environment = env.getVariables();
+ if (environment != null) {
+ for (int i = 0; i < environment.length; i++) {
+ if (isPath(environment[i])) {
+ p = new Path(getProject(), getPath(environment[i]));
+ break;
+ }
+ }
+ }
+ if (p == null) {
+ String path = getPath(Execute.getEnvironmentVariables());
+ if (path != null) {
+ p = new Path(getProject(), path);
+ }
+ }
+ if (p != null) {
+ String[] dirs = p.list();
+ for (int i = 0; i < dirs.length; i++) {
+ executableFile
+ = FILE_UTILS.resolveFile(new File(dirs[i]), exec);
+ if (executableFile.exists()) {
+ return executableFile.getAbsolutePath();
+ }
+ }
+ }
+ }
+ // mustSearchPath is false, or no PATH or not found - keep our
+ // fingers crossed.
+ return exec;
+ }
+
+ /**
+ * Do the work.
+ *
+ * @throws BuildException in a number of circumstances:
+ * <ul>
+ * <li>if failIfExecFails is set to true and the process cannot be started</li>
+ * <li>the java13command launcher can send build exceptions</li>
+ * <li>this list is not exhaustive or limitative</li>
+ * </ul>
+ */
+ public void execute() throws BuildException {
+ // Quick fail if this is not a valid OS for the command
+ if (!isValidOs()) {
+ return;
+ }
+ File savedDir = dir; // possibly altered in prepareExec
+ cmdl.setExecutable(resolveExecutable(executable, searchPath));
+ checkConfiguration();
+ try {
+ runExec(prepareExec());
+ } finally {
+ dir = savedDir;
+ }
+ }
+
+ /**
+ * Has the user set all necessary attributes?
+ * @throws BuildException if there are missing required parameters.
+ */
+ protected void checkConfiguration() throws BuildException {
+ if (cmdl.getExecutable() == null) {
+ throw new BuildException("no executable specified", getLocation());
+ }
+ if (dir != null && !dir.exists()) {
+ throw new BuildException("The directory " + dir + " does not exist");
+ }
+ if (dir != null && !dir.isDirectory()) {
+ throw new BuildException(dir + " is not a directory");
+ }
+ if (spawn && incompatibleWithSpawn) {
+ getProject().log("spawn does not allow attributes related to input, "
+ + "output, error, result", Project.MSG_ERR);
+ getProject().log("spawn also does not allow timeout", Project.MSG_ERR);
+ getProject().log("finally, spawn is not compatible "
+ + "with a nested I/O <redirector>", Project.MSG_ERR);
+ throw new BuildException("You have used an attribute "
+ + "or nested element which is not compatible with spawn");
+ }
+ setupRedirector();
+ }
+
+ /**
+ * Set up properties on the redirector that we needed to store locally.
+ */
+ protected void setupRedirector() {
+ redirector.setInput(input);
+ redirector.setInputString(inputString);
+ redirector.setOutput(output);
+ redirector.setError(error);
+ }
+
+ /**
+ * Is this the OS the user wanted?
+ * @return boolean.
+ * <ul>
+ * <li>
+ * <li><code>true</code> if the os and osfamily attributes are null.</li>
+ * <li><code>true</code> if osfamily is set, and the os family and must match
+ * that of the current OS, according to the logic of
+ * {@link Os#isOs(String, String, String, String)}, and the result of the
+ * <code>os</code> attribute must also evaluate true.
+ * </li>
+ * <li>
+ * <code>true</code> if os is set, and the system.property os.name
+ * is found in the os attribute,</li>
+ * <li><code>false</code> otherwise.</li>
+ * </ul>
+ */
+ protected boolean isValidOs() {
+ //hand osfamily off to Os class, if set
+ if (osFamily != null && !Os.isFamily(osFamily)) {
+ return false;
+ }
+ //the Exec OS check is different from Os.isOs(), which
+ //probes for a specific OS. Instead it searches the os field
+ //for the current os.name
+ 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;
+ }
+
+ /**
+ * Set whether to launch new process with VM, otherwise use the OS's shell.
+ * Default value is true.
+ * @param vmLauncher true if we want to launch new process with VM,
+ * false if we want to use the OS's shell.
+ */
+ public void setVMLauncher(boolean vmLauncher) {
+ this.vmLauncher = vmLauncher;
+ }
+
+ /**
+ * Create an Execute instance with the correct working directory set.
+ *
+ * @return an instance of the Execute class.
+ *
+ * @throws BuildException under unknown circumstances.
+ */
+ protected Execute prepareExec() throws BuildException {
+ // default directory to the project's base directory
+ if (dir == null) {
+ dir = getProject().getBaseDir();
+ }
+ if (redirectorElement != null) {
+ redirectorElement.configure(redirector);
+ }
+ Execute exe = new Execute(createHandler(), createWatchdog());
+ 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).
+ *
+ * @param exe instance of the execute class.
+ *
+ * @throws IOException in case of problem to attach to the stdin/stdout/stderr
+ * streams of the process.
+ */
+ protected final void runExecute(Execute exe) throws IOException {
+ int returnCode = -1; // assume the worst
+
+ if (!spawn) {
+ returnCode = exe.execute();
+
+ //test for and handle a forced process death
+ if (exe.killedProcess()) {
+ String msg = "Timeout: killed the sub-process";
+ if (failOnError) {
+ throw new BuildException(msg);
+ } else {
+ log(msg, Project.MSG_WARN);
+ }
+ }
+ maybeSetResultPropertyValue(returnCode);
+ redirector.complete();
+ if (Execute.isFailure(returnCode)) {
+ if (failOnError) {
+ throw new BuildException(getTaskType() + " returned: "
+ + returnCode, getLocation());
+ } else {
+ log("Result: " + returnCode, Project.MSG_ERR);
+ }
+ }
+ } else {
+ exe.spawn();
+ }
+ }
+
+ /**
+ * Run the command using the given Execute instance. This may be
+ * overridden by subclasses.
+ *
+ * @param exe instance of Execute to run.
+ *
+ * @throws BuildException if the new process could not be started
+ * only if failIfExecFails is set to true (the default).
+ */
+ 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,
+ getLocation());
+ } else {
+ log("Execute failed: " + e.toString(), Project.MSG_ERR);
+ }
+ } finally {
+ // close the output file if required
+ logFlush();
+ }
+ }
+
+ /**
+ * Create the StreamHandler to use with our Execute instance.
+ *
+ * @return instance of ExecuteStreamHandler.
+ *
+ * @throws BuildException under unknown circumstances.
+ */
+ protected ExecuteStreamHandler createHandler() throws BuildException {
+ return redirector.createHandler();
+ }
+
+ /**
+ * Create the Watchdog to kill a runaway process.
+ *
+ * @return instance of ExecuteWatchdog.
+ *
+ * @throws BuildException under unknown circumstances.
+ */
+ protected ExecuteWatchdog createWatchdog() throws BuildException {
+ return (timeout == null)
+ ? null : new ExecuteWatchdog(timeout.longValue());
+ }
+
+ /**
+ * Flush the output stream - if there is one.
+ */
+ protected void logFlush() {
+ }
+
+ private boolean isPath(String line) {
+ return line.startsWith("PATH=")
+ || line.startsWith("Path=");
+ }
+
+ private String getPath(String line) {
+ return line.substring("PATH=".length());
+ }
+
+ private String getPath(Map<String, String> map) {
+ String p = map.get("PATH");
+ return p != null ? p : map.get("Path");
+ }
+}