/** * Copyright (c) 2005-2013 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.List; import org.eclipse.core.runtime.CoreException; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; 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.IDebugTarget; 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.core.log.Log; 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.InteractiveConsoleUMDPrefs; 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.shared_core.net.SocketUtil; import org.python.pydev.shared_core.structure.Tuple; import org.python.pydev.ui.pythonpathconf.AbstractInterpreterPreferencesPage; /** * 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; public final String[] cmdLine; public final String[] env; public final String encoding; /** * @param launch * @param process * @param clientPort * @param interpreter * @param frame * @param env * @param cmdLine */ public PydevConsoleLaunchInfo(Launch launch, Process process, int clientPort, IInterpreterInfo interpreter, PyStackFrame frame, String[] cmdLine, String[] env, String encoding) { this.launch = launch; this.process = process; this.clientPort = clientPort; this.interpreter = interpreter; this.frame = frame; this.cmdLine = cmdLine; this.env = env; this.encoding = encoding; } } 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) { PyStackFrame selectedFrame = dialog.getSelectedFrame(); if (selectedFrame != null) { // Interpreter not required for Debug Console String encoding = getEncodingFromFrame(selectedFrame); return new PydevConsoleLaunchInfo(null, null, 0, null, selectedFrame, new String[] { "Debug connection (no command line)" }, null, encoding); } 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 = 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; } public static String getEncodingFromFrame(PyStackFrame selectedFrame) { try { IDebugTarget adapter = (IDebugTarget) selectedFrame.getAdapter(IDebugTarget.class); if (adapter == null) { return "UTF-8"; } IProcess process = adapter.getProcess(); if (process == null) { return "UTF-8"; } ILaunch launch = process.getLaunch(); if (launch == null) { Log.log("Unable to get launch for: " + process); return "UTF-8"; } return getEncodingFromLaunch(launch); } catch (Exception e) { Log.log(e); return "UTF-8"; } } public static String getEncodingFromLaunch(ILaunch launch) { try { String encoding = launch.getAttribute(DebugPlugin.ATTR_CONSOLE_ENCODING); if (encoding == null) { Log.log("Unable to get: " + DebugPlugin.ATTR_CONSOLE_ENCODING + " from launch."); return "UTF-8"; } return encoding; } catch (Exception e) { Log.log(e); return "UTF-8"; } } 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"); String pythonpathEnv = SimpleRunner.makePythonPathEnvFromPaths(pythonpath); 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 IronPython related."); } String[] cmdLine; String[] env; String encoding = PydevDebugPlugin.getDefault().getPreferenceStore() .getString(PydevConsoleConstants.INTERACTIVE_CONSOLE_ENCODING); if (encoding.trim().length() == 0) { encoding = "UTF-8"; //Default is utf-8 } if (interpreterManager.getInterpreterType() == IInterpreterManager.INTERPRETER_TYPE_JYTHON_ECLIPSE) { process = new JythonEclipseProcess(scriptWithinPySrc.getAbsolutePath(), port, clientPort); cmdLine = new String[] { "Internal Jython process (no command line)" }; env = null; } else { env = SimpleRunner.createEnvWithPythonpath(pythonpathEnv, interpreter.getExecutableOrJar(), interpreterManager, nature); // Add in UMD settings String[] s = new String[env.length + 4]; System.arraycopy(env, 0, s, 0, env.length); s[s.length - 4] = "PYTHONIOENCODING=" + encoding; s[s.length - 3] = "PYDEV_UMD_ENABLED=" + Boolean.toString(InteractiveConsoleUMDPrefs.isUMDEnabled()); s[s.length - 2] = "PYDEV_UMD_NAMELIST=" + InteractiveConsoleUMDPrefs.getUMDExcludeModules(); s[s.length - 1] = "PYDEV_UMD_VERBOSE=" + Boolean.toString(InteractiveConsoleUMDPrefs.isUMDVerbose()); env = s; cmdLine = commandLine; process = SimpleRunner.createProcess(commandLine, env, null); } IProcess newProcess = new PydevSpawnedInterpreterProcess(launch, process, interpreter.getNameForUI(), encoding); launch.addProcess(newProcess); return new PydevConsoleLaunchInfo(launch, process, clientPort, interpreter, null, cmdLine, env, encoding); } }