com.jetbrains.python.run.PythonCommandLineState Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of python-community Show documentation
Show all versions of python-community Show documentation
A packaging of the IntelliJ Community Edition python-community library.
This is release number 1 of trunk branch 142.
The newest version!
/*
* Copyright 2000-2014 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jetbrains.python.run;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.intellij.execution.DefaultExecutionResult;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.ExecutionResult;
import com.intellij.execution.Executor;
import com.intellij.execution.configurations.*;
import com.intellij.execution.filters.TextConsoleBuilder;
import com.intellij.execution.filters.TextConsoleBuilderFactory;
import com.intellij.execution.filters.UrlFilter;
import com.intellij.execution.process.ProcessHandler;
import com.intellij.execution.process.ProcessTerminatedListener;
import com.intellij.execution.runners.ExecutionEnvironment;
import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.facet.Facet;
import com.intellij.facet.FacetManager;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkAdditionalData;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.roots.impl.libraries.LibraryImpl;
import com.intellij.openapi.roots.libraries.Library;
import com.intellij.openapi.roots.libraries.PersistentLibraryKind;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.vfs.JarFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.encoding.EncodingProjectManager;
import com.intellij.remote.RemoteProcessHandlerBase;
import com.intellij.util.PlatformUtils;
import com.intellij.util.containers.HashMap;
import com.jetbrains.python.PythonHelpersLocator;
import com.jetbrains.python.console.PyDebugConsoleBuilder;
import com.jetbrains.python.debugger.PyDebugRunner;
import com.jetbrains.python.debugger.PyDebuggerOptionsProvider;
import com.jetbrains.python.facet.LibraryContributingFacet;
import com.jetbrains.python.facet.PythonPathContributingFacet;
import com.jetbrains.python.library.PythonLibraryType;
import com.jetbrains.python.sdk.PySdkUtil;
import com.jetbrains.python.sdk.PythonEnvUtil;
import com.jetbrains.python.sdk.PythonSdkAdditionalData;
import com.jetbrains.python.sdk.PythonSdkType;
import com.jetbrains.python.sdk.flavors.JythonSdkFlavor;
import com.jetbrains.python.sdk.flavors.PythonSdkFlavor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.IOException;
import java.net.ServerSocket;
import java.util.*;
/**
* @author Leonid Shalupov
*/
public abstract class PythonCommandLineState extends CommandLineState {
// command line has a number of fixed groups of parameters; patchers should only operate on them and not the raw list.
public static final String GROUP_EXE_OPTIONS = "Exe Options";
public static final String GROUP_DEBUGGER = "Debugger";
public static final String GROUP_PROFILER = "Profiler";
public static final String GROUP_SCRIPT = "Script";
private final AbstractPythonRunConfiguration myConfig;
private Boolean myMultiprocessDebug = null;
public boolean isDebug() {
return PyDebugRunner.PY_DEBUG_RUNNER.equals(getEnvironment().getRunner().getRunnerId());
}
public static ServerSocket createServerSocket() throws ExecutionException {
final ServerSocket serverSocket;
try {
//noinspection SocketOpenedButNotSafelyClosed
serverSocket = new ServerSocket(0);
}
catch (IOException e) {
throw new ExecutionException("Failed to find free socket port", e);
}
return serverSocket;
}
public PythonCommandLineState(AbstractPythonRunConfiguration runConfiguration, ExecutionEnvironment env) {
super(env);
myConfig = runConfiguration;
}
@Nullable
public PythonSdkFlavor getSdkFlavor() {
return PythonSdkFlavor.getFlavor(myConfig.getInterpreterPath());
}
public Sdk getSdk() {
return myConfig.getSdk();
}
@NotNull
@Override
public ExecutionResult execute(@NotNull Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
return execute(executor, (CommandLinePatcher[])null);
}
public ExecutionResult execute(Executor executor, CommandLinePatcher... patchers) throws ExecutionException {
final ProcessHandler processHandler = startProcess(patchers);
final ConsoleView console = createAndAttachConsole(myConfig.getProject(), processHandler, executor);
List actions = Lists.newArrayList(createActions(console, processHandler));
return new DefaultExecutionResult(console, processHandler, actions.toArray(new AnAction[actions.size()]));
}
@NotNull
protected ConsoleView createAndAttachConsole(Project project, ProcessHandler processHandler, Executor executor)
throws ExecutionException {
final ConsoleView consoleView = createConsoleBuilder(project).getConsole();
consoleView.addMessageFilter(new UrlFilter());
addTracebackFilter(project, consoleView, processHandler);
consoleView.attachToProcess(processHandler);
return consoleView;
}
protected void addTracebackFilter(Project project, ConsoleView consoleView, ProcessHandler processHandler) {
if (PySdkUtil.isRemote(myConfig.getSdk())) {
assert processHandler instanceof RemoteProcessHandlerBase;
consoleView
.addMessageFilter(new PyRemoteTracebackFilter(project, myConfig.getWorkingDirectory(), (RemoteProcessHandlerBase)processHandler));
}
else {
consoleView.addMessageFilter(new PythonTracebackFilter(project, myConfig.getWorkingDirectorySafe()));
}
consoleView.addMessageFilter(new UrlFilter()); // Url filter is always nice to have
}
private TextConsoleBuilder createConsoleBuilder(Project project) {
if (isDebug()) {
return new PyDebugConsoleBuilder(project, PythonSdkType.findSdkByPath(myConfig.getInterpreterPath()));
}
else {
return TextConsoleBuilderFactory.getInstance().createBuilder(project);
}
}
@Override
@NotNull
protected ProcessHandler startProcess() throws ExecutionException {
return startProcess(new CommandLinePatcher[]{});
}
/**
* Patches the command line parameters applying patchers from first to last, and then runs it.
*
* @param patchers any number of patchers; any patcher may be null, and the whole argument may be null.
* @return handler of the started process
* @throws ExecutionException
*/
protected ProcessHandler startProcess(CommandLinePatcher... patchers) throws ExecutionException {
GeneralCommandLine commandLine = generateCommandLine(patchers);
// Extend command line
PythonRunConfigurationExtensionsManager.getInstance()
.patchCommandLine(myConfig, getRunnerSettings(), commandLine, getEnvironment().getRunner().getRunnerId());
Sdk sdk = PythonSdkType.findSdkByPath(myConfig.getInterpreterPath());
final ProcessHandler processHandler;
if (PySdkUtil.isRemote(sdk)) {
processHandler =
createRemoteProcessStarter().startRemoteProcess(sdk, commandLine, myConfig.getProject(), myConfig.getMappingSettings());
}
else {
EncodingEnvironmentUtil.fixDefaultEncodingIfMac(commandLine, myConfig.getProject());
processHandler = doCreateProcess(commandLine);
ProcessTerminatedListener.attach(processHandler);
}
// attach extensions
PythonRunConfigurationExtensionsManager.getInstance().attachExtensionsToProcess(myConfig, processHandler, getRunnerSettings());
return processHandler;
}
protected PyRemoteProcessStarter createRemoteProcessStarter() {
return new PyRemoteProcessStarter();
}
public GeneralCommandLine generateCommandLine(CommandLinePatcher[] patchers) throws ExecutionException {
GeneralCommandLine commandLine = generateCommandLine();
if (patchers != null) {
for (CommandLinePatcher patcher : patchers) {
if (patcher != null) patcher.patchCommandLine(commandLine);
}
}
return commandLine;
}
protected ProcessHandler doCreateProcess(GeneralCommandLine commandLine) throws ExecutionException {
return PythonProcessRunner.createProcess(commandLine);
}
public GeneralCommandLine generateCommandLine() throws ExecutionException {
GeneralCommandLine commandLine = createCommandLine();
commandLine.withCharset(EncodingProjectManager.getInstance(myConfig.getProject()).getDefaultCharset());
setRunnerPath(commandLine);
// define groups
createStandardGroupsIn(commandLine);
buildCommandLineParameters(commandLine);
initEnvironment(commandLine);
return commandLine;
}
private static GeneralCommandLine createCommandLine() {
return PtyCommandLine.isEnabled() ? new PtyCommandLine() : new GeneralCommandLine();
}
/**
* Creates a number of parameter groups in the command line:
* GROUP_EXE_OPTIONS, GROUP_DEBUGGER, GROUP_SCRIPT.
* These are necessary for command line patchers to work properly.
*
* @param commandLine
*/
public static void createStandardGroupsIn(GeneralCommandLine commandLine) {
ParametersList params = commandLine.getParametersList();
params.addParamsGroup(GROUP_EXE_OPTIONS);
params.addParamsGroup(GROUP_DEBUGGER);
params.addParamsGroup(GROUP_PROFILER);
params.addParamsGroup(GROUP_SCRIPT);
}
protected void initEnvironment(GeneralCommandLine commandLine) {
Map env = myConfig.getEnvs();
if (env == null) {
env = new HashMap();
}
else {
env = new HashMap(env);
}
addPredefinedEnvironmentVariables(env, myConfig.isPassParentEnvs());
addCommonEnvironmentVariables(env);
commandLine.getEnvironment().clear();
commandLine.getEnvironment().putAll(env);
commandLine.setPassParentEnvironment(myConfig.isPassParentEnvs());
buildPythonPath(commandLine, myConfig.isPassParentEnvs());
}
protected static void addCommonEnvironmentVariables(Map env) {
PythonEnvUtil.setPythonUnbuffered(env);
env.put("PYCHARM_HOSTED", "1");
}
public void addPredefinedEnvironmentVariables(Map envs, boolean passParentEnvs) {
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(myConfig.getInterpreterPath());
if (flavor != null) {
flavor.addPredefinedEnvironmentVariables(envs, myConfig.getProject());
}
}
private void buildPythonPath(GeneralCommandLine commandLine, boolean passParentEnvs) {
Sdk pythonSdk = PythonSdkType.findSdkByPath(myConfig.getInterpreterPath());
if (pythonSdk != null) {
List pathList = Lists.newArrayList(getAddedPaths(pythonSdk));
pathList.addAll(collectPythonPath());
initPythonPath(commandLine, passParentEnvs, pathList, myConfig.getInterpreterPath());
}
}
public static void initPythonPath(GeneralCommandLine commandLine,
boolean passParentEnvs,
List pathList,
final String interpreterPath) {
final PythonSdkFlavor flavor = PythonSdkFlavor.getFlavor(interpreterPath);
if (flavor != null) {
flavor.initPythonPath(commandLine, pathList);
}
else {
PythonSdkFlavor.initPythonPath(commandLine.getEnvironment(), passParentEnvs, pathList);
}
}
public static List getAddedPaths(Sdk pythonSdk) {
List pathList = new ArrayList();
final SdkAdditionalData sdkAdditionalData = pythonSdk.getSdkAdditionalData();
if (sdkAdditionalData instanceof PythonSdkAdditionalData) {
final Set addedPaths = ((PythonSdkAdditionalData)sdkAdditionalData).getAddedPathFiles();
for (VirtualFile file : addedPaths) {
addToPythonPath(file, pathList);
}
}
return pathList;
}
private static void addToPythonPath(VirtualFile file, Collection pathList) {
if (file.getFileSystem() instanceof JarFileSystem) {
final VirtualFile realFile = JarFileSystem.getInstance().getVirtualFileForJar(file);
if (realFile != null) {
addIfNeeded(realFile, pathList);
}
}
else {
addIfNeeded(file, pathList);
}
}
private static void addIfNeeded(@NotNull final VirtualFile file, @NotNull final Collection pathList) {
addIfNeeded(pathList, file.getPath());
}
protected static void addIfNeeded(Collection pathList, String path) {
final Set vals = Sets.newHashSet(pathList);
final String filePath = FileUtil.toSystemDependentName(path);
if (!vals.contains(filePath)) {
pathList.add(filePath);
}
}
protected Collection collectPythonPath() {
final Module module = myConfig.getModule();
Set pythonPath = Sets.newHashSet(collectPythonPath(module, myConfig.shouldAddContentRoots(), myConfig.shouldAddSourceRoots()));
if (isDebug() && getSdkFlavor() instanceof JythonSdkFlavor) { //that fixes Jython problem changing sys.argv on execfile, see PY-8164
pythonPath.add(PythonHelpersLocator.getHelperPath("pycharm"));
pythonPath.add(PythonHelpersLocator.getHelperPath("pydev"));
}
return pythonPath;
}
@NotNull
public static Collection collectPythonPath(@Nullable Module module) {
return collectPythonPath(module, true, true);
}
@NotNull
public static Collection collectPythonPath(@Nullable Module module, boolean addContentRoots,
boolean addSourceRoots) {
Collection pythonPathList = Sets.newLinkedHashSet();
if (module != null) {
Set dependencies = new HashSet();
ModuleUtilCore.getDependencies(module, dependencies);
if (addContentRoots) {
addRoots(pythonPathList, ModuleRootManager.getInstance(module).getContentRoots());
for (Module dependency : dependencies) {
addRoots(pythonPathList, ModuleRootManager.getInstance(dependency).getContentRoots());
}
}
if (addSourceRoots) {
addRoots(pythonPathList, ModuleRootManager.getInstance(module).getSourceRoots());
for (Module dependency : dependencies) {
addRoots(pythonPathList, ModuleRootManager.getInstance(dependency).getSourceRoots());
}
}
addLibrariesFromModule(module, pythonPathList);
addRootsFromModule(module, pythonPathList);
for (Module dependency : dependencies) {
addLibrariesFromModule(dependency, pythonPathList);
addRootsFromModule(dependency, pythonPathList);
}
}
return pythonPathList;
}
private static void addLibrariesFromModule(Module module, Collection list) {
final OrderEntry[] entries = ModuleRootManager.getInstance(module).getOrderEntries();
for (OrderEntry entry : entries) {
if (entry instanceof LibraryOrderEntry) {
final String name = ((LibraryOrderEntry)entry).getLibraryName();
if (name != null && name.endsWith(LibraryContributingFacet.PYTHON_FACET_LIBRARY_NAME_SUFFIX)) {
// skip libraries from Python facet
continue;
}
for (VirtualFile root : ((LibraryOrderEntry)entry).getRootFiles(OrderRootType.CLASSES)) {
final Library library = ((LibraryOrderEntry)entry).getLibrary();
if (!PlatformUtils.isPyCharm()) {
addToPythonPath(root, list);
}
else if (library instanceof LibraryImpl) {
final PersistentLibraryKind> kind = ((LibraryImpl)library).getKind();
if (kind == PythonLibraryType.getInstance().getKind()) {
addToPythonPath(root, list);
}
}
}
}
}
}
private static void addRootsFromModule(Module module, Collection pythonPathList) {
// for Jython
final CompilerModuleExtension extension = CompilerModuleExtension.getInstance(module);
if (extension != null) {
final VirtualFile path = extension.getCompilerOutputPath();
if (path != null) {
pythonPathList.add(path.getPath());
}
final VirtualFile pathForTests = extension.getCompilerOutputPathForTests();
if (pathForTests != null) {
pythonPathList.add(pathForTests.getPath());
}
}
//additional paths from facets (f.e. buildout)
final Facet[] facets = FacetManager.getInstance(module).getAllFacets();
for (Facet facet : facets) {
if (facet instanceof PythonPathContributingFacet) {
List more_paths = ((PythonPathContributingFacet)facet).getAdditionalPythonPath();
if (more_paths != null) pythonPathList.addAll(more_paths);
}
}
}
private static void addRoots(Collection pythonPathList, VirtualFile[] roots) {
for (VirtualFile root : roots) {
addToPythonPath(root, pythonPathList);
}
}
protected void setRunnerPath(GeneralCommandLine commandLine) throws ExecutionException {
String interpreterPath = getInterpreterPath();
commandLine.setExePath(FileUtil.toSystemDependentName(interpreterPath));
}
protected String getInterpreterPath() throws ExecutionException {
String interpreterPath = myConfig.getInterpreterPath();
if (interpreterPath == null) {
throw new ExecutionException("Cannot find Python interpreter for this run configuration");
}
return interpreterPath;
}
protected void buildCommandLineParameters(GeneralCommandLine commandLine) {
}
public boolean isMultiprocessDebug() {
if (myMultiprocessDebug != null) {
return myMultiprocessDebug;
}
else {
return PyDebuggerOptionsProvider.getInstance(myConfig.getProject()).isAttachToSubprocess();
}
}
public void setMultiprocessDebug(boolean multiprocessDebug) {
myMultiprocessDebug = multiprocessDebug;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy