@@ -12,11 +12,8 @@ import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Locale;
import java.util.Vector;
import org.apache.avalon.excalibur.io.FileUtil;
import org.apache.myrmidon.api.TaskException;
import org.apache.myrmidon.framework.Os;
import org.apache.tools.ant.Project;
@@ -35,29 +32,29 @@ public class Execute
*/
public final static int INVALID = Integer.MAX_VALUE;
private static String antWorkingDirectory = System.getProperty( "user.dir" );
private static CommandLauncher vmLauncher;
private static CommandLauncher shellLauncher;
private static Vector procEnvironment;
private static String c_ antWorkingDirectory = System.getProperty( "user.dir" );
private static CommandLauncher c_ vmLauncher;
private static CommandLauncher c_ shellLauncher;
private static Vector c_ procEnvironment;
/**
* Used to destroy processes when the VM exits.
*/
private static ProcessDestroyer processDestroyer = new ProcessDestroyer();
private static ProcessDestroyer c_ processDestroyer = new ProcessDestroyer();
private String[] cmdl = null ;
private String[] env = null ;
private int exitValue = INVALID;
private File workingDirectory = null ;
private Project project = null ;
private boolean newEnvironment = false ;
private String[] m_command ;
private String[] m_environment ;
private int m_ exitValue = INVALID;
private File m_ workingDirectory;
private Project m_ project;
private boolean m_ newEnvironment;
/**
* Controls whether the VM is used to launch commands, where possible
*/
private boolean useVMLauncher = true;
private ExecuteStreamHandler streamHandler;
private ExecuteWatchdog watchdog;
private boolean m_ useVMLauncher = true;
private ExecuteStreamHandler m_ streamHandler;
private ExecuteWatchdog m_ watchdog;
/**
* Builds a command launcher for the OS and JVM we are running under
@@ -70,7 +67,7 @@ public class Execute
// Try using a JDK 1.3 launcher
try
{
vmLauncher = new Java13CommandLauncher();
c_ vmLauncher = new Java13CommandLauncher();
}
catch( NoSuchMethodException exc )
{
@@ -80,12 +77,12 @@ public class Execute
if( Os.isFamily( "mac" ) )
{
// Mac
shellLauncher = new MacCommandLauncher( new CommandLauncher() );
c_ shellLauncher = new MacCommandLauncher( new CommandLauncher() );
}
else if( Os.isFamily( "os/2" ) )
{
// OS/2 - use same mechanism as Windows 2000
shellLauncher = new WinNTCommandLauncher( new CommandLauncher() );
c_ shellLauncher = new WinNTCommandLauncher( new CommandLauncher() );
}
else if( Os.isFamily( "windows" ) )
{
@@ -110,15 +107,15 @@ public class Execute
if( osname.indexOf( "nt" ) >= 0 || osname.indexOf( "2000" ) >= 0 )
{
// Windows 2000/NT
shellLauncher = new WinNTCommandLauncher( baseLauncher );
c_ shellLauncher = new WinNTCommandLauncher( baseLauncher );
}
else
{
// Windows 98/95 - need to use an auxiliary script
shellLauncher = new ScriptCommandLauncher( "bin/antRun.bat", baseLauncher );
c_ shellLauncher = new ScriptCommandLauncher( "bin/antRun.bat", baseLauncher );
}
}
else if( ( new Os( "netware" ) ).eval() )
else if( (new Os( "netware" )).eval() )
{
// NetWare. Need to determine which JDK we're running in
CommandLauncher baseLauncher;
@@ -133,12 +130,12 @@ public class Execute
baseLauncher = new CommandLauncher();
}
shellLauncher = new PerlScriptCommandLauncher( "bin/antRun.pl", baseLauncher );
c_ shellLauncher = new PerlScriptCommandLauncher( "bin/antRun.pl", baseLauncher );
}
else
{
// Generic
shellLauncher = new ScriptCommandLauncher( "bin/antRun", new CommandLauncher() );
c_ shellLauncher = new ScriptCommandLauncher( "bin/antRun", new CommandLauncher() );
}
}
catch( TaskException e )
@@ -177,8 +174,8 @@ public class Execute
*/
public Execute( ExecuteStreamHandler streamHandler, ExecuteWatchdog watchdog )
{
this.streamHandler = streamHandler;
this.watchdog = watchdog;
this.m_ streamHandler = streamHandler;
this.m_ watchdog = watchdog;
}
/**
@@ -189,10 +186,10 @@ public class Execute
public static synchronized Vector getProcEnvironment()
throws TaskException
{
if( procEnvironment != null )
return procEnvironment;
if( c_ procEnvironment != null )
return c_ procEnvironment;
procEnvironment = new Vector();
c_ procEnvironment = new Vector();
try
{
ByteArrayOutputStream out = new ByteArrayOutputStream();
@@ -211,7 +208,7 @@ public class Execute
String var = null;
String line;
String lineSep = System.getProperty( "line.separator" );
while( ( line = in.readLine() ) != null )
while( (line = in.readLine()) != null )
{
if( line.indexOf( '=' ) == -1 )
{
@@ -231,20 +228,20 @@ public class Execute
// New env var...append the previous one if we have it.
if( var != null )
{
procEnvironment.addElement( var );
c_ procEnvironment.addElement( var );
}
var = line;
}
}
// Since we "look ahead" before adding, there's one last env var.
procEnvironment.addElement( var );
c_ procEnvironment.addElement( var );
}
catch( IOException exc )
{
exc.printStackTrace();
// Just try to see how much we got
}
return procEnvironment;
return c_ procEnvironment;
}
/**
@@ -335,7 +332,7 @@ public class Execute
public void setAntRun( Project project )
throws TaskException
{
this.project = project;
this.m_ project = project;
}
/**
@@ -345,7 +342,7 @@ public class Execute
*/
public void setCommandline( String[] commandline )
{
cmdl = commandline;
m_ com man d = commandline;
}
/**
@@ -355,7 +352,7 @@ public class Execute
*/
public void setEnvironment( String[] env )
{
this.env = env;
this.m_ environment = env;
}
/**
@@ -365,7 +362,7 @@ public class Execute
*/
public void setNewenvironment( boolean newenv )
{
newEnvironment = newenv;
m_ newEnvironment = newenv;
}
/**
@@ -378,7 +375,7 @@ public class Execute
*/
public void setVMLauncher( boolean useVMLauncher )
{
this.useVMLauncher = useVMLauncher;
this.m_ useVMLauncher = useVMLauncher;
}
/**
@@ -392,10 +389,10 @@ public class Execute
*/
public void setWorkingDirectory( File wd )
{
if( wd == null || wd.getAbsolutePath().equals( antWorkingDirectory ) )
workingDirectory = null;
if( wd == null || wd.getAbsolutePath().equals( c_ antWorkingDirectory ) )
m_ workingDirectory = null;
else
workingDirectory = wd;
m_ workingDirectory = wd;
}
/**
@@ -405,7 +402,7 @@ public class Execute
*/
public String[] getCommandline()
{
return cmdl ;
return m_ com man d;
}
/**
@@ -416,8 +413,8 @@ public class Execute
public String[] getEnvironment()
throws TaskException
{
if( env == null || newEnvironment )
return env;
if( m_ environment == null || m_ newEnvironment )
return m_ environment ;
return patchEnvironment();
}
@@ -429,7 +426,7 @@ public class Execute
*/
public int getExitValue()
{
return exitValue;
return m_ exitValue;
}
/**
@@ -441,43 +438,43 @@ public class Execute
public int execute()
throws IOException, TaskException
{
CommandLauncher launcher = vmLauncher != null ? vmLauncher : shellLauncher;
if( !useVMLauncher )
CommandLauncher launcher = c_ vmLauncher != null ? c_ vmLauncher : c_ shellLauncher;
if( !m_ useVMLauncher )
{
launcher = shellLauncher;
launcher = c_ shellLauncher;
}
final Process process = launcher.exec( project, getCommandline(), getEnvironment(), workingDirectory );
final Process process = launcher.exec( m_ project, getCommandline(), getEnvironment(), m_ workingDirectory );
try
{
streamHandler.setProcessInputStream( process.getOutputStream() );
streamHandler.setProcessOutputStream( process.getInputStream() );
streamHandler.setProcessErrorStream( process.getErrorStream() );
m_ streamHandler.setProcessInputStream( process.getOutputStream() );
m_ streamHandler.setProcessOutputStream( process.getInputStream() );
m_ streamHandler.setProcessErrorStream( process.getErrorStream() );
}
catch( IOException e )
{
process.destroy();
throw e;
}
streamHandler.start();
m_ streamHandler.start();
// add the process to the list of those to destroy if the VM exits
//
processDestroyer.add( process );
c_ processDestroyer.add( process );
if( watchdog != null )
watchdog.start( process );
if( m_ watchdog != null )
m_ watchdog.start( process );
waitFor( process );
// remove the process to the list of those to destroy if the VM exits
//
processDestroyer.remove( process );
c_ processDestroyer.remove( process );
if( watchdog != null )
watchdog.stop();
streamHandler.stop();
if( watchdog != null )
watchdog.checkException();
if( m_ watchdog != null )
m_ watchdog.stop();
m_ streamHandler.stop();
if( m_ watchdog != null )
m_ watchdog.checkException();
return getExitValue();
}
@@ -489,12 +486,12 @@ public class Execute
*/
public boolean killedProcess()
{
return watchdog != null && watchdog.killedProcess();
return m_ watchdog != null && m_ watchdog.killedProcess();
}
protected void setExitValue( int value )
private void setExitValue( final int value )
{
exitValue = value;
m_ exitValue = value;
}
protected void waitFor( Process process )
@@ -518,443 +515,25 @@ public class Execute
throws TaskException
{
Vector osEnv = (Vector)getProcEnvironment().clone();
for( int i = 0; i < env.length; i++ )
for( int i = 0; i < m_ environment .length; i++ )
{
int pos = env[ i ].indexOf( '=' );
int pos = m_ environment [ i ].indexOf( '=' );
// Get key including "="
String key = env[ i ].substring( 0, pos + 1 );
String key = m_ environment [ i ].substring( 0, pos + 1 );
int size = osEnv.size();
for( int j = 0; j < size; j++ )
{
if( ( (String)osEnv.elementAt( j ) ).startsWith( key ) )
if( ((String)osEnv.elementAt( j )).startsWith( key ) )
{
osEnv.removeElementAt( j );
break;
}
}
osEnv.addElement( env[ i ] );
osEnv.addElement( m_ environment [ i ] );
}
String[] result = new String[ osEnv.size() ];
osEnv.copyInto( result );
return result;
}
/**
* A command launcher for a particular JVM/OS platform. This class is a
* general purpose command launcher which can only launch commands in the
* current working directory.
*
* @author RT
*/
private static class CommandLauncher
{
/**
* Launches the given command in a new process.
*
* @param project The project that the command is part of
* @param cmd The command to execute
* @param env The environment for the new process. If null, the
* environment of the current proccess is used.
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env )
throws IOException, TaskException
{
if( project != null )
{
project.log( "Execute:CommandLauncher: " +
Commandline.toString( cmd ), Project.MSG_DEBUG );
}
return Runtime.getRuntime().exec( cmd, env );
}
/**
* Launches the given command in a new process, in the given working
* directory.
*
* @param project The project that the command is part of
* @param cmd The command to execute
* @param env The environment for the new process. If null, the
* environment of the current proccess is used.
* @param workingDir The directory to start the command in. If null, the
* current directory is used
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env, File workingDir )
throws IOException, TaskException
{
if( workingDir == null )
{
return exec( project, cmd, env );
}
throw new IOException( "Cannot execute a process in different directory under this JVM" );
}
}
/**
* A command launcher that proxies another command launcher. Sub-classes
* override exec(args, env, workdir)
*
* @author RT
*/
private static class CommandLauncherProxy extends CommandLauncher
{
private CommandLauncher _launcher;
CommandLauncherProxy( CommandLauncher launcher )
{
_launcher = launcher;
}
/**
* Launches the given command in a new process. Delegates this method to
* the proxied launcher
*
* @param project Description of Parameter
* @param cmd Description of Parameter
* @param env Description of Parameter
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env )
throws IOException, TaskException
{
return _launcher.exec( project, cmd, env );
}
}
/**
* A command launcher for JDK/JRE 1.1 under Windows. Fixes quoting problems
* in Runtime.exec(). Can only launch commands in the current working
* directory
*
* @author RT
*/
private static class Java11CommandLauncher extends CommandLauncher
{
/**
* Launches the given command in a new process. Needs to quote arguments
*
* @param project Description of Parameter
* @param cmd Description of Parameter
* @param env Description of Parameter
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env )
throws IOException, TaskException
{
// Need to quote arguments with spaces, and to escape quote characters
String[] newcmd = new String[ cmd.length ];
for( int i = 0; i < cmd.length; i++ )
{
newcmd[ i ] = Commandline.quoteArgument( cmd[ i ] );
}
if( project != null )
{
project.log( "Execute:Java11CommandLauncher: " +
Commandline.toString( newcmd ), Project.MSG_DEBUG );
}
return Runtime.getRuntime().exec( newcmd, env );
}
}
/**
* A command launcher for JDK/JRE 1.3 (and higher). Uses the built-in
* Runtime.exec() command
*
* @author RT
*/
private static class Java13CommandLauncher extends CommandLauncher
{
private Method _execWithCWD;
public Java13CommandLauncher()
throws NoSuchMethodException
{
// Locate method Runtime.exec(String[] cmdarray, String[] envp, File dir)
_execWithCWD = Runtime.class.getMethod( "exec", new Class[]{String[].class, String[].class, File.class} );
}
/**
* Launches the given command in a new process, in the given working
* directory
*
* @param project Description of Parameter
* @param cmd Description of Parameter
* @param env Description of Parameter
* @param workingDir Description of Parameter
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env, File workingDir )
throws IOException, TaskException
{
try
{
if( project != null )
{
project.log( "Execute:Java13CommandLauncher: " +
Commandline.toString( cmd ), Project.MSG_DEBUG );
}
Object[] arguments = {cmd, env, workingDir};
return (Process)_execWithCWD.invoke( Runtime.getRuntime(), arguments );
}
catch( InvocationTargetException exc )
{
Throwable realexc = exc.getTargetException();
if( realexc instanceof ThreadDeath )
{
throw (ThreadDeath)realexc;
}
else if( realexc instanceof IOException )
{
throw (IOException)realexc;
}
else
{
throw new TaskException( "Unable to execute command", realexc );
}
}
catch( Exception exc )
{
// IllegalAccess, IllegalArgument, ClassCast
throw new TaskException( "Unable to execute command", exc );
}
}
}
/**
* A command launcher for Mac that uses a dodgy mechanism to change working
* directory before launching commands.
*
* @author RT
*/
private static class MacCommandLauncher extends CommandLauncherProxy
{
MacCommandLauncher( CommandLauncher launcher )
{
super( launcher );
}
/**
* Launches the given command in a new process, in the given working
* directory
*
* @param project Description of Parameter
* @param cmd Description of Parameter
* @param env Description of Parameter
* @param workingDir Description of Parameter
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env, File workingDir )
throws IOException, TaskException
{
if( workingDir == null )
{
return exec( project, cmd, env );
}
System.getProperties().put( "user.dir", workingDir.getAbsolutePath() );
try
{
return exec( project, cmd, env );
}
finally
{
System.getProperties().put( "user.dir", antWorkingDirectory );
}
}
}
/**
* A command launcher that uses an auxiliary perl script to launch commands
* in directories other than the current working directory.
*
* @author RT
*/
private static class PerlScriptCommandLauncher extends CommandLauncherProxy
{
private String _script;
PerlScriptCommandLauncher( String script, CommandLauncher launcher )
{
super( launcher );
_script = script;
}
/**
* Launches the given command in a new process, in the given working
* directory
*
* @param project Description of Parameter
* @param cmd Description of Parameter
* @param env Description of Parameter
* @param workingDir Description of Parameter
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env, File workingDir )
throws IOException, TaskException
{
if( project == null )
{
if( workingDir == null )
{
return exec( project, cmd, env );
}
throw new IOException( "Cannot locate antRun script: No project provided" );
}
// Locate the auxiliary script
String antHome = project.getProperty( "ant.home" );
if( antHome == null )
{
throw new IOException( "Cannot locate antRun script: Property 'ant.home' not found" );
}
String antRun = FileUtil.
resolveFile( project.getBaseDir(), antHome + File.separator + _script ).toString();
// Build the command
File commandDir = workingDir;
if( workingDir == null && project != null )
{
commandDir = project.getBaseDir();
}
String[] newcmd = new String[ cmd.length + 3 ];
newcmd[ 0 ] = "perl";
newcmd[ 1 ] = antRun;
newcmd[ 2 ] = commandDir.getAbsolutePath();
System.arraycopy( cmd, 0, newcmd, 3, cmd.length );
return exec( project, newcmd, env );
}
}
/**
* A command launcher that uses an auxiliary script to launch commands in
* directories other than the current working directory.
*
* @author RT
*/
private static class ScriptCommandLauncher extends CommandLauncherProxy
{
private String _script;
ScriptCommandLauncher( String script, CommandLauncher launcher )
{
super( launcher );
_script = script;
}
/**
* Launches the given command in a new process, in the given working
* directory
*
* @param project Description of Parameter
* @param cmd Description of Parameter
* @param env Description of Parameter
* @param workingDir Description of Parameter
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env, File workingDir )
throws IOException, TaskException
{
if( project == null )
{
if( workingDir == null )
{
return exec( project, cmd, env );
}
throw new IOException( "Cannot locate antRun script: No project provided" );
}
// Locate the auxiliary script
String antHome = project.getProperty( "ant.home" );
if( antHome == null )
{
throw new IOException( "Cannot locate antRun script: Property 'ant.home' not found" );
}
String antRun = FileUtil.
resolveFile( project.getBaseDir(), antHome + File.separator + _script ).toString();
// Build the command
File commandDir = workingDir;
if( workingDir == null && project != null )
{
commandDir = project.getBaseDir();
}
String[] newcmd = new String[ cmd.length + 2 ];
newcmd[ 0 ] = antRun;
newcmd[ 1 ] = commandDir.getAbsolutePath();
System.arraycopy( cmd, 0, newcmd, 2, cmd.length );
return exec( project, newcmd, env );
}
}
/**
* A command launcher for Windows 2000/NT that uses 'cmd.exe' when launching
* commands in directories other than the current working directory.
*
* @author RT
*/
private static class WinNTCommandLauncher extends CommandLauncherProxy
{
WinNTCommandLauncher( CommandLauncher launcher )
{
super( launcher );
}
/**
* Launches the given command in a new process, in the given working
* directory.
*
* @param project Description of Parameter
* @param cmd Description of Parameter
* @param env Description of Parameter
* @param workingDir Description of Parameter
* @return Description of the Returned Value
* @exception IOException Description of Exception
*/
public Process exec( Project project, String[] cmd, String[] env, File workingDir )
throws IOException, TaskException
{
File commandDir = workingDir;
if( workingDir == null )
{
if( project != null )
{
commandDir = project.getBaseDir();
}
else
{
return exec( project, cmd, env );
}
}
// Use cmd.exe to change to the specified directory before running
// the command
final int preCmdLength = 6;
String[] newcmd = new String[ cmd.length + preCmdLength ];
newcmd[ 0 ] = "cmd";
newcmd[ 1 ] = "/c";
newcmd[ 2 ] = "cd";
newcmd[ 3 ] = "/d";
newcmd[ 4 ] = commandDir.getAbsolutePath();
newcmd[ 5 ] = "&&";
System.arraycopy( cmd, 0, newcmd, preCmdLength, cmd.length );
return exec( project, newcmd, env );
}
}
}