From f41f9c370a4c93c9619b3699cd9df250a45597ef Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 14 Jul 2014 12:59:14 +0200 Subject: [PATCH 1/3] Debugger reader performance fixed, now uses BaseOutpuReader (PY-11393). --- .../python/debugger/pydev/RemoteDebugger.java | 59 ++++++++++++------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java index a307c031d380..9e347e0e5d7b 100644 --- a/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java +++ b/python/pydevSrc/com/jetbrains/python/debugger/pydev/RemoteDebugger.java @@ -10,7 +10,9 @@ import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.util.TimeoutUtil; import com.intellij.util.containers.ContainerUtil; +import com.intellij.util.io.BaseOutputReader; import com.intellij.xdebugger.frame.XValueChildrenList; import com.jetbrains.python.console.pydev.PydevCompletionVariant; import com.jetbrains.python.debugger.*; @@ -25,6 +27,7 @@ import java.nio.charset.Charset; import java.security.SecureRandom; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Future; public class RemoteDebugger implements ProcessDebugger { @@ -87,8 +90,7 @@ public class RemoteDebugger implements ProcessDebugger { if (myConnected) { try { - myDebuggerReader = new DebuggerReader(); - ApplicationManager.getApplication().executeOnPooledThread(myDebuggerReader); + myDebuggerReader = createReader(mySocket); } catch (Exception e) { synchronized (mySocketObject) { @@ -405,35 +407,42 @@ public class RemoteDebugger implements ProcessDebugger { execute(command); } - private class DebuggerReader implements Runnable { - private final InputStream myInputStream; - private boolean myClosing = false; + public DebuggerReader createReader(@NotNull Socket socket) throws IOException { + synchronized (mySocketObject) { + final InputStream myInputStream = socket.getInputStream(); + //noinspection IOResourceOpenedButNotSafelyClosed + final Reader reader = new InputStreamReader(myInputStream, Charset.forName("UTF-8")); //TODO: correct econding? + return new DebuggerReader(reader); + } + } - private DebuggerReader() throws IOException { - synchronized (mySocketObject) { - this.myInputStream = mySocket.getInputStream(); - } + private class DebuggerReader extends BaseOutputReader { + private boolean myClosing = false; + private Reader myReader; + + private DebuggerReader(final Reader reader) throws IOException { + super(reader); + myReader = reader; + start(); } - public void run() { - final BufferedReader reader = new BufferedReader(new InputStreamReader(myInputStream, Charset.forName("UTF-8"))); + protected void doRun() { try { - String line; - while ((line = reader.readLine()) != null) { - processResponse(line); + while (true) { + boolean read = readAvailable(); + if (myClosing) { break; } + + TimeoutUtil.sleep(mySleepingPolicy.getTimeToSleep(read)); } } - catch (SocketException ignore) { + catch (Exception e) { fireCommunicationError(); } - catch (Exception e) { - LOG.error(e); - } finally { - closeReader(reader); + closeReader(myReader); fireExitEvent(); } } @@ -518,7 +527,7 @@ public class RemoteDebugger implements ProcessDebugger { return ProtocolParser.parseThread(frame.getPayload(), myDebugProcess.getPositionConverter()); } - private void closeReader(BufferedReader reader) { + private void closeReader(Reader reader) { try { reader.close(); } @@ -526,9 +535,19 @@ public class RemoteDebugger implements ProcessDebugger { } } + @Override + protected Future executeOnPooledThread(Runnable runnable) { + return ApplicationManager.getApplication().executeOnPooledThread(runnable); + } + public void close() { myClosing = true; } + + @Override + protected void onTextAvailable(@NotNull String text) { + processResponse(text); + } } private void writeToConsole(PyIo io) { From 912c0d72c1d010ed6dceec830d45da9ab788afad Mon Sep 17 00:00:00 2001 From: Konstantin Bulenkov Date: Mon, 14 Jul 2014 17:04:38 +0200 Subject: [PATCH 2/3] html editor as a error pane --- .../configuration/ErrorPaneConfigurable.java | 63 ++++++++++++++++++- .../ProjectStructureConfigurable.java | 2 +- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ErrorPaneConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ErrorPaneConfigurable.java index 2e2860c9f047..e8dede7c0902 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ErrorPaneConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ErrorPaneConfigurable.java @@ -15,22 +15,63 @@ */ package com.intellij.openapi.roots.ui.configuration; +import com.intellij.openapi.Disposable; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.Project; +import com.intellij.openapi.roots.ui.configuration.projectRoot.StructureConfigurableContext; +import com.intellij.openapi.util.Disposer; +import com.intellij.ui.ScrollPaneFactory; +import com.intellij.util.Alarm; +import com.intellij.util.ui.UIUtil; import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; +import java.awt.*; +import java.util.ArrayList; /** * @author Konstantin Bulenkov */ -public class ErrorPaneConfigurable implements Configurable { +public class ErrorPaneConfigurable extends JPanel implements Configurable, Disposable, ConfigurationErrors { private final Project myProject; + private final StructureConfigurableContext myContext; + private final Alarm myAlarm; + private final ArrayList myErrors = new ArrayList(); + private final JTextPane myContent = new JTextPane(); - public ErrorPaneConfigurable(Project project) { + public ErrorPaneConfigurable(Project project, StructureConfigurableContext context) { + super(new BorderLayout()); + myContent.setEditorKit(UIUtil.getHTMLEditorKit()); + myContent.setEditable(false); + final JScrollPane pane = ScrollPaneFactory.createScrollPane(myContent, true); + pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); + add(pane); myProject = project; + myContext = context; + myAlarm = new Alarm(this); + project.getMessageBus().connect(this).subscribe(ConfigurationErrors.TOPIC, this); + + refresh(); + } + + public void refresh() { + myAlarm.cancelAllRequests(); + myAlarm.addRequest(new Runnable() { + @Override + public void run() { + String html = ""; + int i = 0; + for (ConfigurationError error : myErrors) { + i++; + html+= i + ". " + error.getDescription() + "
"; + } + html += ""; + myContent.setText(html); + } + }, 100); } @Nls @@ -48,7 +89,7 @@ public class ErrorPaneConfigurable implements Configurable { @Nullable @Override public JComponent createComponent() { - return new JLabel("Demo"); + return this; } @Override @@ -68,6 +109,22 @@ public class ErrorPaneConfigurable implements Configurable { @Override public void disposeUIResources() { + Disposer.dispose(this); + } + @Override + public void dispose() { + } + + @Override + public void addError(@NotNull ConfigurationError error) { + myErrors.add(error); + refresh(); + } + + @Override + public void removeError(@NotNull ConfigurationError error) { + myErrors.remove(error); + refresh(); } } diff --git a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java index 131a15858eab..2337550cf146 100644 --- a/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java +++ b/java/idea-ui/src/com/intellij/openapi/roots/ui/configuration/ProjectStructureConfigurable.java @@ -300,7 +300,7 @@ public class ProjectStructureConfigurable extends BaseConfigurable implements Se } private void addErrorPane() { - addConfigurable(new ErrorPaneConfigurable(myProject), true); + addConfigurable(new ErrorPaneConfigurable(myProject, myContext), true); } private void addGlobalLibrariesConfig() { From 86b7bf5c1eb46e3442844fd01fb5a5a82ce3a88f Mon Sep 17 00:00:00 2001 From: Dmitry Trofimov Date: Mon, 14 Jul 2014 17:22:56 +0200 Subject: [PATCH 3/3] Fix copying .egg files from remote host to libraries folder (PY-13044). --- .../src/com/intellij/remote/RemoteFile.java | 9 ++-- python/helpers/generator3.py | 3 ++ .../projectView/PyRemoteLibrariesNode.java | 41 +++++++++++++++---- .../projectView/PyTreeStructureProvider.java | 22 +++++++--- .../python/sdk/flavors/PyRemoteSdkFlavor.java | 2 +- 5 files changed, 60 insertions(+), 17 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/remote/RemoteFile.java b/platform/platform-impl/src/com/intellij/remote/RemoteFile.java index 4a2e11379364..724ec31fe1ef 100644 --- a/platform/platform-impl/src/com/intellij/remote/RemoteFile.java +++ b/platform/platform-impl/src/com/intellij/remote/RemoteFile.java @@ -2,7 +2,6 @@ package com.intellij.remote; import com.intellij.openapi.util.io.FileUtil; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * @author traff @@ -25,14 +24,14 @@ public class RemoteFile { this(resolveChild(parent, child, isWin), isWin); } - @Nullable + @NotNull public String getName() { int ind = myPath.lastIndexOf(getSeparator(myWin)); if (ind != -1 && ind < myPath.length() - 1) { //not last char return myPath.substring(ind + 1); } else { - return null; + return myPath; } } @@ -88,6 +87,10 @@ public class RemoteFile { return detectSystemByPath(path).createRemoteFile(path, script); } + public static RemoteFile createRemoteFile(String path) { + return detectSystemByPath(path).createRemoteFile(path); + } + public static RemoteFile createRemoteFile(final String path, final String script, final boolean isWindows) { return new RemoteFileBuilder(isWindows).createRemoteFile(path, script); } diff --git a/python/helpers/generator3.py b/python/helpers/generator3.py index 50e911923a43..d09f6d918e18 100644 --- a/python/helpers/generator3.py +++ b/python/helpers/generator3.py @@ -161,6 +161,9 @@ def list_sources(paths): path = os.path.normpath(path) + if path.endswith('.egg') and os.path.isfile(path): + say("%s\t%s\t%d", path, path, os.path.getsize(path)) + for root, files in walk_python_path(path): for name in files: if name.endswith('.py'): diff --git a/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java b/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java index 62de7ea14daf..c5b0af7103f3 100644 --- a/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java +++ b/python/src/com/jetbrains/python/projectView/PyRemoteLibrariesNode.java @@ -19,16 +19,16 @@ import com.google.common.base.Function; import com.google.common.base.Predicates; import com.google.common.collect.FluentIterable; import com.google.common.collect.Lists; +import com.intellij.ide.highlighter.ArchiveFileType; import com.intellij.ide.projectView.PresentationData; import com.intellij.ide.projectView.ViewSettings; import com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode; import com.intellij.ide.util.treeView.AbstractTreeNode; import com.intellij.openapi.project.Project; import com.intellij.openapi.projectRoots.Sdk; +import com.intellij.openapi.vfs.JarFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.PsiDirectory; -import com.intellij.psi.PsiElement; -import com.intellij.psi.PsiManager; +import com.intellij.psi.*; import com.intellij.util.PlatformIcons; import com.jetbrains.python.remote.PyRemoteSdkAdditionalDataBase; import com.jetbrains.python.sdk.PySdkUtil; @@ -75,11 +75,16 @@ public class PyRemoteLibrariesNode extends PsiDirectoryNode { return FluentIterable.from(Lists.newArrayList(getValue().getChildren())).transform(new Function() { @Override public AbstractTreeNode apply(PsiElement input) { - if (input instanceof PsiDirectory) { - PsiDirectory directory = (PsiDirectory)input; - if (myRemoteSdkData.getPathMappings().canReplaceLocal((directory.getVirtualFile().getPath()))) { - return new PyRemoteRootNode(myRemoteSdkData.getPathMappings().convertToRemote(directory.getVirtualFile().getPath()), - getProject(), directory, getSettings()); + if (input instanceof PsiFileSystemItem) { + String path = ((PsiFileSystemItem)input).getVirtualFile().getPath(); + + + PsiDirectory dir = input instanceof PsiDirectory ? (PsiDirectory)input : getDirectoryForJar((PsiFile)input); + + + if (myRemoteSdkData.getPathMappings().canReplaceLocal(path)) { + return new PyRemoteRootNode(myRemoteSdkData.getPathMappings().convertToRemote(path), + getProject(), dir, getSettings()); } } @@ -88,6 +93,26 @@ public class PyRemoteLibrariesNode extends PsiDirectoryNode { }).filter(Predicates.notNull()).toList(); } + @Nullable + private PsiDirectory getDirectoryForJar(PsiFile input) { + VirtualFile jarRoot = getJarRoot(input); + if (myProject != null && jarRoot != null) { + return PsiManager.getInstance(myProject).findDirectory(jarRoot); + } + else { + return null; + } + } + + @Nullable + private static VirtualFile getJarRoot(PsiFile input) { + final VirtualFile file = input.getVirtualFile(); + if (file == null || !file.isValid() || !(file.getFileType() instanceof ArchiveFileType)) { + return null; + } + return JarFileSystem.getInstance().getJarRootForLocalFile(file); + } + public static class PyRemoteRootNode extends PsiDirectoryNode { private String myRemotePath; diff --git a/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java b/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java index 6153bc64146d..8e4889498bca 100644 --- a/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java +++ b/python/src/com/jetbrains/python/projectView/PyTreeStructureProvider.java @@ -28,6 +28,8 @@ import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.projectRoots.SdkTypeId; import com.intellij.openapi.roots.JdkOrderEntry; import com.intellij.openapi.roots.LibraryOrSdkOrderEntry; +import com.intellij.openapi.vfs.JarFileSystem; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDirectory; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -50,7 +52,9 @@ import java.util.List; public class PyTreeStructureProvider implements SelectableTreeStructureProvider, DumbAware { @NotNull @Override - public Collection modify(@NotNull AbstractTreeNode parent, @NotNull Collection children, ViewSettings settings) { + public Collection modify(@NotNull AbstractTreeNode parent, + @NotNull Collection children, + ViewSettings settings) { final Project project = parent.getProject(); final Sdk sdk = getPythonSdk(parent); if (sdk != null && project != null) { @@ -111,7 +115,15 @@ public class PyTreeStructureProvider implements SelectableTreeStructureProvider, if (directory.getVirtualFile().equals(PyUserSkeletonsUtil.getUserSkeletonsDirectory())) { continue; } - PsiDirectory dirParent = directory.getParent(); + VirtualFile dir = directory.getVirtualFile(); + if (dir.getFileSystem() instanceof JarFileSystem) { + dir = ((JarFileSystem)directory.getVirtualFile().getFileSystem()).getLocalVirtualFileFor(directory.getVirtualFile()); + } + if (dir == null) { + continue; + } + VirtualFile dirParent = dir.getParent(); + if (dirParent != null && dirParent.getName().equals(PythonSdkType.SKELETON_DIR_NAME)) { continue; } @@ -120,7 +132,7 @@ public class PyTreeStructureProvider implements SelectableTreeStructureProvider, continue; } if (dirParent != null) { - PsiDirectory grandParent = dirParent.getParent(); + VirtualFile grandParent = dirParent.getParent(); if (grandParent != null && grandParent.getName().equals(PythonSdkType.REMOTE_SOURCES_DIR_NAME)) { continue; @@ -158,8 +170,8 @@ public class PyTreeStructureProvider implements SelectableTreeStructureProvider, } } if (parents.size() > 0) { - return parents.get(parents.size()-1); + return parents.get(parents.size() - 1); } - return element.getContainingFile(); + return element.getContainingFile(); } } diff --git a/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java b/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java index 271afc6e8c2f..124003158038 100644 --- a/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java +++ b/python/src/com/jetbrains/python/sdk/flavors/PyRemoteSdkFlavor.java @@ -57,6 +57,6 @@ public class PyRemoteSdkFlavor extends CPythonSdkFlavor { @Nullable private static String getExecutableName(String path) { - return RemoteFile.detectSystemByPath(path).createRemoteFile(path).getName(); + return RemoteFile.createRemoteFile(path).getName(); } }