(1) it wouldn't use the basedir (2) all diagnostic messages have been swallowed Submitted by: Ilya A. Kriveshko <ilya@kaon.com> Note that this patch needs the magic of Execute but also access to the processes' standard input - this has been solved by adding a new static method launch to Execute which hands out the Process instance, the proper fix would be to handle input for the spawned processes as well. git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@271431 13f79535-47bb-0310-9956-ffa450edef68master
@@ -382,6 +382,28 @@ public class Execute { | |||||
this.useVMLauncher = 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 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. | * Runs a process defined by the command line and returns its exit status. | ||||
* | * | ||||
@@ -390,12 +412,10 @@ public class Execute { | |||||
* of the subprocess failed | * of the subprocess failed | ||||
*/ | */ | ||||
public int execute() throws IOException { | 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 { | try { | ||||
streamHandler.setProcessInputStream(process.getOutputStream()); | streamHandler.setProcessInputStream(process.getOutputStream()); | ||||
streamHandler.setProcessOutputStream(process.getInputStream()); | streamHandler.setProcessOutputStream(process.getInputStream()); | ||||
@@ -1,7 +1,7 @@ | |||||
/* | /* | ||||
* The Apache Software License, Version 1.1 | * 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. | * reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * 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 final static int SIZE = 128; | ||||
private InputStream is; | private InputStream is; | ||||
private OutputStream os; | private OutputStream os; | ||||
private boolean finished; | |||||
/** | /** | ||||
* Create a new stream pumper. | * 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. | * Terminates as soon as the input stream is closed or an error occurs. | ||||
*/ | */ | ||||
public void run() { | public void run() { | ||||
synchronized(this) { | |||||
// Just in case this object is reused in the future | |||||
finished = false; | |||||
} | |||||
final byte[] buf = new byte[SIZE]; | final byte[] buf = new byte[SIZE]; | ||||
int length; | int length; | ||||
@@ -102,6 +107,32 @@ public class StreamPumper implements Runnable { | |||||
Thread.sleep(SLEEP); | Thread.sleep(SLEEP); | ||||
} catch (InterruptedException e) {} | } 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(); | |||||
} | |||||
} | } | ||||
} | } |
@@ -1,7 +1,7 @@ | |||||
/* | /* | ||||
* The Apache Software License, Version 1.1 | * 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. | * reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * 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.BuildException; | ||||
import org.apache.tools.ant.DirectoryScanner; | import org.apache.tools.ant.DirectoryScanner; | ||||
import org.apache.tools.ant.Project; | 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.ExecTask; | ||||
import org.apache.tools.ant.taskdefs.LogOutputStream; | |||||
import org.apache.tools.ant.taskdefs.MatchingTask; | 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.taskdefs.condition.Os; | ||||
import org.apache.tools.ant.types.Commandline; | import org.apache.tools.ant.types.Commandline; | ||||
import org.apache.tools.ant.types.FileSet; | 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++) { | for (int i = 0; i < files.size() && upToDate; i++) { | ||||
String file = files.elementAt(i).toString(); | String file = files.elementAt(i).toString(); | ||||
if (new File(baseDir, file).lastModified() > | if (new File(baseDir, file).lastModified() > | ||||
cabFile.lastModified()) { | |||||
cabFile.lastModified()) { | |||||
upToDate = false; | upToDate = false; | ||||
} | } | ||||
} | } | ||||
@@ -212,7 +215,7 @@ public class Cab extends MatchingTask { | |||||
* to be included in the cab, one file per line. | * to be included in the cab, one file per line. | ||||
*/ | */ | ||||
protected File createListFile(Vector files) | protected File createListFile(Vector files) | ||||
throws IOException { | |||||
throws IOException { | |||||
File listFile = fileUtils.createTempFile("ant", "", null); | File listFile = fileUtils.createTempFile("ant", "", null); | ||||
PrintWriter writer = new PrintWriter(new FileOutputStream(listFile)); | PrintWriter writer = new PrintWriter(new FileOutputStream(listFile)); | ||||
@@ -286,11 +289,45 @@ public class Cab extends MatchingTask { | |||||
sb.append("\n").append(cabFile.getAbsolutePath()).append("\n"); | sb.append("\n").append(cabFile.getAbsolutePath()).append("\n"); | ||||
try { | try { | ||||
Process p = Runtime.getRuntime().exec("listcab"); | |||||
Process p = Execute.launch(getProject(), | |||||
new String[] {"listcab"}, null, | |||||
baseDir, true); | |||||
OutputStream out = p.getOutputStream(); | OutputStream out = p.getOutputStream(); | ||||
out.write(sb.toString().getBytes()); | out.write(sb.toString().getBytes()); | ||||
out.flush(); | out.flush(); | ||||
out.close(); | 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) { | } catch (IOException ex) { | ||||
String msg = "Problem creating " + cabFile + " " + ex.getMessage(); | String msg = "Problem creating " + cabFile + " " + ex.getMessage(); | ||||
throw new BuildException(msg); | throw new BuildException(msg); | ||||