diff --git a/src/main/org/apache/tools/ant/taskdefs/Execute.java b/src/main/org/apache/tools/ant/taskdefs/Execute.java index 50f32ffe6..e64269c0b 100644 --- a/src/main/org/apache/tools/ant/taskdefs/Execute.java +++ b/src/main/org/apache/tools/ant/taskdefs/Execute.java @@ -382,6 +382,28 @@ public class Execute { 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 the working directory for the command + * @param useVM use the built-in exec command for JDK 1.3 if available. + * + * @since 1.35, Ant 1.5 + */ + public static Process launch(Project project, String[] command, + String[] env, File dir, boolean useVM) + throws IOException { + CommandLauncher launcher = vmLauncher != null ? vmLauncher : shellLauncher; + if (!useVM) { + launcher = shellLauncher; + } + + return launcher.exec(project, command, env, dir); + } + /** * Runs a process defined by the command line and returns its exit status. * @@ -390,12 +412,10 @@ public class Execute { * of the subprocess failed */ public int execute() throws IOException { - CommandLauncher launcher = vmLauncher != null ? vmLauncher : shellLauncher; - if (!useVMLauncher) { - launcher = shellLauncher; - } + final Process process = launch(project, getCommandline(), + getEnvironment(), workingDirectory, + useVMLauncher); - final Process process = launcher.exec(project, getCommandline(), getEnvironment(), workingDirectory); try { streamHandler.setProcessInputStream(process.getOutputStream()); streamHandler.setProcessOutputStream(process.getInputStream()); diff --git a/src/main/org/apache/tools/ant/taskdefs/StreamPumper.java b/src/main/org/apache/tools/ant/taskdefs/StreamPumper.java index be4ad79c3..999979c9f 100644 --- a/src/main/org/apache/tools/ant/taskdefs/StreamPumper.java +++ b/src/main/org/apache/tools/ant/taskdefs/StreamPumper.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2000 The Apache Software Foundation. All rights + * Copyright (c) 2000,2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -72,7 +72,7 @@ public class StreamPumper implements Runnable { private final static int SIZE = 128; private InputStream is; private OutputStream os; - + private boolean finished; /** * Create a new stream pumper. @@ -92,6 +92,11 @@ public class StreamPumper implements Runnable { * Terminates as soon as the input stream is closed or an error occurs. */ public void run() { + synchronized(this) { + // Just in case this object is reused in the future + finished = false; + } + final byte[] buf = new byte[SIZE]; int length; @@ -102,6 +107,32 @@ public class StreamPumper implements Runnable { Thread.sleep(SLEEP); } catch (InterruptedException e) {} } - } catch(IOException e) {} + } catch(IOException e) { + } finally { + synchronized(this) { + finished = true; + notify(); + } + } + } + + /** + * Tells whether the end of the stream has been reached. + * @return true is the stream has been exhausted. + **/ + public synchronized boolean isFinished() { + return finished; + } + + /** + * This method blocks until the stream pumper finishes. + * @see #isFinished() + **/ + public synchronized void waitFor() + throws InterruptedException + { + while(!isFinished()) { + wait(); + } } } diff --git a/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java b/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java index 32845d8ad..92a337fbd 100644 --- a/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java +++ b/src/main/org/apache/tools/ant/taskdefs/optional/Cab.java @@ -1,7 +1,7 @@ /* * The Apache Software License, Version 1.1 * - * Copyright (c) 2000-2001 The Apache Software Foundation. All rights + * Copyright (c) 2000-2002 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without @@ -65,8 +65,11 @@ import java.util.Vector; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Execute; import org.apache.tools.ant.taskdefs.ExecTask; +import org.apache.tools.ant.taskdefs.LogOutputStream; import org.apache.tools.ant.taskdefs.MatchingTask; +import org.apache.tools.ant.taskdefs.StreamPumper; import org.apache.tools.ant.taskdefs.condition.Os; import org.apache.tools.ant.types.Commandline; import org.apache.tools.ant.types.FileSet; @@ -175,7 +178,7 @@ public class Cab extends MatchingTask { for (int i = 0; i < files.size() && upToDate; i++) { String file = files.elementAt(i).toString(); if (new File(baseDir, file).lastModified() > - cabFile.lastModified()) { + cabFile.lastModified()) { upToDate = false; } } @@ -212,7 +215,7 @@ public class Cab extends MatchingTask { * to be included in the cab, one file per line. */ protected File createListFile(Vector files) - throws IOException { + throws IOException { File listFile = fileUtils.createTempFile("ant", "", null); PrintWriter writer = new PrintWriter(new FileOutputStream(listFile)); @@ -286,11 +289,45 @@ public class Cab extends MatchingTask { sb.append("\n").append(cabFile.getAbsolutePath()).append("\n"); try { - Process p = Runtime.getRuntime().exec("listcab"); + Process p = Execute.launch(getProject(), + new String[] {"listcab"}, null, + baseDir, true); OutputStream out = p.getOutputStream(); out.write(sb.toString().getBytes()); out.flush(); out.close(); + + // Create the stream pumpers to forward listcab's stdout and stderr to the log + // note: listcab is an interactive program, and issues prompts for every new line. + // Therefore, make it show only with verbose logging turned on. + LogOutputStream outLog = new LogOutputStream(this, Project.MSG_VERBOSE); + LogOutputStream errLog = new LogOutputStream(this, Project.MSG_ERR); + StreamPumper outPump = new StreamPumper(p.getInputStream(), outLog); + StreamPumper errPump = new StreamPumper(p.getErrorStream(), errLog); + + // Pump streams asynchronously + (new Thread(outPump)).start(); + (new Thread(errPump)).start(); + + int result = -99; // A wild default for when the thread is interrupted + + try { + // Wait for the process to finish + result = p.waitFor(); + + // Wait for the end of output and error streams + outPump.waitFor(); + outLog.close(); + errPump.waitFor(); + errLog.close(); + } catch(InterruptedException ie) { + log("Thread interrupted: " + ie); + } + + // Informative summary message in case of errors + if(result != 0) { + log("Error executing listcab; error code: " + result); + } } catch (IOException ex) { String msg = "Problem creating " + cabFile + " " + ex.getMessage(); throw new BuildException(msg);