package org.rubypeople.rdt.internal.launching;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.model.IProcess;
import org.rubypeople.rdt.core.SocketUtil;
import org.rubypeople.rdt.internal.debug.core.RubyDebuggerProxy;
import org.rubypeople.rdt.internal.debug.core.model.RubyDebugTarget;
import org.rubypeople.rdt.internal.debug.core.model.RubyProcessingException;
import org.rubypeople.rdt.launching.IRubyLaunchConfigurationConstants;
import org.rubypeople.rdt.launching.IVMRunner;
import org.rubypeople.rdt.launching.VMRunnerConfiguration;
public class JRubyDebugVMDebugger extends JRubyVMRunner implements IVMRunner {
private static final String PORT_SWITCH = "--port";
private static final String VERBOSE_FLAG = "-d";
private static final String RDEBUG_EXECUTABLE = "rdebug-ide";
/*
* (non-Javadoc)
*
* @see org.eclipse.jdt.launching.IVMRunner#run(org.eclipse.jdt.launching.VMRunnerConfiguration,
* org.eclipse.debug.core.ILaunch,
* org.eclipse.core.runtime.IProgressMonitor)
*/
public void run(VMRunnerConfiguration config, ILaunch launch, IProgressMonitor monitor) throws CoreException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
IProgressMonitor subMonitor = new SubProgressMonitor(monitor, 1);
subMonitor.beginTask(LaunchingMessages.StandardVMDebugger_Launching_VM____1, 4);
subMonitor.subTask(LaunchingMessages.StandardVMDebugger_Finding_free_socket____2);
int port = SocketUtil.findFreePort();
if (port == -1) {
abort(LaunchingMessages.StandardVMDebugger_Could_not_find_a_free_socket_for_the_debugger_1, null, IRubyLaunchConfigurationConstants.ERR_NO_SOCKET_AVAILABLE);
}
subMonitor.worked(1);
// check for cancellation
if (monitor.isCanceled()) {
return;
}
subMonitor.subTask(LaunchingMessages.StandardVMDebugger_Constructing_command_line____3);
RubyDebugTarget debugTarget = new RubyDebugTarget(launch, port);
List<String> arguments = constructProgramString(config, monitor);
arguments.addAll(debugSpecificVMArgs(debugTarget));
// VM args are the first thing after the ruby program so that users can
// specify
// options like '-client' & '-server' which are required to be the first
// options
String[] allVMArgs = combineVmArgs(config, fVMInstance);
addArguments(allVMArgs, arguments);
String[] cp = config.getLoadPath();
if (cp.length > 0) {
arguments.addAll(convertLoadPath(config, cp));
}
arguments.addAll(debugArgs(debugTarget));
arguments.add(StandardVMRunner.END_OF_OPTIONS_DELIMITER);
arguments.add(getFileToLaunch(config));
addArguments(config.getProgramArguments(), arguments);
String[] cmdLine = new String[arguments.size()];
arguments.toArray(cmdLine);
String[] envp = getEnvironment(config);
// check for cancellation
if (monitor.isCanceled()) {
return;
}
subMonitor.worked(1);
subMonitor.subTask(LaunchingMessages.StandardVMDebugger_Starting_virtual_machine____4);
Process p = null;
// check for cancellation
if (monitor.isCanceled()) {
return;
}
File workingDir = getWorkingDir(config);
p = exec(cmdLine, workingDir, envp);
if (p == null) {
return;
}
// check for cancellation
if (monitor.isCanceled()) {
p.destroy();
return;
}
IProcess process = newProcess(launch, p, renderProcessLabel(cmdLine), getDefaultProcessMap());
String commandLine = renderCommandLine(cmdLine);
LaunchingPlugin.debug("Starting: " + commandLine) ;
process.setAttribute(IProcess.ATTR_CMDLINE, commandLine);
subMonitor.worked(1);
subMonitor.subTask(LaunchingMessages.StandardVMDebugger_Establishing_debug_connection____5);
debugTarget.setProcess(process);
RubyDebuggerProxy proxy = getDebugProxy(debugTarget);
try {
proxy.start();
launch.addDebugTarget(debugTarget);
} catch (IOException iox) {
LaunchingPlugin.log(new Status(IStatus.ERROR, LaunchingPlugin.PLUGIN_ID, IStatus.ERROR, LaunchingMessages.RdtLaunchingPlugin_processTerminatedBecauseNoDebuggerConnection, null));
debugTarget.terminate();
} catch (RubyProcessingException e) {
abort(LaunchingMessages.StandardVMDebugger_Couldn__t_connect_to_VM_5, e, IRubyLaunchConfigurationConstants.ERR_CONNECTION_FAILED);
debugTarget.terminate();
}
}
protected List<String> debugSpecificVMArgs(RubyDebugTarget debugTarget) {
List<String> arguments = new ArrayList<String>();
arguments.add("--debug");
return arguments;
}
protected List<String> debugArgs(RubyDebugTarget debugTarget) {
List<String> arguments = new ArrayList<String>();
String rdebug = RDebugVMDebugger.findRDebugExecutable(fVMInstance.getInstallLocation());
arguments.add(rdebug);
arguments.add(PORT_SWITCH);
arguments.add(Integer.toString(debugTarget.getPort()));
if (isDebuggerVerbose()) {
arguments.add(VERBOSE_FLAG);
}
return arguments;
}
protected static boolean isDebuggerVerbose() {
return LaunchingPlugin.getDefault().getPluginPreferences().getBoolean(PreferenceConstants.VERBOSE_DEBUGGER);
}
protected RubyDebuggerProxy getDebugProxy(RubyDebugTarget debugTarget) {
return new RubyDebuggerProxy(debugTarget, true);
}
}