aboutsummaryrefslogtreecommitdiffstats
path: root/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Execute.java
diff options
context:
space:
mode:
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Execute.java')
-rw-r--r--framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Execute.java734
1 files changed, 734 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Execute.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Execute.java
new file mode 100644
index 00000000..9523f453
--- /dev/null
+++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/Execute.java
@@ -0,0 +1,734 @@
+/*
+ * 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.BufferedReader;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Vector;
+
+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.taskdefs.launcher.CommandLauncher;
+import org.apache.tools.ant.types.Commandline;
+import org.apache.tools.ant.util.FileUtils;
+import org.apache.tools.ant.util.StringUtils;
+
+/**
+ * Runs an external program.
+ *
+ * @since Ant 1.2
+ */
+public class Execute {
+
+ private static final int ONE_SECOND = 1000;
+
+ /**
+ * Invalid exit code. set to {@link Integer#MAX_VALUE}
+ */
+ public static final int INVALID = Integer.MAX_VALUE;
+
+ private String[] cmdl = null;
+ private String[] env = null;
+ private int exitValue = INVALID;
+ private ExecuteStreamHandler streamHandler;
+ private final ExecuteWatchdog watchdog;
+ private File workingDirectory = null;
+ private Project project = null;
+ private boolean newEnvironment = false;
+
+ /** 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 Map<String, String> procEnvironment = null;
+
+ /** Used to destroy processes when the VM exits. */
+ private static ProcessDestroyer processDestroyer = new ProcessDestroyer();
+
+ /** Used for replacing env variables */
+ private static boolean environmentCaseInSensitive = false;
+
+ static {
+ if (Os.isFamily("windows")) {
+ environmentCaseInSensitive = true;
+ }
+ }
+
+ /**
+ * Set whether or not you want the process to be spawned.
+ * Default is not spawned.
+ *
+ * @param spawn if true you do not want Ant
+ * to wait for the end of the process.
+ * Has no influence in here, the calling task contains
+ * and acts accordingly
+ *
+ * @since Ant 1.6
+ * @deprecated
+ */
+ @Deprecated
+ public void setSpawn(boolean spawn) {
+ // Method did not do anything to begin with
+ }
+
+ /**
+ * Find the list of environment variables for this process.
+ *
+ * @return a map containing the environment variables.
+ * @since Ant 1.8.2
+ */
+ public static synchronized Map<String,String> getEnvironmentVariables() {
+ if (procEnvironment != null) {
+ return procEnvironment;
+ }
+ if (!Os.isFamily("openvms")) {
+ try {
+ procEnvironment = System.getenv();
+ return procEnvironment;
+ } catch (Exception x) {
+ x.printStackTrace();
+ }
+ }
+
+ procEnvironment = new LinkedHashMap<String, String>();
+ 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(toString(out)));
+
+ if (Os.isFamily("openvms")) {
+ procEnvironment = getVMSLogicals(in);
+ return procEnvironment;
+ }
+ String var = null;
+ String line, lineSep = StringUtils.LINE_SEP;
+ 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) {
+ int eq = var.indexOf("=");
+ procEnvironment.put(var.substring(0, eq),
+ var.substring(eq + 1));
+ }
+ var = line;
+ }
+ }
+ // Since we "look ahead" before adding, there's one last env var.
+ if (var != null) {
+ int eq = var.indexOf("=");
+ procEnvironment.put(var.substring(0, eq), var.substring(eq + 1));
+ }
+ } catch (java.io.IOException exc) {
+ exc.printStackTrace();
+ // Just try to see how much we got
+ }
+ return procEnvironment;
+ }
+
+ /**
+ * Find the list of environment variables for this process.
+ *
+ * @return a vector containing the environment variables.
+ * The vector elements are strings formatted like variable = value.
+ * @deprecated use #getEnvironmentVariables instead
+ */
+ @Deprecated
+ public static synchronized Vector<String> getProcEnvironment() {
+ Vector<String> v = new Vector<String>();
+ for (Entry<String, String> entry : getEnvironmentVariables().entrySet()) {
+ v.add(entry.getKey() + "=" + entry.getValue());
+ }
+ return v;
+ }
+
+ /**
+ * This is the operation to get our environment.
+ * It is a notorious troublespot pre-Java1.5, and should be approached
+ * with extreme caution.
+ *
+ * @return command and arguments to get our environment
+ */
+ private static String[] getProcEnvCommand() {
+ if (Os.isFamily("os/2")) {
+ // OS/2 - use same mechanism as Windows 2000
+ return new String[] {"cmd", "/c", "set"};
+ } else if (Os.isFamily("windows")) {
+ // Determine if we're running under XP/2000/NT or 98/95
+ if (Os.isFamily("win9x")) {
+ // Windows 98/95
+ return new String[] {"command.com", "/c", "set"};
+ } else {
+ // Windows XP/2000/NT/2003
+ return new String[] {"cmd", "/c", "set"};
+ }
+ } else if (Os.isFamily("z/os") || Os.isFamily("unix")) {
+ // On most systems one could use: /bin/sh -c env
+
+ // Some systems have /bin/env, others /usr/bin/env, just try
+ String[] cmd = new String[1];
+ if (new File("/bin/env").canRead()) {
+ cmd[0] = "/bin/env";
+ } else if (new File("/usr/bin/env").canRead()) {
+ cmd[0] = "/usr/bin/env";
+ } else {
+ // rely on PATH
+ cmd[0] = "env";
+ }
+ return cmd;
+ } else if (Os.isFamily("netware") || Os.isFamily("os/400")) {
+ // rely on PATH
+ return new String[] {"env"};
+ } else if (Os.isFamily("openvms")) {
+ return new String[] {"show", "logical"};
+ } else {
+ // MAC OS 9 and previous
+ // TODO: I have no idea how to get it, someone must fix it
+ return null;
+ }
+ }
+
+ /**
+ * ByteArrayOutputStream#toString doesn't seem to work reliably on
+ * OS/390, at least not the way we use it in the execution
+ * context.
+ *
+ * @param bos the output stream that one wants to read.
+ * @return the output stream as a string, read with
+ * special encodings in the case of z/os and os/400.
+ * @since Ant 1.5
+ */
+ public static String toString(ByteArrayOutputStream bos) {
+ if (Os.isFamily("z/os")) {
+ try {
+ return bos.toString("Cp1047");
+ } catch (java.io.UnsupportedEncodingException e) {
+ // noop default encoding used
+ }
+ } else if (Os.isFamily("os/400")) {
+ try {
+ return bos.toString("Cp500");
+ } catch (java.io.UnsupportedEncodingException e) {
+ // noop default encoding used
+ }
+ }
+ return bos.toString();
+ }
+
+ /**
+ * 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 disable a timeout for the subprocess.
+ */
+ public Execute(ExecuteStreamHandler streamHandler,
+ ExecuteWatchdog watchdog) {
+ setStreamHandler(streamHandler);
+ this.watchdog = watchdog;
+ // By default, use the shell launcher for VMS
+ //
+ if (Os.isFamily("openvms")) {
+ useVMLauncher = false;
+ }
+ }
+
+ /**
+ * Set the stream handler to use.
+ *
+ * @param streamHandler ExecuteStreamHandler.
+ * @since Ant 1.6
+ */
+ public void setStreamHandler(ExecuteStreamHandler streamHandler) {
+ this.streamHandler = streamHandler;
+ }
+
+ /**
+ * 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() {
+ return (env == null || newEnvironment)
+ ? env : patchEnvironment();
+ }
+
+ /**
+ * Sets the environment variables for the subprocess to launch.
+ *
+ * @param env 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) {
+ workingDirectory =
+ (wd == null || wd.getAbsolutePath().equals(antWorkingDirectory))
+ ? null : wd;
+ }
+
+ /**
+ * Return the working directory.
+ *
+ * @return the directory as a File.
+ * @since Ant 1.7
+ */
+ public File getWorkingDirectory() {
+ return workingDirectory == null ? new File(antWorkingDirectory)
+ : workingDirectory;
+ }
+
+ /**
+ * Set the name of the antRun script using the project's value.
+ *
+ * @param project the current project.
+ * @throws BuildException not clear when it is going to throw an exception, but
+ * it is the method's signature.
+ */
+ 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 useVMLauncher true if exec should launch through the VM,
+ * false if the shell should be used to launch the
+ * command.
+ */
+ public void setVMLauncher(boolean useVMLauncher) {
+ this.useVMLauncher = useVMLauncher;
+ }
+
+ /**
+ * Creates a process that runs a command.
+ *
+ * @param project the Project, only used for logging purposes, may be null.
+ * @param command the command to run.
+ * @param env the environment for the command.
+ * @param dir the working directory for the command.
+ * @param useVM use the built-in exec command for JDK 1.3 if available.
+ * @return the process started.
+ * @throws IOException forwarded from the particular launcher used.
+ * @since Ant 1.5
+ */
+ public static Process launch(Project project, String[] command,
+ String[] env, File dir, boolean useVM)
+ throws IOException {
+ if (dir != null && !dir.exists()) {
+ throw new BuildException(dir + " doesn't exist.");
+ }
+
+ CommandLauncher vmLauncher = CommandLauncher.getVMLauncher(project);
+ CommandLauncher launcher = (useVM && vmLauncher != null)
+ ? vmLauncher : CommandLauncher.getShellLauncher(project);
+ return launcher.exec(project, command, env, dir);
+ }
+
+ /**
+ * 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.IOException The exception is thrown, if launching
+ * of the subprocess failed.
+ */
+ public int execute() throws IOException {
+ if (workingDirectory != null && !workingDirectory.exists()) {
+ throw new BuildException(workingDirectory + " doesn't exist.");
+ }
+ final Process process = launch(project, getCommandline(),
+ getEnvironment(), workingDirectory,
+ useVMLauncher);
+ try {
+ streamHandler.setProcessInputStream(process.getOutputStream());
+ streamHandler.setProcessOutputStream(process.getInputStream());
+ streamHandler.setProcessErrorStream(process.getErrorStream());
+ } catch (IOException e) {
+ process.destroy();
+ throw e;
+ }
+ streamHandler.start();
+
+ try {
+ // add the process to the list of those to destroy if the VM exits
+ //
+ processDestroyer.add(process);
+
+ if (watchdog != null) {
+ watchdog.start(process);
+ }
+ waitFor(process);
+
+ if (watchdog != null) {
+ watchdog.stop();
+ }
+ streamHandler.stop();
+ closeStreams(process);
+
+ if (watchdog != null) {
+ watchdog.checkException();
+ }
+ return getExitValue();
+ } catch (ThreadDeath t) {
+ // #31928: forcibly kill it before continuing.
+ process.destroy();
+ throw t;
+ } finally {
+ // remove the process to the list of those to destroy if
+ // the VM exits
+ //
+ processDestroyer.remove(process);
+ }
+ }
+
+ /**
+ * Starts a process defined by the command line.
+ * Ant will not wait for this process, nor log its output.
+ *
+ * @throws java.io.IOException The exception is thrown, if launching
+ * of the subprocess failed.
+ * @since Ant 1.6
+ */
+ public void spawn() throws IOException {
+ if (workingDirectory != null && !workingDirectory.exists()) {
+ throw new BuildException(workingDirectory + " doesn't exist.");
+ }
+ final Process process = launch(project, getCommandline(),
+ getEnvironment(), workingDirectory,
+ useVMLauncher);
+ if (Os.isFamily("windows")) {
+ try {
+ Thread.sleep(ONE_SECOND);
+ } catch (InterruptedException e) {
+ project.log("interruption in the sleep after having spawned a"
+ + " process", Project.MSG_VERBOSE);
+ }
+ }
+ OutputStream dummyOut = new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ // Method intended to swallow whatever comes at it
+ }
+ };
+
+ ExecuteStreamHandler handler = new PumpStreamHandler(dummyOut);
+ handler.setProcessErrorStream(process.getErrorStream());
+ handler.setProcessOutputStream(process.getInputStream());
+ handler.start();
+ process.getOutputStream().close();
+
+ project.log("spawned process " + process.toString(),
+ Project.MSG_VERBOSE);
+ }
+
+ /**
+ * Wait for a given process.
+ *
+ * @param process the process one wants to wait for.
+ */
+ protected void waitFor(Process process) {
+ try {
+ process.waitFor();
+ setExitValue(process.exitValue());
+ } catch (InterruptedException e) {
+ process.destroy();
+ }
+ }
+
+ /**
+ * Set the exit value.
+ *
+ * @param value exit value of the process.
+ */
+ protected void setExitValue(int value) {
+ exitValue = value;
+ }
+
+ /**
+ * Query the exit value of the process.
+ *
+ * @return the exit value or Execute.INVALID if no exit value has
+ * been received.
+ */
+ public int getExitValue() {
+ return exitValue;
+ }
+
+ /**
+ * Checks whether <code>exitValue</code> signals a failure on the current
+ * system (OS specific).
+ *
+ * <p><b>Note</b> that this method relies on the conventions of
+ * the OS, it will return false results if the application you are
+ * running doesn't follow these conventions. One notable
+ * exception is the Java VM provided by HP for OpenVMS - it will
+ * return 0 if successful (like on any other platform), but this
+ * signals a failure on OpenVMS. So if you execute a new Java VM
+ * on OpenVMS, you cannot trust this method.</p>
+ *
+ * @param exitValue the exit value (return code) to be checked.
+ * @return <code>true</code> if <code>exitValue</code> signals a failure.
+ */
+ public static boolean isFailure(int exitValue) {
+ // on openvms even exit value signals failure;
+ // for other platforms nonzero exit value signals failure
+ return Os.isFamily("openvms")
+ ? (exitValue % 2 == 0) : (exitValue != 0);
+ }
+
+ /**
+ * Did this execute return in a failure.
+ *
+ * @see #isFailure(int)
+ * @return true if and only if the exit code is interpreted as a failure
+ * @since Ant1.7
+ */
+ public boolean isFailure() {
+ return isFailure(getExitValue());
+ }
+
+ /**
+ * Test for an untimely death of the process.
+ *
+ * @return true if a watchdog had to kill the process.
+ * @since Ant 1.5
+ */
+ public boolean killedProcess() {
+ return watchdog != null && watchdog.killedProcess();
+ }
+
+ /**
+ * Patch the current environment with the new values from the user.
+ *
+ * @return the patched environment.
+ */
+ private String[] patchEnvironment() {
+ // On OpenVMS Runtime#exec() doesn't support the environment array,
+ // so we only return the new values which then will be set in
+ // the generated DCL script, inheriting the parent process environment
+ if (Os.isFamily("openvms")) {
+ return env;
+ }
+ Map<String, String> osEnv =
+ new LinkedHashMap<String, String>(getEnvironmentVariables());
+ for (int i = 0; i < env.length; i++) {
+ String keyValue = env[i];
+ String key = keyValue.substring(0, keyValue.indexOf('='));
+ // Find the key in the current environment copy
+ // and remove it.
+
+ // Try without changing case first
+ if (osEnv.remove(key) == null && environmentCaseInSensitive) {
+ // not found, maybe perform a case insensitive search
+
+ for (String osEnvItem : osEnv.keySet()) {
+ // Nb: using default locale as key is a env name
+ if (osEnvItem.toLowerCase().equals(key.toLowerCase())) {
+ // Use the original casiness of the key
+ key = osEnvItem;
+ break;
+ }
+ }
+ }
+
+ // Add the key to the enviromnent copy
+ osEnv.put(key, keyValue.substring(key.length() + 1));
+ }
+
+ ArrayList<String> l = new ArrayList<String>();
+ for (Entry<String, String> entry : osEnv.entrySet()) {
+ l.add(entry.getKey() + "=" + entry.getValue());
+ }
+ return l.toArray(new String[osEnv.size()]);
+ }
+
+ /**
+ * 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 exit successfully.
+ */
+ public static void runCommand(Task task, String[] cmdline)
+ throws BuildException {
+ try {
+ task.log(Commandline.describeCommand(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 (isFailure(retval)) {
+ 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());
+ }
+ }
+
+ /**
+ * Close the streams belonging to the given Process.
+ *
+ * @param process the <code>Process</code>.
+ */
+ public static void closeStreams(Process process) {
+ FileUtils.close(process.getInputStream());
+ FileUtils.close(process.getOutputStream());
+ FileUtils.close(process.getErrorStream());
+ }
+
+ /**
+ * This method is VMS specific and used by getEnvironmentVariables().
+ *
+ * Parses VMS logicals from <code>in</code> and returns them as a Map.
+ * <code>in</code> is expected to be the
+ * output of "SHOW LOGICAL". The method takes care of parsing the output
+ * correctly as well as making sure that a logical defined in multiple
+ * tables only gets added from the highest order table. Logicals with
+ * multiple equivalence names are mapped to a variable with multiple
+ * values separated by a comma (,).
+ */
+ private static Map<String, String> getVMSLogicals(BufferedReader in)
+ throws IOException {
+ HashMap<String, String> logicals = new HashMap<String, String>();
+ String logName = null, logValue = null, newLogName;
+ String line = null;
+ // CheckStyle:MagicNumber OFF
+ while ((line = in.readLine()) != null) {
+ // parse the VMS logicals into required format ("VAR=VAL[,VAL2]")
+ if (line.startsWith("\t=")) {
+ // further equivalence name of previous logical
+ if (logName != null) {
+ logValue += "," + line.substring(4, line.length() - 1);
+ }
+ } else if (line.startsWith(" \"")) {
+ // new logical?
+ if (logName != null) {
+ logicals.put(logName, logValue);
+ }
+ int eqIndex = line.indexOf('=');
+ newLogName = line.substring(3, eqIndex - 2);
+ if (logicals.containsKey(newLogName)) {
+ // already got this logical from a higher order table
+ logName = null;
+ } else {
+ logName = newLogName;
+ logValue = line.substring(eqIndex + 3, line.length() - 1);
+ }
+ }
+ }
+ // CheckStyle:MagicNumber ON
+ // Since we "look ahead" before adding, there's one last env var.
+ if (logName != null) {
+ logicals.put(logName, logValue);
+ }
+ return logicals;
+ }
+}