/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
/*
* Created on Mar 20, 2006
*/
package org.python.pydev.debug.newconsole.env;
import java.io.File;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.DebugPlugin;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationType;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.Launch;
import org.eclipse.debug.core.model.IProcess;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ListDialog;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.python.pydev.core.IInterpreterInfo;
import org.python.pydev.core.IInterpreterManager;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.debug.core.PydevDebugPlugin;
import org.python.pydev.debug.model.PyStackFrame;
import org.python.pydev.debug.newconsole.PydevConsoleConstants;
import org.python.pydev.debug.newconsole.prefs.InteractiveConsolePrefs;
import org.python.pydev.editor.PyEdit;
import org.python.pydev.plugin.PydevPlugin;
import org.python.pydev.runners.SimpleIronpythonRunner;
import org.python.pydev.runners.SimpleJythonRunner;
import org.python.pydev.runners.SimplePythonRunner;
import org.python.pydev.runners.SimpleRunner;
import org.python.pydev.ui.pythonpathconf.AbstractInterpreterPreferencesPage;
import com.aptana.shared_core.net.SocketUtil;
import com.aptana.shared_core.structure.Tuple;
/**
* This class is used to create the given IProcess and get the console that is attached to that process.
*/
public class PydevIProcessFactory {
public static final class PydevConsoleLaunchInfo {
public final Launch launch;
public final Process process;
public final int clientPort;
public final IInterpreterInfo interpreter;
public final PyStackFrame frame;
/**
* @param launch
* @param process
* @param clientPort
* @param interpreter
* @param frame
*/
public PydevConsoleLaunchInfo(Launch launch, Process process, int clientPort, IInterpreterInfo interpreter,
PyStackFrame frame) {
this.launch = launch;
this.process = process;
this.clientPort = clientPort;
this.interpreter = interpreter;
this.frame = frame;
}
}
private List<IPythonNature> naturesUsed;
public List<IPythonNature> getNaturesUsed() {
return naturesUsed;
}
/**
* @return a shell that we can use.
*/
public Shell getShell() {
return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
}
public static final String INTERACTIVE_LAUNCH_PORT = "INTERACTIVE_LAUNCH_PORT";
/**
* Creates a launch (and its associated IProcess) for the xml-rpc server to be used in the interactive console.
*
* It'll ask the user how to create it:
* - editor
* - python interpreter
* - jython interpreter
*
* @return the Launch, the Process created and the port that'll be used for the server to call back into
* this client for requesting input.
*
* @throws UserCanceledException
* @throws Exception
*/
public PydevConsoleLaunchInfo createInteractiveLaunch() throws UserCanceledException, Exception {
IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
IWorkbenchPage activePage = workbenchWindow.getActivePage();
IEditorPart activeEditor = activePage.getActiveEditor();
PyEdit edit = null;
if (activeEditor instanceof PyEdit) {
edit = (PyEdit) activeEditor;
}
ChooseProcessTypeDialog dialog = new ChooseProcessTypeDialog(getShell(), edit);
if (dialog.open() == ChooseProcessTypeDialog.OK) {
if (dialog.getSelectedFrame() != null) {
// Interpreter not required for Debug Console
return new PydevConsoleLaunchInfo(null, null, 0, null, dialog.getSelectedFrame());
}
IInterpreterManager interpreterManager = dialog.getInterpreterManager();
if (interpreterManager == null) {
MessageDialog.openError(workbenchWindow.getShell(), "No interpreter manager for creating console",
"No interpreter manager was available for creating a console.");
}
IInterpreterInfo[] interpreters = interpreterManager.getInterpreterInfos();
if (interpreters == null || interpreters.length == 0) {
MessageDialog.openError(workbenchWindow.getShell(), "No interpreters for creating console",
"No interpreter available for creating a console.");
return null;
}
IInterpreterInfo interpreter = null;
if (interpreters.length == 1) {
//We just have one, so, no point in asking about which one should be there.
interpreter = interpreters[0];
}
if (interpreter == null) {
SelectionDialog listDialog = AbstractInterpreterPreferencesPage.createChooseIntepreterInfoDialog(
workbenchWindow, interpreters, "Select interpreter to be used.", false);
int open = listDialog.open();
if (open != ListDialog.OK || listDialog.getResult().length > 1) {
return null;
}
Object[] result = (Object[]) listDialog.getResult();
if (result == null || result.length == 0) {
interpreter = interpreters[0];
} else {
interpreter = ((IInterpreterInfo) result[0]);
}
}
if (interpreter == null) {
return null;
}
Tuple<Collection<String>, IPythonNature> pythonpathAndNature = dialog.getPythonpathAndNature(interpreter);
if (pythonpathAndNature == null) {
return null;
}
return createLaunch(interpreterManager, interpreter, pythonpathAndNature.o1, pythonpathAndNature.o2,
dialog.getNatures());
}
return null;
}
private static ILaunchConfiguration createLaunchConfig() {
ILaunchManager manager = DebugPlugin.getDefault().getLaunchManager();
ILaunchConfigurationType launchConfigurationType = manager
.getLaunchConfigurationType("org.python.pydev.debug.interactiveConsoleConfigurationType");
ILaunchConfigurationWorkingCopy newInstance;
try {
newInstance = launchConfigurationType.newInstance(null,
manager.generateLaunchConfigurationName("PyDev Interactive Launch"));
} catch (CoreException e) {
return null;
}
newInstance.setAttribute(IDebugUIConstants.ATTR_PRIVATE, true);
return newInstance;
}
public PydevConsoleLaunchInfo createLaunch(IInterpreterManager interpreterManager, IInterpreterInfo interpreter,
Collection<String> pythonpath, IPythonNature nature, List<IPythonNature> naturesUsed) throws Exception {
Process process = null;
this.naturesUsed = naturesUsed;
Integer[] ports = SocketUtil.findUnusedLocalPorts(2);
int port = ports[0];
int clientPort = ports[1];
final Launch launch = new Launch(createLaunchConfig(), "interactive", null);
launch.setAttribute(DebugPlugin.ATTR_CAPTURE_OUTPUT, "false");
launch.setAttribute(INTERACTIVE_LAUNCH_PORT, "" + port);
File scriptWithinPySrc = PydevPlugin.getScriptWithinPySrc("pydevconsole.py");
Collection<String> extraPath = pythonpath;
if (InteractiveConsolePrefs.getConsoleConnectVariableView()
&& interpreterManager.getInterpreterType() != IInterpreterManager.INTERPRETER_TYPE_JYTHON_ECLIPSE) {
// Add PydevDebugPlugin's pysrc so we can access pydevd
extraPath = new LinkedHashSet<String>();
extraPath.add(PydevDebugPlugin.getPySrcPath().getAbsolutePath()); //Add this one as the first in the PYTHONPATH!
extraPath.addAll(pythonpath);
}
String pythonpathEnv = SimpleRunner.makePythonPathEnvFromPaths(extraPath);
String[] commandLine;
switch (interpreterManager.getInterpreterType()) {
case IInterpreterManager.INTERPRETER_TYPE_PYTHON:
commandLine = SimplePythonRunner.makeExecutableCommandStr(interpreter.getExecutableOrJar(),
scriptWithinPySrc.getAbsolutePath(),
new String[] { String.valueOf(port), String.valueOf(clientPort) });
break;
case IInterpreterManager.INTERPRETER_TYPE_IRONPYTHON:
commandLine = SimpleIronpythonRunner.makeExecutableCommandStr(interpreter.getExecutableOrJar(),
scriptWithinPySrc.getAbsolutePath(),
new String[] { String.valueOf(port), String.valueOf(clientPort) });
break;
case IInterpreterManager.INTERPRETER_TYPE_JYTHON:
String vmArgs = PydevDebugPlugin.getDefault().getPreferenceStore()
.getString(PydevConsoleConstants.INTERACTIVE_CONSOLE_VM_ARGS);
commandLine = SimpleJythonRunner.makeExecutableCommandStrWithVMArgs(interpreter.getExecutableOrJar(),
scriptWithinPySrc.getAbsolutePath(), pythonpathEnv, vmArgs, new String[] {
String.valueOf(port), String.valueOf(clientPort) });
break;
case IInterpreterManager.INTERPRETER_TYPE_JYTHON_ECLIPSE:
commandLine = null;
break;
default:
throw new RuntimeException(
"Expected interpreter manager to be python or jython or iron python related.");
}
if (interpreterManager.getInterpreterType() == IInterpreterManager.INTERPRETER_TYPE_JYTHON_ECLIPSE) {
process = new JythonEclipseProcess(scriptWithinPySrc.getAbsolutePath(), port, clientPort);
} else {
String[] env = SimpleRunner.createEnvWithPythonpath(pythonpathEnv, interpreter.getExecutableOrJar(),
interpreterManager, nature);
process = SimpleRunner.createProcess(commandLine, env, null);
}
IProcess newProcess = new PydevSpawnedInterpreterProcess(launch, process, interpreter.getNameForUI(), null);
launch.addProcess(newProcess);
return new PydevConsoleLaunchInfo(launch, process, clientPort, interpreter, null);
}
}