1 | /*
|
---|
2 | * Copyright 2000-2005 The Apache Software Foundation
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
---|
5 | * you may not use this file except in compliance with the License.
|
---|
6 | * You may obtain a copy of the License at
|
---|
7 | *
|
---|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
9 | *
|
---|
10 | * Unless required by applicable law or agreed to in writing, software
|
---|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
13 | * See the License for the specific language governing permissions and
|
---|
14 | * limitations under the License.
|
---|
15 | *
|
---|
16 | */
|
---|
17 |
|
---|
18 | package org.apache.tools.ant.taskdefs;
|
---|
19 |
|
---|
20 | import java.io.OutputStream;
|
---|
21 | import java.io.BufferedReader;
|
---|
22 | import java.io.ByteArrayOutputStream;
|
---|
23 | import java.io.File;
|
---|
24 | import java.io.FileWriter;
|
---|
25 | import java.io.IOException;
|
---|
26 | import java.io.PrintWriter;
|
---|
27 | import java.io.StringReader;
|
---|
28 | import java.lang.reflect.InvocationTargetException;
|
---|
29 | import java.lang.reflect.Method;
|
---|
30 | import java.util.HashMap;
|
---|
31 | import java.util.Iterator;
|
---|
32 | import java.util.Vector;
|
---|
33 | import org.apache.tools.ant.BuildException;
|
---|
34 | import org.apache.tools.ant.Project;
|
---|
35 | import org.apache.tools.ant.Task;
|
---|
36 | import org.apache.tools.ant.taskdefs.condition.Os;
|
---|
37 | import org.apache.tools.ant.types.Commandline;
|
---|
38 |
|
---|
39 | /**
|
---|
40 | * Runs an external program.
|
---|
41 | *
|
---|
42 | * @since Ant 1.2
|
---|
43 | *
|
---|
44 | */
|
---|
45 | public class Execute {
|
---|
46 |
|
---|
47 | /** Invalid exit code. **/
|
---|
48 | public static final int INVALID = Integer.MAX_VALUE;
|
---|
49 |
|
---|
50 | private String[] cmdl = null;
|
---|
51 | private String[] env = null;
|
---|
52 | private int exitValue = INVALID;
|
---|
53 | private ExecuteStreamHandler streamHandler;
|
---|
54 | private ExecuteWatchdog watchdog;
|
---|
55 | private File workingDirectory = null;
|
---|
56 | private Project project = null;
|
---|
57 | private boolean newEnvironment = false;
|
---|
58 |
|
---|
59 | /** Controls whether the VM is used to launch commands, where possible */
|
---|
60 | private boolean useVMLauncher = true;
|
---|
61 |
|
---|
62 | private static String antWorkingDirectory = System.getProperty("user.dir");
|
---|
63 | private static CommandLauncher vmLauncher = null;
|
---|
64 | private static CommandLauncher shellLauncher = null;
|
---|
65 | private static Vector procEnvironment = null;
|
---|
66 | private boolean spawn = false;
|
---|
67 |
|
---|
68 | /** Used to destroy processes when the VM exits. */
|
---|
69 | private static ProcessDestroyer processDestroyer = new ProcessDestroyer();
|
---|
70 |
|
---|
71 | /**
|
---|
72 | * Builds a command launcher for the OS and JVM we are running under
|
---|
73 | */
|
---|
74 | static {
|
---|
75 | // Try using a JDK 1.3 launcher
|
---|
76 | try {
|
---|
77 | if (Os.isFamily("openvms")) {
|
---|
78 | vmLauncher = new VmsCommandLauncher();
|
---|
79 | } else if (!Os.isFamily("os/2")) {
|
---|
80 | vmLauncher = new Java13CommandLauncher();
|
---|
81 | }
|
---|
82 | } catch (NoSuchMethodException exc) {
|
---|
83 | // Ignore and keep trying
|
---|
84 | }
|
---|
85 |
|
---|
86 | if (Os.isFamily("mac") && !Os.isFamily("unix")) {
|
---|
87 | // Mac
|
---|
88 | shellLauncher = new MacCommandLauncher(new CommandLauncher());
|
---|
89 | } else if (Os.isFamily("os/2")) {
|
---|
90 | // OS/2
|
---|
91 | shellLauncher = new OS2CommandLauncher(new CommandLauncher());
|
---|
92 | } else if (Os.isFamily("windows")) {
|
---|
93 | // Windows. Need to determine which JDK we're running in
|
---|
94 |
|
---|
95 | CommandLauncher baseLauncher;
|
---|
96 | if (System.getProperty("java.version").startsWith("1.1")) {
|
---|
97 | // JDK 1.1
|
---|
98 | baseLauncher = new Java11CommandLauncher();
|
---|
99 | } else {
|
---|
100 | // JDK 1.2
|
---|
101 | baseLauncher = new CommandLauncher();
|
---|
102 | }
|
---|
103 |
|
---|
104 | if (!Os.isFamily("win9x")) {
|
---|
105 | // Windows XP/2000/NT
|
---|
106 | shellLauncher = new WinNTCommandLauncher(baseLauncher);
|
---|
107 | } else {
|
---|
108 | // Windows 98/95 - need to use an auxiliary script
|
---|
109 | shellLauncher
|
---|
110 | = new ScriptCommandLauncher("bin/antRun.bat", baseLauncher);
|
---|
111 | }
|
---|
112 | } else if (Os.isFamily("netware")) {
|
---|
113 | // NetWare. Need to determine which JDK we're running in
|
---|
114 | CommandLauncher baseLauncher;
|
---|
115 | if (System.getProperty("java.version").startsWith("1.1")) {
|
---|
116 | // JDK 1.1
|
---|
117 | baseLauncher = new Java11CommandLauncher();
|
---|
118 | } else {
|
---|
119 | // JDK 1.2
|
---|
120 | baseLauncher = new CommandLauncher();
|
---|
121 | }
|
---|
122 |
|
---|
123 | shellLauncher
|
---|
124 | = new PerlScriptCommandLauncher("bin/antRun.pl", baseLauncher);
|
---|
125 | } else if (Os.isFamily("openvms")) {
|
---|
126 | // the vmLauncher already uses the shell
|
---|
127 | shellLauncher = vmLauncher;
|
---|
128 | } else {
|
---|
129 | // Generic
|
---|
130 | shellLauncher = new ScriptCommandLauncher("bin/antRun",
|
---|
131 | new CommandLauncher());
|
---|
132 | }
|
---|
133 | }
|
---|
134 |
|
---|
135 | /**
|
---|
136 | * set whether or not you want the process to be spawned
|
---|
137 | * default is not spawned
|
---|
138 | *
|
---|
139 | * @param spawn if true you do not want ant to wait for the end of the process
|
---|
140 | *
|
---|
141 | * @since ant 1.6
|
---|
142 | */
|
---|
143 | public void setSpawn(boolean spawn) {
|
---|
144 | this.spawn = spawn;
|
---|
145 | }
|
---|
146 |
|
---|
147 | /**
|
---|
148 | * Find the list of environment variables for this process.
|
---|
149 | *
|
---|
150 | * @return a vector containing the environment variables
|
---|
151 | * the vector elements are strings formatted like variable = value
|
---|
152 | */
|
---|
153 | public static synchronized Vector getProcEnvironment() {
|
---|
154 | if (procEnvironment != null) {
|
---|
155 | return procEnvironment;
|
---|
156 | }
|
---|
157 |
|
---|
158 | procEnvironment = new Vector();
|
---|
159 | try {
|
---|
160 | ByteArrayOutputStream out = new ByteArrayOutputStream();
|
---|
161 | Execute exe = new Execute(new PumpStreamHandler(out));
|
---|
162 | exe.setCommandline(getProcEnvCommand());
|
---|
163 | // Make sure we do not recurse forever
|
---|
164 | exe.setNewenvironment(true);
|
---|
165 | int retval = exe.execute();
|
---|
166 | if (retval != 0) {
|
---|
167 | // Just try to use what we got
|
---|
168 | }
|
---|
169 |
|
---|
170 | BufferedReader in =
|
---|
171 | new BufferedReader(new StringReader(toString(out)));
|
---|
172 |
|
---|
173 | if (Os.isFamily("openvms")) {
|
---|
174 | procEnvironment = addVMSLogicals(procEnvironment, in);
|
---|
175 | return procEnvironment;
|
---|
176 | }
|
---|
177 |
|
---|
178 | String var = null;
|
---|
179 | String line, lineSep = System.getProperty("line.separator");
|
---|
180 | while ((line = in.readLine()) != null) {
|
---|
181 | if (line.indexOf('=') == -1) {
|
---|
182 | // Chunk part of previous env var (UNIX env vars can
|
---|
183 | // contain embedded new lines).
|
---|
184 | if (var == null) {
|
---|
185 | var = lineSep + line;
|
---|
186 | } else {
|
---|
187 | var += lineSep + line;
|
---|
188 | }
|
---|
189 | } else {
|
---|
190 | // New env var...append the previous one if we have it.
|
---|
191 | if (var != null) {
|
---|
192 | procEnvironment.addElement(var);
|
---|
193 | }
|
---|
194 | var = line;
|
---|
195 | }
|
---|
196 | }
|
---|
197 | // Since we "look ahead" before adding, there's one last env var.
|
---|
198 | if (var != null) {
|
---|
199 | procEnvironment.addElement(var);
|
---|
200 | }
|
---|
201 | } catch (java.io.IOException exc) {
|
---|
202 | exc.printStackTrace();
|
---|
203 | // Just try to see how much we got
|
---|
204 | }
|
---|
205 | return procEnvironment;
|
---|
206 | }
|
---|
207 |
|
---|
208 | private static String[] getProcEnvCommand() {
|
---|
209 | if (Os.isFamily("os/2")) {
|
---|
210 | // OS/2 - use same mechanism as Windows 2000
|
---|
211 | return new String[] {"cmd", "/c", "set" };
|
---|
212 | } else if (Os.isFamily("windows")) {
|
---|
213 | // Determine if we're running under XP/2000/NT or 98/95
|
---|
214 | if (Os.isFamily("win9x")) {
|
---|
215 | // Windows 98/95
|
---|
216 | return new String[] {"command.com", "/c", "set" };
|
---|
217 | } else {
|
---|
218 | // Windows XP/2000/NT/2003
|
---|
219 | return new String[] {"cmd", "/c", "set" };
|
---|
220 | }
|
---|
221 | } else if (Os.isFamily("z/os") || Os.isFamily("unix")) {
|
---|
222 | // On most systems one could use: /bin/sh -c env
|
---|
223 |
|
---|
224 | // Some systems have /bin/env, others /usr/bin/env, just try
|
---|
225 | String[] cmd = new String[1];
|
---|
226 | if (new File("/bin/env").canRead()) {
|
---|
227 | cmd[0] = "/bin/env";
|
---|
228 | } else if (new File("/usr/bin/env").canRead()) {
|
---|
229 | cmd[0] = "/usr/bin/env";
|
---|
230 | } else {
|
---|
231 | // rely on PATH
|
---|
232 | cmd[0] = "env";
|
---|
233 | }
|
---|
234 | return cmd;
|
---|
235 | } else if (Os.isFamily("netware") || Os.isFamily("os/400")) {
|
---|
236 | // rely on PATH
|
---|
237 | return new String[] {"env"};
|
---|
238 | } else if (Os.isFamily("openvms")) {
|
---|
239 | return new String[] {"show", "logical"};
|
---|
240 | } else {
|
---|
241 | // MAC OS 9 and previous
|
---|
242 | //TODO: I have no idea how to get it, someone must fix it
|
---|
243 | return null;
|
---|
244 | }
|
---|
245 | }
|
---|
246 |
|
---|
247 | /**
|
---|
248 | * ByteArrayOutputStream#toString doesn't seem to work reliably on
|
---|
249 | * OS/390, at least not the way we use it in the execution
|
---|
250 | * context.
|
---|
251 | *
|
---|
252 | * @param bos the output stream that one wants to read
|
---|
253 | * @return the output stream as a string, read with
|
---|
254 | * special encodings in the case of z/os and os/400
|
---|
255 | *
|
---|
256 | * @since Ant 1.5
|
---|
257 | */
|
---|
258 | public static String toString(ByteArrayOutputStream bos) {
|
---|
259 | if (Os.isFamily("z/os")) {
|
---|
260 | try {
|
---|
261 | return bos.toString("Cp1047");
|
---|
262 | } catch (java.io.UnsupportedEncodingException e) {
|
---|
263 | //noop default encoding used
|
---|
264 | }
|
---|
265 | } else if (Os.isFamily("os/400")) {
|
---|
266 | try {
|
---|
267 | return bos.toString("Cp500");
|
---|
268 | } catch (java.io.UnsupportedEncodingException e) {
|
---|
269 | //noop default encoding used
|
---|
270 | }
|
---|
271 | }
|
---|
272 | return bos.toString();
|
---|
273 | }
|
---|
274 |
|
---|
275 | /**
|
---|
276 | * Creates a new execute object using <code>PumpStreamHandler</code> for
|
---|
277 | * stream handling.
|
---|
278 | */
|
---|
279 | public Execute() {
|
---|
280 | this(new PumpStreamHandler(), null);
|
---|
281 | }
|
---|
282 |
|
---|
283 |
|
---|
284 | /**
|
---|
285 | * Creates a new execute object.
|
---|
286 | *
|
---|
287 | * @param streamHandler the stream handler used to handle the input and
|
---|
288 | * output streams of the subprocess.
|
---|
289 | */
|
---|
290 | public Execute(ExecuteStreamHandler streamHandler) {
|
---|
291 | this(streamHandler, null);
|
---|
292 | }
|
---|
293 |
|
---|
294 | /**
|
---|
295 | * Creates a new execute object.
|
---|
296 | *
|
---|
297 | * @param streamHandler the stream handler used to handle the input and
|
---|
298 | * output streams of the subprocess.
|
---|
299 | * @param watchdog a watchdog for the subprocess or <code>null</code> to
|
---|
300 | * to disable a timeout for the subprocess.
|
---|
301 | */
|
---|
302 | public Execute(ExecuteStreamHandler streamHandler,
|
---|
303 | ExecuteWatchdog watchdog) {
|
---|
304 | setStreamHandler(streamHandler);
|
---|
305 | this.watchdog = watchdog;
|
---|
306 | }
|
---|
307 |
|
---|
308 | /**
|
---|
309 | * @since Ant 1.6
|
---|
310 | */
|
---|
311 | public void setStreamHandler(ExecuteStreamHandler streamHandler) {
|
---|
312 | this.streamHandler = streamHandler;
|
---|
313 | }
|
---|
314 |
|
---|
315 | /**
|
---|
316 | * Returns the commandline used to create a subprocess.
|
---|
317 | *
|
---|
318 | * @return the commandline used to create a subprocess
|
---|
319 | */
|
---|
320 | public String[] getCommandline() {
|
---|
321 | return cmdl;
|
---|
322 | }
|
---|
323 |
|
---|
324 |
|
---|
325 | /**
|
---|
326 | * Sets the commandline of the subprocess to launch.
|
---|
327 | *
|
---|
328 | * @param commandline the commandline of the subprocess to launch
|
---|
329 | */
|
---|
330 | public void setCommandline(String[] commandline) {
|
---|
331 | cmdl = commandline;
|
---|
332 | }
|
---|
333 |
|
---|
334 | /**
|
---|
335 | * Set whether to propagate the default environment or not.
|
---|
336 | *
|
---|
337 | * @param newenv whether to propagate the process environment.
|
---|
338 | */
|
---|
339 | public void setNewenvironment(boolean newenv) {
|
---|
340 | newEnvironment = newenv;
|
---|
341 | }
|
---|
342 |
|
---|
343 | /**
|
---|
344 | * Returns the environment used to create a subprocess.
|
---|
345 | *
|
---|
346 | * @return the environment used to create a subprocess
|
---|
347 | */
|
---|
348 | public String[] getEnvironment() {
|
---|
349 | if (env == null || newEnvironment) {
|
---|
350 | return env;
|
---|
351 | }
|
---|
352 | return patchEnvironment();
|
---|
353 | }
|
---|
354 |
|
---|
355 |
|
---|
356 | /**
|
---|
357 | * Sets the environment variables for the subprocess to launch.
|
---|
358 | *
|
---|
359 | * @param env array of Strings, each element of which has
|
---|
360 | * an environment variable settings in format <em>key=value</em>
|
---|
361 | */
|
---|
362 | public void setEnvironment(String[] env) {
|
---|
363 | this.env = env;
|
---|
364 | }
|
---|
365 |
|
---|
366 | /**
|
---|
367 | * Sets the working directory of the process to execute.
|
---|
368 | *
|
---|
369 | * <p>This is emulated using the antRun scripts unless the OS is
|
---|
370 | * Windows NT in which case a cmd.exe is spawned,
|
---|
371 | * or MRJ and setting user.dir works, or JDK 1.3 and there is
|
---|
372 | * official support in java.lang.Runtime.
|
---|
373 | *
|
---|
374 | * @param wd the working directory of the process.
|
---|
375 | */
|
---|
376 | public void setWorkingDirectory(File wd) {
|
---|
377 | if (wd == null || wd.getAbsolutePath().equals(antWorkingDirectory)) {
|
---|
378 | workingDirectory = null;
|
---|
379 | } else {
|
---|
380 | workingDirectory = wd;
|
---|
381 | }
|
---|
382 | }
|
---|
383 |
|
---|
384 | /**
|
---|
385 | * Set the name of the antRun script using the project's value.
|
---|
386 | *
|
---|
387 | * @param project the current project.
|
---|
388 | *
|
---|
389 | * @throws BuildException not clear when it is going to throw an exception, but
|
---|
390 | * it is the method's signature
|
---|
391 | */
|
---|
392 | public void setAntRun(Project project) throws BuildException {
|
---|
393 | this.project = project;
|
---|
394 | }
|
---|
395 |
|
---|
396 | /**
|
---|
397 | * Launch this execution through the VM, where possible, rather than through
|
---|
398 | * the OS's shell. In some cases and operating systems using the shell will
|
---|
399 | * allow the shell to perform additional processing such as associating an
|
---|
400 | * executable with a script, etc
|
---|
401 | *
|
---|
402 | * @param useVMLauncher true if exec should launch through the VM,
|
---|
403 | * false if the shell should be used to launch the
|
---|
404 | * command.
|
---|
405 | */
|
---|
406 | public void setVMLauncher(boolean useVMLauncher) {
|
---|
407 | this.useVMLauncher = useVMLauncher;
|
---|
408 | }
|
---|
409 |
|
---|
410 | /**
|
---|
411 | * Creates a process that runs a command.
|
---|
412 | *
|
---|
413 | * @param project the Project, only used for logging purposes, may be null.
|
---|
414 | * @param command the command to run
|
---|
415 | * @param env the environment for the command
|
---|
416 | * @param dir the working directory for the command
|
---|
417 | * @param useVM use the built-in exec command for JDK 1.3 if available.
|
---|
418 | * @return the process started
|
---|
419 | * @throws IOException forwarded from the particular launcher used
|
---|
420 | *
|
---|
421 | * @since Ant 1.5
|
---|
422 | */
|
---|
423 | public static Process launch(Project project, String[] command,
|
---|
424 | String[] env, File dir, boolean useVM)
|
---|
425 | throws IOException {
|
---|
426 | CommandLauncher launcher
|
---|
427 | = vmLauncher != null ? vmLauncher : shellLauncher;
|
---|
428 | if (!useVM) {
|
---|
429 | launcher = shellLauncher;
|
---|
430 | }
|
---|
431 |
|
---|
432 | if (dir != null && !dir.exists()) {
|
---|
433 | throw new BuildException(dir + " doesn't exist.");
|
---|
434 | }
|
---|
435 | return launcher.exec(project, command, env, dir);
|
---|
436 | }
|
---|
437 |
|
---|
438 | /**
|
---|
439 | * Runs a process defined by the command line and returns its exit status.
|
---|
440 | *
|
---|
441 | * @return the exit status of the subprocess or <code>INVALID</code>
|
---|
442 | * @exception java.io.IOException The exception is thrown, if launching
|
---|
443 | * of the subprocess failed
|
---|
444 | */
|
---|
445 | public int execute() throws IOException {
|
---|
446 | if (workingDirectory != null && !workingDirectory.exists()) {
|
---|
447 | throw new BuildException(workingDirectory + " doesn't exist.");
|
---|
448 | }
|
---|
449 | final Process process = launch(project, getCommandline(),
|
---|
450 | getEnvironment(), workingDirectory,
|
---|
451 | useVMLauncher);
|
---|
452 |
|
---|
453 | try {
|
---|
454 | streamHandler.setProcessInputStream(process.getOutputStream());
|
---|
455 | streamHandler.setProcessOutputStream(process.getInputStream());
|
---|
456 | streamHandler.setProcessErrorStream(process.getErrorStream());
|
---|
457 | } catch (IOException e) {
|
---|
458 | process.destroy();
|
---|
459 | throw e;
|
---|
460 | }
|
---|
461 | streamHandler.start();
|
---|
462 |
|
---|
463 | try {
|
---|
464 | // add the process to the list of those to destroy if the VM exits
|
---|
465 | //
|
---|
466 | processDestroyer.add(process);
|
---|
467 |
|
---|
468 | if (watchdog != null) {
|
---|
469 | watchdog.start(process);
|
---|
470 | }
|
---|
471 | waitFor(process);
|
---|
472 |
|
---|
473 | if (watchdog != null) {
|
---|
474 | watchdog.stop();
|
---|
475 | }
|
---|
476 | streamHandler.stop();
|
---|
477 | closeStreams(process);
|
---|
478 |
|
---|
479 | if (watchdog != null) {
|
---|
480 | watchdog.checkException();
|
---|
481 | }
|
---|
482 | return getExitValue();
|
---|
483 | } catch (ThreadDeath t) {
|
---|
484 | // #31928: forcibly kill it before continuing.
|
---|
485 | process.destroy();
|
---|
486 | throw t;
|
---|
487 | } finally {
|
---|
488 | // remove the process to the list of those to destroy if the VM exits
|
---|
489 | //
|
---|
490 | processDestroyer.remove(process);
|
---|
491 | }
|
---|
492 | }
|
---|
493 |
|
---|
494 | /**
|
---|
495 | * Starts a process defined by the command line.
|
---|
496 | * Ant will not wait for this process, nor log its output
|
---|
497 | *
|
---|
498 | * @throws java.io.IOException The exception is thrown, if launching
|
---|
499 | * of the subprocess failed
|
---|
500 | * @since ant 1.6
|
---|
501 | */
|
---|
502 | public void spawn() throws IOException {
|
---|
503 | if (workingDirectory != null && !workingDirectory.exists()) {
|
---|
504 | throw new BuildException(workingDirectory + " doesn't exist.");
|
---|
505 | }
|
---|
506 | final Process process = launch(project, getCommandline(),
|
---|
507 | getEnvironment(), workingDirectory,
|
---|
508 | useVMLauncher);
|
---|
509 | if (Os.isFamily("windows")) {
|
---|
510 | try {
|
---|
511 | Thread.sleep(1000);
|
---|
512 | } catch (InterruptedException e) {
|
---|
513 | project.log("interruption in the sleep after having spawned a process",
|
---|
514 | Project.MSG_VERBOSE);
|
---|
515 | }
|
---|
516 | }
|
---|
517 |
|
---|
518 | OutputStream dummyOut = new OutputStream() {
|
---|
519 | public void write(int b) throws IOException {
|
---|
520 | }
|
---|
521 | };
|
---|
522 |
|
---|
523 | ExecuteStreamHandler streamHandler = new PumpStreamHandler(dummyOut);
|
---|
524 | streamHandler.setProcessErrorStream(process.getErrorStream());
|
---|
525 | streamHandler.setProcessOutputStream(process.getInputStream());
|
---|
526 | streamHandler.start();
|
---|
527 | process.getOutputStream().close();
|
---|
528 |
|
---|
529 | project.log("spawned process " + process.toString(), Project.MSG_VERBOSE);
|
---|
530 | }
|
---|
531 |
|
---|
532 | /**
|
---|
533 | * wait for a given process
|
---|
534 | *
|
---|
535 | * @param process the process one wants to wait for
|
---|
536 | */
|
---|
537 | protected void waitFor(Process process) {
|
---|
538 | try {
|
---|
539 | process.waitFor();
|
---|
540 | setExitValue(process.exitValue());
|
---|
541 | } catch (InterruptedException e) {
|
---|
542 | process.destroy();
|
---|
543 | }
|
---|
544 | }
|
---|
545 |
|
---|
546 | /**
|
---|
547 | * set the exit value
|
---|
548 | *
|
---|
549 | * @param value exit value of the process
|
---|
550 | */
|
---|
551 | protected void setExitValue(int value) {
|
---|
552 | exitValue = value;
|
---|
553 | }
|
---|
554 |
|
---|
555 | /**
|
---|
556 | * Query the exit value of the process.
|
---|
557 | * @return the exit value or Execute.INVALID if no exit value has
|
---|
558 | * been received
|
---|
559 | */
|
---|
560 | public int getExitValue() {
|
---|
561 | return exitValue;
|
---|
562 | }
|
---|
563 |
|
---|
564 | /**
|
---|
565 | * Checks whether <code>exitValue</code> signals a failure on the current
|
---|
566 | * system (OS specific).
|
---|
567 | *
|
---|
568 | * <p><b>Note</b> that this method relies on the conventions of
|
---|
569 | * the OS, it will return false results if the application you are
|
---|
570 | * running doesn't follow these conventions. One notable
|
---|
571 | * exception is the Java VM provided by HP for OpenVMS - it will
|
---|
572 | * return 0 if successful (like on any other platform), but this
|
---|
573 | * signals a failure on OpenVMS. So if you execute a new Java VM
|
---|
574 | * on OpenVMS, you cannot trust this method.</p>
|
---|
575 | *
|
---|
576 | * @param exitValue the exit value (return code) to be checked
|
---|
577 | * @return <code>true</code> if <code>exitValue</code> signals a failure
|
---|
578 | */
|
---|
579 | public static boolean isFailure(int exitValue) {
|
---|
580 | if (Os.isFamily("openvms")) {
|
---|
581 | // even exit value signals failure
|
---|
582 | return (exitValue % 2) == 0;
|
---|
583 | } else {
|
---|
584 | // non zero exit value signals failure
|
---|
585 | return exitValue != 0;
|
---|
586 | }
|
---|
587 | }
|
---|
588 |
|
---|
589 | /**
|
---|
590 | * test for an untimely death of the process
|
---|
591 | * @return true if a watchdog had to kill the process
|
---|
592 | * @since Ant 1.5
|
---|
593 | */
|
---|
594 | public boolean killedProcess() {
|
---|
595 | return watchdog != null && watchdog.killedProcess();
|
---|
596 | }
|
---|
597 |
|
---|
598 | /**
|
---|
599 | * Patch the current environment with the new values from the user.
|
---|
600 | * @return the patched environment
|
---|
601 | */
|
---|
602 | private String[] patchEnvironment() {
|
---|
603 | // On OpenVMS Runtime#exec() doesn't support the environment array,
|
---|
604 | // so we only return the new values which then will be set in
|
---|
605 | // the generated DCL script, inheriting the parent process environment
|
---|
606 | if (Os.isFamily("openvms")) {
|
---|
607 | return env;
|
---|
608 | }
|
---|
609 |
|
---|
610 | Vector osEnv = (Vector) getProcEnvironment().clone();
|
---|
611 | for (int i = 0; i < env.length; i++) {
|
---|
612 | int pos = env[i].indexOf('=');
|
---|
613 | // Get key including "="
|
---|
614 | String key = env[i].substring(0, pos + 1);
|
---|
615 | int size = osEnv.size();
|
---|
616 | for (int j = 0; j < size; j++) {
|
---|
617 | if (((String) osEnv.elementAt(j)).startsWith(key)) {
|
---|
618 | osEnv.removeElementAt(j);
|
---|
619 | break;
|
---|
620 | }
|
---|
621 | }
|
---|
622 | osEnv.addElement(env[i]);
|
---|
623 | }
|
---|
624 | String[] result = new String[osEnv.size()];
|
---|
625 | osEnv.copyInto(result);
|
---|
626 | return result;
|
---|
627 | }
|
---|
628 |
|
---|
629 | /**
|
---|
630 | * A utility method that runs an external command. Writes the output and
|
---|
631 | * error streams of the command to the project log.
|
---|
632 | *
|
---|
633 | * @param task The task that the command is part of. Used for logging
|
---|
634 | * @param cmdline The command to execute.
|
---|
635 | *
|
---|
636 | * @throws BuildException if the command does not return 0.
|
---|
637 | */
|
---|
638 | public static void runCommand(Task task, String[] cmdline)
|
---|
639 | throws BuildException {
|
---|
640 | try {
|
---|
641 | task.log(Commandline.describeCommand(cmdline),
|
---|
642 | Project.MSG_VERBOSE);
|
---|
643 | Execute exe = new Execute(new LogStreamHandler(task,
|
---|
644 | Project.MSG_INFO,
|
---|
645 | Project.MSG_ERR));
|
---|
646 | exe.setAntRun(task.getProject());
|
---|
647 | exe.setCommandline(cmdline);
|
---|
648 | int retval = exe.execute();
|
---|
649 | if (isFailure(retval)) {
|
---|
650 | throw new BuildException(cmdline[0]
|
---|
651 | + " failed with return code " + retval, task.getLocation());
|
---|
652 | }
|
---|
653 | } catch (java.io.IOException exc) {
|
---|
654 | throw new BuildException("Could not launch " + cmdline[0] + ": "
|
---|
655 | + exc, task.getLocation());
|
---|
656 | }
|
---|
657 | }
|
---|
658 |
|
---|
659 | /**
|
---|
660 | * Close the streams belonging to the given Process.
|
---|
661 | * @param process the <CODE>Process</CODE>.
|
---|
662 | */
|
---|
663 | public static void closeStreams(Process process) {
|
---|
664 | try {
|
---|
665 | process.getInputStream().close();
|
---|
666 | } catch (IOException eyeOhEx) {
|
---|
667 | }
|
---|
668 | try {
|
---|
669 | process.getOutputStream().close();
|
---|
670 | } catch (IOException eyeOhEx) {
|
---|
671 | }
|
---|
672 | try {
|
---|
673 | process.getErrorStream().close();
|
---|
674 | } catch (IOException eyeOhEx) {
|
---|
675 | }
|
---|
676 | }
|
---|
677 |
|
---|
678 | /**
|
---|
679 | * This method is VMS specific and used by getProcEnvironment().
|
---|
680 | *
|
---|
681 | * Parses VMS logicals from <code>in</code> and adds them to
|
---|
682 | * <code>environment</code>. <code>in</code> is expected to be the
|
---|
683 | * output of "SHOW LOGICAL". The method takes care of parsing the output
|
---|
684 | * correctly as well as making sure that a logical defined in multiple
|
---|
685 | * tables only gets added from the highest order table. Logicals with
|
---|
686 | * multiple equivalence names are mapped to a variable with multiple
|
---|
687 | * values separated by a comma (,).
|
---|
688 | */
|
---|
689 | private static Vector addVMSLogicals(Vector environment, BufferedReader in)
|
---|
690 | throws IOException {
|
---|
691 | HashMap logicals = new HashMap();
|
---|
692 | String logName = null, logValue = null, newLogName;
|
---|
693 | String line = null;
|
---|
694 | while ((line = in.readLine()) != null) {
|
---|
695 | // parse the VMS logicals into required format ("VAR=VAL[,VAL2]")
|
---|
696 | if (line.startsWith("\t=")) {
|
---|
697 | // further equivalence name of previous logical
|
---|
698 | if (logName != null) {
|
---|
699 | logValue += "," + line.substring(4, line.length() - 1);
|
---|
700 | }
|
---|
701 | } else if (line.startsWith(" \"")) {
|
---|
702 | // new logical?
|
---|
703 | if (logName != null) {
|
---|
704 | logicals.put(logName, logValue);
|
---|
705 | }
|
---|
706 | int eqIndex = line.indexOf('=');
|
---|
707 | newLogName = line.substring(3, eqIndex - 2);
|
---|
708 | if (logicals.containsKey(newLogName)) {
|
---|
709 | // already got this logical from a higher order table
|
---|
710 | logName = null;
|
---|
711 | } else {
|
---|
712 | logName = newLogName;
|
---|
713 | logValue = line.substring(eqIndex + 3, line.length() - 1);
|
---|
714 | }
|
---|
715 | }
|
---|
716 | }
|
---|
717 | // Since we "look ahead" before adding, there's one last env var.
|
---|
718 | if (logName != null) {
|
---|
719 | logicals.put(logName, logValue);
|
---|
720 | }
|
---|
721 |
|
---|
722 | for (Iterator i = logicals.keySet().iterator(); i.hasNext();) {
|
---|
723 | String logical = (String) i.next();
|
---|
724 | environment.add(logical + "=" + logicals.get(logical));
|
---|
725 | }
|
---|
726 | return environment;
|
---|
727 | }
|
---|
728 |
|
---|
729 | /**
|
---|
730 | * A command launcher for a particular JVM/OS platform. This class is
|
---|
731 | * a general purpose command launcher which can only launch commands in
|
---|
732 | * the current working directory.
|
---|
733 | */
|
---|
734 | private static class CommandLauncher {
|
---|
735 | /**
|
---|
736 | * Launches the given command in a new process.
|
---|
737 | *
|
---|
738 | * @param project The project that the command is part of
|
---|
739 | * @param cmd The command to execute
|
---|
740 | * @param env The environment for the new process. If null,
|
---|
741 | * the environment of the current process is used.
|
---|
742 | * @throws IOException if attempting to run a command in a specific directory
|
---|
743 | */
|
---|
744 | public Process exec(Project project, String[] cmd, String[] env)
|
---|
745 | throws IOException {
|
---|
746 | if (project != null) {
|
---|
747 | project.log("Execute:CommandLauncher: "
|
---|
748 | + Commandline.describeCommand(cmd), Project.MSG_DEBUG);
|
---|
749 | }
|
---|
750 | return Runtime.getRuntime().exec(cmd, env);
|
---|
751 | }
|
---|
752 |
|
---|
753 | /**
|
---|
754 | * Launches the given command in a new process, in the given working
|
---|
755 | * directory.
|
---|
756 | *
|
---|
757 | * @param project The project that the command is part of
|
---|
758 | * @param cmd The command to execute
|
---|
759 | * @param env The environment for the new process. If null,
|
---|
760 | * the environment of the current process is used.
|
---|
761 | * @param workingDir The directory to start the command in. If null,
|
---|
762 | * the current directory is used
|
---|
763 | * @throws IOException if trying to change directory
|
---|
764 | */
|
---|
765 | public Process exec(Project project, String[] cmd, String[] env,
|
---|
766 | File workingDir) throws IOException {
|
---|
767 | if (workingDir == null) {
|
---|
768 | return exec(project, cmd, env);
|
---|
769 | }
|
---|
770 | throw new IOException("Cannot execute a process in different "
|
---|
771 | + "directory under this JVM");
|
---|
772 | }
|
---|
773 | }
|
---|
774 |
|
---|
775 | /**
|
---|
776 | * A command launcher for JDK/JRE 1.1 under Windows. Fixes quoting problems
|
---|
777 | * in Runtime.exec(). Can only launch commands in the current working
|
---|
778 | * directory
|
---|
779 | */
|
---|
780 | private static class Java11CommandLauncher extends CommandLauncher {
|
---|
781 | /**
|
---|
782 | * Launches the given command in a new process. Needs to quote
|
---|
783 | * arguments
|
---|
784 | * @param project the ant project
|
---|
785 | * @param cmd the command line to execute as an array of strings
|
---|
786 | * @param env the environment to set as an array of strings
|
---|
787 | * @throws IOException probably forwarded from Runtime#exec
|
---|
788 | */
|
---|
789 | public Process exec(Project project, String[] cmd, String[] env)
|
---|
790 | throws IOException {
|
---|
791 | // Need to quote arguments with spaces, and to escape
|
---|
792 | // quote characters
|
---|
793 | String[] newcmd = new String[cmd.length];
|
---|
794 | for (int i = 0; i < cmd.length; i++) {
|
---|
795 | newcmd[i] = Commandline.quoteArgument(cmd[i]);
|
---|
796 | }
|
---|
797 | if (project != null) {
|
---|
798 | project.log("Execute:Java11CommandLauncher: "
|
---|
799 | + Commandline.describeCommand(newcmd), Project.MSG_DEBUG);
|
---|
800 | }
|
---|
801 | return Runtime.getRuntime().exec(newcmd, env);
|
---|
802 | }
|
---|
803 | }
|
---|
804 |
|
---|
805 | /**
|
---|
806 | * A command launcher for JDK/JRE 1.3 (and higher). Uses the built-in
|
---|
807 | * Runtime.exec() command
|
---|
808 | */
|
---|
809 | private static class Java13CommandLauncher extends CommandLauncher {
|
---|
810 | public Java13CommandLauncher() throws NoSuchMethodException {
|
---|
811 | // Locate method Runtime.exec(String[] cmdarray,
|
---|
812 | // String[] envp, File dir)
|
---|
813 | myExecWithCWD = Runtime.class.getMethod("exec",
|
---|
814 | new Class[] {String[].class, String[].class, File.class});
|
---|
815 | }
|
---|
816 |
|
---|
817 | /**
|
---|
818 | * Launches the given command in a new process, in the given working
|
---|
819 | * directory
|
---|
820 | * @param project the ant project
|
---|
821 | * @param cmd the command line to execute as an array of strings
|
---|
822 | * @param env the environment to set as an array of strings
|
---|
823 | * @param workingDir the working directory where the command should run
|
---|
824 | * @throws IOException probably forwarded from Runtime#exec
|
---|
825 | */
|
---|
826 | public Process exec(Project project, String[] cmd, String[] env,
|
---|
827 | File workingDir) throws IOException {
|
---|
828 | try {
|
---|
829 | if (project != null) {
|
---|
830 | project.log("Execute:Java13CommandLauncher: "
|
---|
831 | + Commandline.describeCommand(cmd), Project.MSG_DEBUG);
|
---|
832 | }
|
---|
833 | Object[] arguments = {cmd, env, workingDir};
|
---|
834 | return (Process) myExecWithCWD.invoke(Runtime.getRuntime(),
|
---|
835 | arguments);
|
---|
836 | } catch (InvocationTargetException exc) {
|
---|
837 | Throwable realexc = exc.getTargetException();
|
---|
838 | if (realexc instanceof ThreadDeath) {
|
---|
839 | throw (ThreadDeath) realexc;
|
---|
840 | } else if (realexc instanceof IOException) {
|
---|
841 | throw (IOException) realexc;
|
---|
842 | } else {
|
---|
843 | throw new BuildException("Unable to execute command",
|
---|
844 | realexc);
|
---|
845 | }
|
---|
846 | } catch (Exception exc) {
|
---|
847 | // IllegalAccess, IllegalArgument, ClassCast
|
---|
848 | throw new BuildException("Unable to execute command", exc);
|
---|
849 | }
|
---|
850 | }
|
---|
851 |
|
---|
852 | private Method myExecWithCWD;
|
---|
853 | }
|
---|
854 |
|
---|
855 | /**
|
---|
856 | * A command launcher that proxies another command launcher.
|
---|
857 | *
|
---|
858 | * Sub-classes override exec(args, env, workdir)
|
---|
859 | */
|
---|
860 | private static class CommandLauncherProxy extends CommandLauncher {
|
---|
861 | CommandLauncherProxy(CommandLauncher launcher) {
|
---|
862 | myLauncher = launcher;
|
---|
863 | }
|
---|
864 |
|
---|
865 | /**
|
---|
866 | * Launches the given command in a new process. Delegates this
|
---|
867 | * method to the proxied launcher
|
---|
868 | * @param project the ant project
|
---|
869 | * @param cmd the command line to execute as an array of strings
|
---|
870 | * @param env the environment to set as an array of strings
|
---|
871 | * @throws IOException forwarded from the exec method of the command launcher
|
---|
872 | */
|
---|
873 | public Process exec(Project project, String[] cmd, String[] env)
|
---|
874 | throws IOException {
|
---|
875 | return myLauncher.exec(project, cmd, env);
|
---|
876 | }
|
---|
877 |
|
---|
878 | private CommandLauncher myLauncher;
|
---|
879 | }
|
---|
880 |
|
---|
881 | /**
|
---|
882 | * A command launcher for OS/2 that uses 'cmd.exe' when launching
|
---|
883 | * commands in directories other than the current working
|
---|
884 | * directory.
|
---|
885 | *
|
---|
886 | * <p>Unlike Windows NT and friends, OS/2's cd doesn't support the
|
---|
887 | * /d switch to change drives and directories in one go.</p>
|
---|
888 | */
|
---|
889 | private static class OS2CommandLauncher extends CommandLauncherProxy {
|
---|
890 | OS2CommandLauncher(CommandLauncher launcher) {
|
---|
891 | super(launcher);
|
---|
892 | }
|
---|
893 |
|
---|
894 | /**
|
---|
895 | * Launches the given command in a new process, in the given working
|
---|
896 | * directory.
|
---|
897 | * @param project the ant project
|
---|
898 | * @param cmd the command line to execute as an array of strings
|
---|
899 | * @param env the environment to set as an array of strings
|
---|
900 | * @param workingDir working directory where the command should run
|
---|
901 | * @throws IOException forwarded from the exec method of the command launcher
|
---|
902 | */
|
---|
903 | public Process exec(Project project, String[] cmd, String[] env,
|
---|
904 | File workingDir) throws IOException {
|
---|
905 | File commandDir = workingDir;
|
---|
906 | if (workingDir == null) {
|
---|
907 | if (project != null) {
|
---|
908 | commandDir = project.getBaseDir();
|
---|
909 | } else {
|
---|
910 | return exec(project, cmd, env);
|
---|
911 | }
|
---|
912 | }
|
---|
913 |
|
---|
914 | // Use cmd.exe to change to the specified drive and
|
---|
915 | // directory before running the command
|
---|
916 | final int preCmdLength = 7;
|
---|
917 | final String cmdDir = commandDir.getAbsolutePath();
|
---|
918 | String[] newcmd = new String[cmd.length + preCmdLength];
|
---|
919 | newcmd[0] = "cmd";
|
---|
920 | newcmd[1] = "/c";
|
---|
921 | newcmd[2] = cmdDir.substring(0, 2);
|
---|
922 | newcmd[3] = "&&";
|
---|
923 | newcmd[4] = "cd";
|
---|
924 | newcmd[5] = cmdDir.substring(2);
|
---|
925 | newcmd[6] = "&&";
|
---|
926 | System.arraycopy(cmd, 0, newcmd, preCmdLength, cmd.length);
|
---|
927 |
|
---|
928 | return exec(project, newcmd, env);
|
---|
929 | }
|
---|
930 | }
|
---|
931 |
|
---|
932 | /**
|
---|
933 | * A command launcher for Windows XP/2000/NT that uses 'cmd.exe' when
|
---|
934 | * launching commands in directories other than the current working
|
---|
935 | * directory.
|
---|
936 | */
|
---|
937 | private static class WinNTCommandLauncher extends CommandLauncherProxy {
|
---|
938 | WinNTCommandLauncher(CommandLauncher launcher) {
|
---|
939 | super(launcher);
|
---|
940 | }
|
---|
941 |
|
---|
942 | /**
|
---|
943 | * Launches the given command in a new process, in the given working
|
---|
944 | * directory.
|
---|
945 | * @param project the ant project
|
---|
946 | * @param cmd the command line to execute as an array of strings
|
---|
947 | * @param env the environment to set as an array of strings
|
---|
948 | * @param workingDir working directory where the command should run
|
---|
949 | * @throws IOException forwarded from the exec method of the command launcher
|
---|
950 | */
|
---|
951 | public Process exec(Project project, String[] cmd, String[] env,
|
---|
952 | File workingDir) throws IOException {
|
---|
953 | File commandDir = workingDir;
|
---|
954 | if (workingDir == null) {
|
---|
955 | if (project != null) {
|
---|
956 | commandDir = project.getBaseDir();
|
---|
957 | } else {
|
---|
958 | return exec(project, cmd, env);
|
---|
959 | }
|
---|
960 | }
|
---|
961 |
|
---|
962 | // Use cmd.exe to change to the specified directory before running
|
---|
963 | // the command
|
---|
964 | final int preCmdLength = 6;
|
---|
965 | String[] newcmd = new String[cmd.length + preCmdLength];
|
---|
966 | newcmd[0] = "cmd";
|
---|
967 | newcmd[1] = "/c";
|
---|
968 | newcmd[2] = "cd";
|
---|
969 | newcmd[3] = "/d";
|
---|
970 | newcmd[4] = commandDir.getAbsolutePath();
|
---|
971 | newcmd[5] = "&&";
|
---|
972 | System.arraycopy(cmd, 0, newcmd, preCmdLength, cmd.length);
|
---|
973 |
|
---|
974 | return exec(project, newcmd, env);
|
---|
975 | }
|
---|
976 | }
|
---|
977 |
|
---|
978 | /**
|
---|
979 | * A command launcher for Mac that uses a dodgy mechanism to change
|
---|
980 | * working directory before launching commands.
|
---|
981 | */
|
---|
982 | private static class MacCommandLauncher extends CommandLauncherProxy {
|
---|
983 | MacCommandLauncher(CommandLauncher launcher) {
|
---|
984 | super(launcher);
|
---|
985 | }
|
---|
986 |
|
---|
987 | /**
|
---|
988 | * Launches the given command in a new process, in the given working
|
---|
989 | * directory
|
---|
990 | * @param project the ant project
|
---|
991 | * @param cmd the command line to execute as an array of strings
|
---|
992 | * @param env the environment to set as an array of strings
|
---|
993 | * @param workingDir working directory where the command should run
|
---|
994 | * @throws IOException forwarded from the exec method of the command launcher
|
---|
995 | */
|
---|
996 | public Process exec(Project project, String[] cmd, String[] env,
|
---|
997 | File workingDir) throws IOException {
|
---|
998 | if (workingDir == null) {
|
---|
999 | return exec(project, cmd, env);
|
---|
1000 | }
|
---|
1001 |
|
---|
1002 | System.getProperties().put("user.dir", workingDir.getAbsolutePath());
|
---|
1003 | try {
|
---|
1004 | return exec(project, cmd, env);
|
---|
1005 | } finally {
|
---|
1006 | System.getProperties().put("user.dir", antWorkingDirectory);
|
---|
1007 | }
|
---|
1008 | }
|
---|
1009 | }
|
---|
1010 |
|
---|
1011 | /**
|
---|
1012 | * A command launcher that uses an auxiliary script to launch commands
|
---|
1013 | * in directories other than the current working directory.
|
---|
1014 | */
|
---|
1015 | private static class ScriptCommandLauncher extends CommandLauncherProxy {
|
---|
1016 | ScriptCommandLauncher(String script, CommandLauncher launcher) {
|
---|
1017 | super(launcher);
|
---|
1018 | myScript = script;
|
---|
1019 | }
|
---|
1020 |
|
---|
1021 | /**
|
---|
1022 | * Launches the given command in a new process, in the given working
|
---|
1023 | * directory
|
---|
1024 | */
|
---|
1025 | public Process exec(Project project, String[] cmd, String[] env,
|
---|
1026 | File workingDir) throws IOException {
|
---|
1027 | if (project == null) {
|
---|
1028 | if (workingDir == null) {
|
---|
1029 | return exec(project, cmd, env);
|
---|
1030 | }
|
---|
1031 | throw new IOException("Cannot locate antRun script: "
|
---|
1032 | + "No project provided");
|
---|
1033 | }
|
---|
1034 |
|
---|
1035 | // Locate the auxiliary script
|
---|
1036 | String antHome = project.getProperty("ant.home");
|
---|
1037 | if (antHome == null) {
|
---|
1038 | throw new IOException("Cannot locate antRun script: "
|
---|
1039 | + "Property 'ant.home' not found");
|
---|
1040 | }
|
---|
1041 | String antRun = project.resolveFile(antHome + File.separator + myScript).toString();
|
---|
1042 |
|
---|
1043 | // Build the command
|
---|
1044 | File commandDir = workingDir;
|
---|
1045 | if (workingDir == null && project != null) {
|
---|
1046 | commandDir = project.getBaseDir();
|
---|
1047 | }
|
---|
1048 |
|
---|
1049 | String[] newcmd = new String[cmd.length + 2];
|
---|
1050 | newcmd[0] = antRun;
|
---|
1051 | newcmd[1] = commandDir.getAbsolutePath();
|
---|
1052 | System.arraycopy(cmd, 0, newcmd, 2, cmd.length);
|
---|
1053 |
|
---|
1054 | return exec(project, newcmd, env);
|
---|
1055 | }
|
---|
1056 |
|
---|
1057 | private String myScript;
|
---|
1058 | }
|
---|
1059 |
|
---|
1060 | /**
|
---|
1061 | * A command launcher that uses an auxiliary perl script to launch commands
|
---|
1062 | * in directories other than the current working directory.
|
---|
1063 | */
|
---|
1064 | private static class PerlScriptCommandLauncher
|
---|
1065 | extends CommandLauncherProxy {
|
---|
1066 | PerlScriptCommandLauncher(String script, CommandLauncher launcher) {
|
---|
1067 | super(launcher);
|
---|
1068 | myScript = script;
|
---|
1069 | }
|
---|
1070 |
|
---|
1071 | /**
|
---|
1072 | * Launches the given command in a new process, in the given working
|
---|
1073 | * directory
|
---|
1074 | */
|
---|
1075 | public Process exec(Project project, String[] cmd, String[] env,
|
---|
1076 | File workingDir) throws IOException {
|
---|
1077 | if (project == null) {
|
---|
1078 | if (workingDir == null) {
|
---|
1079 | return exec(project, cmd, env);
|
---|
1080 | }
|
---|
1081 | throw new IOException("Cannot locate antRun script: "
|
---|
1082 | + "No project provided");
|
---|
1083 | }
|
---|
1084 |
|
---|
1085 | // Locate the auxiliary script
|
---|
1086 | String antHome = project.getProperty("ant.home");
|
---|
1087 | if (antHome == null) {
|
---|
1088 | throw new IOException("Cannot locate antRun script: "
|
---|
1089 | + "Property 'ant.home' not found");
|
---|
1090 | }
|
---|
1091 | String antRun = project.resolveFile(antHome + File.separator + myScript).toString();
|
---|
1092 |
|
---|
1093 | // Build the command
|
---|
1094 | File commandDir = workingDir;
|
---|
1095 | if (workingDir == null && project != null) {
|
---|
1096 | commandDir = project.getBaseDir();
|
---|
1097 | }
|
---|
1098 |
|
---|
1099 | String[] newcmd = new String[cmd.length + 3];
|
---|
1100 | newcmd[0] = "perl";
|
---|
1101 | newcmd[1] = antRun;
|
---|
1102 | newcmd[2] = commandDir.getAbsolutePath();
|
---|
1103 | System.arraycopy(cmd, 0, newcmd, 3, cmd.length);
|
---|
1104 |
|
---|
1105 | return exec(project, newcmd, env);
|
---|
1106 | }
|
---|
1107 |
|
---|
1108 | private String myScript;
|
---|
1109 | }
|
---|
1110 |
|
---|
1111 | /**
|
---|
1112 | * A command launcher for VMS that writes the command to a temporary DCL
|
---|
1113 | * script before launching commands. This is due to limitations of both
|
---|
1114 | * the DCL interpreter and the Java VM implementation.
|
---|
1115 | */
|
---|
1116 | private static class VmsCommandLauncher extends Java13CommandLauncher {
|
---|
1117 |
|
---|
1118 | public VmsCommandLauncher() throws NoSuchMethodException {
|
---|
1119 | super();
|
---|
1120 | }
|
---|
1121 |
|
---|
1122 | /**
|
---|
1123 | * Launches the given command in a new process.
|
---|
1124 | */
|
---|
1125 | public Process exec(Project project, String[] cmd, String[] env)
|
---|
1126 | throws IOException {
|
---|
1127 | String[] vmsCmd = {createCommandFile(cmd, env).getPath()};
|
---|
1128 | return super.exec(project, vmsCmd, env);
|
---|
1129 | }
|
---|
1130 |
|
---|
1131 | /**
|
---|
1132 | * Launches the given command in a new process, in the given working
|
---|
1133 | * directory. Note that under Java 1.3.1, 1.4.0 and 1.4.1 on VMS this
|
---|
1134 | * method only works if <code>workingDir</code> is null or the logical
|
---|
1135 | * JAVA$FORK_SUPPORT_CHDIR needs to be set to TRUE.
|
---|
1136 | */
|
---|
1137 | public Process exec(Project project, String[] cmd, String[] env,
|
---|
1138 | File workingDir) throws IOException {
|
---|
1139 | String[] vmsCmd = {createCommandFile(cmd, env).getPath()};
|
---|
1140 | return super.exec(project, vmsCmd, env, workingDir);
|
---|
1141 | }
|
---|
1142 |
|
---|
1143 | /*
|
---|
1144 | * Writes the command into a temporary DCL script and returns the
|
---|
1145 | * corresponding File object. The script will be deleted on exit.
|
---|
1146 | */
|
---|
1147 | private File createCommandFile(String[] cmd, String[] env)
|
---|
1148 | throws IOException {
|
---|
1149 | File script = File.createTempFile("ANT", ".COM");
|
---|
1150 | script.deleteOnExit();
|
---|
1151 | PrintWriter out = null;
|
---|
1152 | try {
|
---|
1153 | out = new PrintWriter(new FileWriter(script));
|
---|
1154 |
|
---|
1155 | // add the environment as logicals to the DCL script
|
---|
1156 | if (env != null) {
|
---|
1157 | int eqIndex;
|
---|
1158 | for (int i = 1; i < env.length ; i++) {
|
---|
1159 | eqIndex = env[i].indexOf('=');
|
---|
1160 | if (eqIndex != -1) {
|
---|
1161 | out.print("$ DEFINE/NOLOG ");
|
---|
1162 | out.print(env[i].substring(0, eqIndex));
|
---|
1163 | out.print(" \"");
|
---|
1164 | out.print(env[i].substring(eqIndex + 1));
|
---|
1165 | out.println('\"');
|
---|
1166 | }
|
---|
1167 | }
|
---|
1168 | }
|
---|
1169 |
|
---|
1170 | out.print("$ " + cmd[0]);
|
---|
1171 | for (int i = 1; i < cmd.length ; i++) {
|
---|
1172 | out.println(" -");
|
---|
1173 | out.print(cmd[i]);
|
---|
1174 | }
|
---|
1175 | } finally {
|
---|
1176 | if (out != null) {
|
---|
1177 | out.close();
|
---|
1178 | }
|
---|
1179 | }
|
---|
1180 | return script;
|
---|
1181 | }
|
---|
1182 |
|
---|
1183 | }
|
---|
1184 | }
|
---|