(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; | |||
| } | |||
| /** | |||
| * 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()); | |||
| @@ -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(); | |||
| } | |||
| } | |||
| } | |||
| @@ -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); | |||