From 7a9ea508544b1eb2885dabe57dbfe1adde054d90 Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 9 Jul 2012 19:10:24 +0400 Subject: [PATCH 1/2] [git] Optimize listening of VFS events: don't use VirtualFile#getFile(), use getPath() and getName() instead. getFile() calls findChild for VFileCreateEvent, which may result in performance problems as in IDEA-87656. --- .../com/intellij/openapi/vfs/newvfs/events/VFileEvent.java | 3 +++ .../git4idea/src/git4idea/repo/GitRepositoryUpdater.java | 6 +++--- .../git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java | 5 ++--- plugins/git4idea/src/git4idea/roots/GitRootScanner.java | 5 ++--- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileEvent.java b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileEvent.java index 909bd42284ca..3e931a588d7d 100644 --- a/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileEvent.java +++ b/platform/core-api/src/com/intellij/openapi/vfs/newvfs/events/VFileEvent.java @@ -46,6 +46,9 @@ public abstract class VFileEvent { /** * Returns the VirtualFile which this event belongs to. * In some cases it may be null - it is not guaranteed that there is such file. + * + * NB: Use this method with caution, because {@link com.intellij.openapi.vfs.newvfs.events.VFileCreateEvent#getFile()} needs + * {@link VirtualFile#findChild(String)} which may be a performance leak. */ @Nullable public abstract VirtualFile getFile(); diff --git a/plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java b/plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java index 5bf34489e979..b95fb692d950 100644 --- a/plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java +++ b/plugins/git4idea/src/git4idea/repo/GitRepositoryUpdater.java @@ -112,11 +112,11 @@ final class GitRepositoryUpdater implements Disposable, BulkFileListener { boolean rebaseFileChanged = false; boolean mergeFileChanged = false; for (VFileEvent event : events) { - final VirtualFile file = event.getFile(); - if (file == null) { + String filePath = event.getPath(); + if (filePath == null) { continue; } - String filePath = GitFileUtils.stripFileProtocolPrefix(file.getPath()); + filePath = GitFileUtils.stripFileProtocolPrefix(filePath); if (myRepositoryFiles.isConfigFile(filePath)) { configChanged = true; } else if (myRepositoryFiles.isHeadFile(filePath)) { diff --git a/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java b/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java index 389c20aafa2b..33a701d154e0 100644 --- a/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java +++ b/plugins/git4idea/src/git4idea/repo/GitUntrackedFilesHolder.java @@ -227,11 +227,10 @@ public class GitUntrackedFilesHolder implements Disposable, BulkFileListener { if (allChanged) { break; } - VirtualFile file = event.getFile(); - if (file == null) { + String path = event.getPath(); + if (path == null) { continue; } - String path = file.getPath(); if (totalRefreshNeeded(path)) { allChanged = true; } diff --git a/plugins/git4idea/src/git4idea/roots/GitRootScanner.java b/plugins/git4idea/src/git4idea/roots/GitRootScanner.java index 02cebd2fce56..37e15beea9d2 100644 --- a/plugins/git4idea/src/git4idea/roots/GitRootScanner.java +++ b/plugins/git4idea/src/git4idea/roots/GitRootScanner.java @@ -25,7 +25,6 @@ import com.intellij.openapi.roots.ModuleRootListener; import com.intellij.openapi.startup.StartupManager; import com.intellij.openapi.vcs.ProjectLevelVcsManager; import com.intellij.openapi.vcs.VcsListener; -import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFileManager; import com.intellij.openapi.vfs.newvfs.BulkFileListener; import com.intellij.openapi.vfs.newvfs.events.VFileEvent; @@ -79,8 +78,8 @@ public class GitRootScanner implements BulkFileListener, ModuleRootListener, Dis @Override public void after(@NotNull List events) { for (VFileEvent event : events) { - VirtualFile file = event.getFile(); - if (file != null && file.getName().equalsIgnoreCase(GitUtil.DOT_GIT) && file.isDirectory()) { + String filePath = event.getPath(); + if (filePath != null && filePath.toLowerCase().endsWith(GitUtil.DOT_GIT)) { scanIfReady(); } } From 3eb6c9ac204e189ecfa96253c7420af30d4c3736 Mon Sep 17 00:00:00 2001 From: Eugene Kudelevsky Date: Mon, 9 Jul 2012 19:17:19 +0400 Subject: [PATCH 2/2] refactor execution of android tools, implement better api --- .../android/util/AndroidCommonUtils.java | 13 ++++ .../actions/RunAndroidAvdManagerAction.java | 14 ++-- .../actions/RunAndroidSdkManagerAction.java | 14 ++-- .../compiler/tools/AndroidMavenExecutor.java | 11 ++- .../jetbrains/android/facet/AndroidFacet.java | 30 ++++++-- .../newProject/AndroidModuleBuilder.java | 2 +- .../org/jetbrains/android/run/AvdChooser.java | 15 ++-- ...AndroidLayoutPreviewToolWindowManager.java | 18 +---- .../jetbrains/android/util/AndroidUtils.java | 75 +++++++------------ .../android/util/OutputProcessor.java | 10 +++ .../util/StringBuildingOutputProcessor.java | 20 +++++ .../android/util/WaitingStrategies.java | 55 ++++++++++++++ 12 files changed, 181 insertions(+), 96 deletions(-) create mode 100644 plugins/android/src/org/jetbrains/android/util/OutputProcessor.java create mode 100644 plugins/android/src/org/jetbrains/android/util/StringBuildingOutputProcessor.java create mode 100644 plugins/android/src/org/jetbrains/android/util/WaitingStrategies.java diff --git a/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java b/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java index 64edc51716a7..4bf3ff099498 100644 --- a/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java +++ b/plugins/android/common/src/org/jetbrains/android/util/AndroidCommonUtils.java @@ -567,4 +567,17 @@ public class AndroidCommonUtils { } } } + + @NotNull + public static String getStackTrace(@NotNull Throwable t) { + final StringWriter stringWriter = new StringWriter(); + final PrintWriter writer = new PrintWriter(stringWriter); + try { + t.printStackTrace(writer); + return stringWriter.toString(); + } + finally { + writer.close(); + } + } } diff --git a/plugins/android/src/org/jetbrains/android/actions/RunAndroidAvdManagerAction.java b/plugins/android/src/org/jetbrains/android/actions/RunAndroidAvdManagerAction.java index dce6550d55d4..787555bb0423 100644 --- a/plugins/android/src/org/jetbrains/android/actions/RunAndroidAvdManagerAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/RunAndroidAvdManagerAction.java @@ -21,10 +21,7 @@ import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.android.util.AndroidCommonUtils; -import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.ExecutionStatus; +import org.jetbrains.android.util.*; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -53,9 +50,10 @@ public class RunAndroidAvdManagerAction extends AndroidRunSdkToolAction { commandLine.setExePath(toolPath); commandLine.addParameter("avd"); - final StringBuilder messageBuilder = new StringBuilder(); + final StringBuildingOutputProcessor processor = new StringBuildingOutputProcessor(); try { - if (AndroidUtils.executeCommand(commandLine, messageBuilder, 500) == ExecutionStatus.TIMEOUT) { + if (AndroidUtils.executeCommand(commandLine, processor, WaitingStrategies.WaitForTime.getInstance(500)) == + ExecutionStatus.TIMEOUT) { return; } } @@ -64,12 +62,12 @@ public class RunAndroidAvdManagerAction extends AndroidRunSdkToolAction { return; } - final String message = messageBuilder.toString(); + final String message = processor.getMessage(); if (message.contains("Error")) { commandLine = new GeneralCommandLine(); commandLine.setExePath(toolPath); try { - AndroidUtils.executeCommand(commandLine, messageBuilder, 0); + AndroidUtils.executeCommand(commandLine, null, WaitingStrategies.DoNotWait.getInstance()); } catch (ExecutionException e) { LOG.error(e); diff --git a/plugins/android/src/org/jetbrains/android/actions/RunAndroidSdkManagerAction.java b/plugins/android/src/org/jetbrains/android/actions/RunAndroidSdkManagerAction.java index 8a896827c172..824d0186fcd8 100644 --- a/plugins/android/src/org/jetbrains/android/actions/RunAndroidSdkManagerAction.java +++ b/plugins/android/src/org/jetbrains/android/actions/RunAndroidSdkManagerAction.java @@ -21,10 +21,7 @@ import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; -import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.android.util.AndroidCommonUtils; -import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.ExecutionStatus; +import org.jetbrains.android.util.*; import org.jetbrains.annotations.NotNull; import java.io.File; @@ -49,9 +46,10 @@ public class RunAndroidSdkManagerAction extends AndroidRunSdkToolAction { commandLine.setExePath(toolPath); commandLine.addParameter("sdk"); - final StringBuilder messageBuilder = new StringBuilder(); + final StringBuildingOutputProcessor processor = new StringBuildingOutputProcessor(); try { - if (AndroidUtils.executeCommand(commandLine, messageBuilder, 500) == ExecutionStatus.TIMEOUT) { + if (AndroidUtils.executeCommand(commandLine, processor, WaitingStrategies.WaitForTime.getInstance(500)) == + ExecutionStatus.TIMEOUT) { return; } } @@ -60,12 +58,12 @@ public class RunAndroidSdkManagerAction extends AndroidRunSdkToolAction { return; } - final String message = messageBuilder.toString(); + final String message = processor.getMessage(); if (message.contains("Error")) { commandLine = new GeneralCommandLine(); commandLine.setExePath(toolPath); try { - AndroidUtils.executeCommand(commandLine, messageBuilder, 0); + AndroidUtils.executeCommand(commandLine, null, WaitingStrategies.DoNotWait.getInstance()); } catch (ExecutionException e) { LOG.error(e); diff --git a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java index 0798f83d368f..4cdbf9247f79 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java +++ b/plugins/android/src/org/jetbrains/android/compiler/tools/AndroidMavenExecutor.java @@ -27,6 +27,8 @@ import com.intellij.openapi.util.Computable; import com.intellij.util.containers.HashMap; import org.jetbrains.android.util.AndroidUtils; import org.jetbrains.android.util.ExecutionStatus; +import org.jetbrains.android.util.StringBuildingOutputProcessor; +import org.jetbrains.android.util.WaitingStrategies; import org.jetbrains.annotations.Nullable; import org.jetbrains.idea.maven.execution.MavenExternalParameters; import org.jetbrains.idea.maven.execution.MavenRunnerParameters; @@ -79,10 +81,11 @@ public class AndroidMavenExecutor { } GeneralCommandLine commandLine = CommandLineBuilder.createFromJavaParameters(javaParams); - StringBuilder messageBuilder = new StringBuilder(); - boolean success = AndroidUtils.executeCommand(commandLine, messageBuilder, null) == ExecutionStatus.SUCCESS; - String message = messageBuilder.toString(); - if (message != null && !success) { + final StringBuildingOutputProcessor processor = new StringBuildingOutputProcessor(); + boolean success = + AndroidUtils.executeCommand(commandLine, processor, WaitingStrategies.WaitForever.getInstance()) == ExecutionStatus.SUCCESS; + String message = processor.getMessage(); + if (!success) { LOG.info(message); String lcmessage = message.toLowerCase(); int buildErrorIndex = lcmessage.indexOf(BUILD_ERROR_INDICATOR); diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java index cafa5787a04c..8d5a4150966d 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java @@ -26,6 +26,7 @@ import com.android.sdklib.internal.avd.AvdInfo; import com.android.sdklib.internal.avd.AvdManager; import com.intellij.CommonBundle; import com.intellij.ProjectTopics; +import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.ParametersList; import com.intellij.execution.process.ProcessHandler; @@ -84,9 +85,7 @@ import org.jetbrains.android.resourceManagers.LocalResourceManager; import org.jetbrains.android.resourceManagers.ResourceManager; import org.jetbrains.android.resourceManagers.SystemResourceManager; import org.jetbrains.android.sdk.*; -import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.android.util.AndroidCommonUtils; -import org.jetbrains.android.util.AndroidUtils; +import org.jetbrains.android.util.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -401,7 +400,7 @@ public class AndroidFacet extends Facet { return myAvdManager; } - public void launchEmulator(@Nullable final String avdName, @NotNull final String commands, @Nullable ProcessHandler handler) { + public void launchEmulator(@Nullable final String avdName, @NotNull final String commands, @NotNull final ProcessHandler handler) { AndroidPlatform platform = getConfiguration().getAndroidPlatform(); if (platform != null) { final String emulatorPath = platform.getSdkData().getLocation() + File.separator + AndroidCommonUtils @@ -418,10 +417,25 @@ public class AndroidFacet extends Facet { commandLine.addParameter(s); } } - if (handler != null) { - handler.notifyTextAvailable(commandLine.getCommandLineString() + '\n', ProcessOutputTypes.STDOUT); - } - AndroidUtils.runExternalToolInSeparateThread(commandLine, handler); + handler.notifyTextAvailable(commandLine.getCommandLineString() + '\n', ProcessOutputTypes.STDOUT); + + ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { + @Override + public void run() { + try { + AndroidUtils.executeCommand(commandLine, new OutputProcessor() { + @Override + public void onTextAvailable(@NotNull String text) { + handler.notifyTextAvailable(text, ProcessOutputTypes.STDOUT); + } + }, WaitingStrategies.WaitForTime.getInstance(5000)); + } + catch (ExecutionException e) { + final String stackTrace = AndroidCommonUtils.getStackTrace(e); + handler.notifyTextAvailable(stackTrace, ProcessOutputTypes.STDERR); + } + } + }); } } diff --git a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java index c94d87cb677a..eca2954117cc 100644 --- a/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java +++ b/plugins/android/src/org/jetbrains/android/newProject/AndroidModuleBuilder.java @@ -281,7 +281,7 @@ public class AndroidModuleBuilder extends JavaModuleBuilder { @Override public void run() { final Project project = module.getProject(); - AndroidUtils.runExternalTool(commandLine, null, true, project); + AndroidUtils.runExternalTool(commandLine, project); if (finalTempContentRoot != null) { final File[] children = finalTempContentRoot.listFiles(); diff --git a/plugins/android/src/org/jetbrains/android/run/AvdChooser.java b/plugins/android/src/org/jetbrains/android/run/AvdChooser.java index 551a17477e08..2353cb8ad2ab 100644 --- a/plugins/android/src/org/jetbrains/android/run/AvdChooser.java +++ b/plugins/android/src/org/jetbrains/android/run/AvdChooser.java @@ -22,6 +22,8 @@ import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; import com.android.sdklib.internal.avd.AvdInfo; import com.android.sdklib.internal.avd.AvdManager; +import com.intellij.CommonBundle; +import com.intellij.execution.ExecutionException; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.DialogWrapper; @@ -30,10 +32,7 @@ import com.intellij.ui.DoubleClickListener; import org.jetbrains.android.facet.AndroidFacet; import org.jetbrains.android.sdk.AndroidSdkData; import org.jetbrains.android.sdk.AndroidSdkUtils; -import org.jetbrains.android.util.AndroidBundle; -import org.jetbrains.android.util.AndroidCommonUtils; -import org.jetbrains.android.util.AndroidUtils; -import org.jetbrains.android.util.BooleanCellRenderer; +import org.jetbrains.android.util.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -122,7 +121,13 @@ public class AvdChooser extends DialogWrapper { public void actionPerformed(ActionEvent e) { GeneralCommandLine commandLine = new GeneralCommandLine(); commandLine.setExePath(androidToolPath); - AndroidUtils.runExternalToolInSeparateThread(commandLine, null); + try { + AndroidUtils.executeCommand(commandLine, new StringBuildingOutputProcessor(), WaitingStrategies.DoNotWait.getInstance()); + } + catch (ExecutionException e1) { + final String message = e1.getMessage() != null ? e1.getMessage() : "Cannot launch AVD manager"; + Messages.showErrorDialog(myPanel, message, CommonBundle.getErrorTitle()); + } } }); updateTable(); diff --git a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java index b07992425205..6aa21c0aeca3 100644 --- a/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java +++ b/plugins/android/src/org/jetbrains/android/uipreview/AndroidLayoutPreviewToolWindowManager.java @@ -68,6 +68,7 @@ import org.jetbrains.android.sdk.AndroidSdkAdditionalData; import org.jetbrains.android.sdk.AndroidSdkType; import org.jetbrains.android.sdk.AndroidSdkUtils; import org.jetbrains.android.util.AndroidBundle; +import org.jetbrains.android.util.AndroidCommonUtils; import org.jetbrains.android.util.AndroidResourceUtil; import org.jetbrains.android.util.AndroidSdkNotConfiguredException; import org.jetbrains.annotations.NonNls; @@ -80,8 +81,6 @@ import java.awt.*; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -454,7 +453,7 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { if (messageBuilder.length() > 0) { messageBuilder.append("\n\n"); } - messageBuilder.append(getStackTrace(t)); + messageBuilder.append(AndroidCommonUtils.getStackTrace(t)); } final DialogWrapper wrapper = new DialogWrapper(myProject, false) { @@ -478,19 +477,6 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent { wrapper.show(); } - @NotNull - private static String getStackTrace(@NotNull Throwable t) { - final StringWriter stringWriter = new StringWriter(); - final PrintWriter writer = new PrintWriter(stringWriter); - try { - t.printStackTrace(writer); - return stringWriter.toString(); - } - finally { - writer.close(); - } - } - @Nullable private TextEditor getActiveLayoutXmlEditor() { FileEditor[] fileEditors = myFileEditorManager.getSelectedEditors(); diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java index 02eaf55bc54c..9bfafc939fd3 100644 --- a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java +++ b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java @@ -30,7 +30,9 @@ import com.intellij.execution.configurations.ConfigurationType; import com.intellij.execution.configurations.GeneralCommandLine; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.execution.impl.ConsoleViewImpl; -import com.intellij.execution.process.*; +import com.intellij.execution.process.OSProcessHandler; +import com.intellij.execution.process.ProcessAdapter; +import com.intellij.execution.process.ProcessEvent; import com.intellij.execution.ui.ConsoleView; import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.facet.FacetManager; @@ -339,27 +341,29 @@ public class AndroidUtils { @NotNull public static ExecutionStatus executeCommand(@NotNull GeneralCommandLine commandLine, - @NotNull final StringBuilder messageBuilder, - @Nullable Integer timeout) throws ExecutionException { + @Nullable final OutputProcessor processor, + @Nullable WaitingStrategies.Strategy strategy) throws ExecutionException { LOG.info(commandLine.getCommandLineString()); OSProcessHandler handler = new OSProcessHandler(commandLine.createProcess(), ""); - final StringBuffer buffer = new StringBuffer(); final ProcessAdapter listener = new ProcessAdapter() { public void onTextAvailable(final ProcessEvent event, final Key outputType) { - buffer.append(event.getText()); + if (processor != null) { + final String message = event.getText(); + processor.onTextAvailable(message); + } } }; - if (timeout == null || timeout > 0) { + if (!(strategy instanceof WaitingStrategies.DoNotWait)) { handler.addProcessListener(listener); } handler.startNotify(); try { - if (timeout != null) { - if (timeout > 0) { - handler.waitFor(timeout); + if (!(strategy instanceof WaitingStrategies.WaitForever)) { + if (strategy instanceof WaitingStrategies.WaitForTime) { + handler.waitFor(((WaitingStrategies.WaitForTime)strategy).getTimeMs()); } } else { @@ -374,58 +378,37 @@ public class AndroidUtils { return ExecutionStatus.TIMEOUT; } - if (timeout == null || timeout > 0) { + if (!(strategy instanceof WaitingStrategies.DoNotWait)) { handler.removeProcessListener(listener); - final String message = buffer.toString(); - messageBuilder.append(message); - LOG.info(message); } - int exitCode = handler.getProcess().exitValue(); return exitCode == 0 ? ExecutionStatus.SUCCESS : ExecutionStatus.ERROR; } - public static void runExternalToolInSeparateThread(@NotNull final GeneralCommandLine commandLine, - @Nullable final ProcessHandler processHandler) { - ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { - public void run() { - runExternalTool(commandLine, processHandler, false, null); - } - }); - } - - public static void runExternalTool(@NotNull GeneralCommandLine commandLine, - @Nullable ProcessHandler processHandler, - boolean printOutputToAndroidConsole, - @Nullable final Project project) { - StringBuilder messageBuilder = new StringBuilder(); + public static void runExternalTool(@NotNull GeneralCommandLine commandLine, @Nullable final Project project) { + final StringBuildingOutputProcessor processor = new StringBuildingOutputProcessor(); String result; boolean success = false; try { - success = executeCommand(commandLine, messageBuilder, null) == ExecutionStatus.SUCCESS; - result = messageBuilder.toString(); + success = executeCommand(commandLine, processor, WaitingStrategies.WaitForever.getInstance()) == ExecutionStatus.SUCCESS; + result = processor.getMessage(); } catch (ExecutionException e) { result = e.getMessage(); } if (result != null) { - if (printOutputToAndroidConsole) { - final ConsoleViewContentType contentType = success ? - ConsoleViewContentType.NORMAL_OUTPUT : - ConsoleViewContentType.ERROR_OUTPUT; - final String finalResult = result; - assert project != null; - ApplicationManager.getApplication().invokeLater(new Runnable() { - @Override - public void run() { - printMessageToConsole(project, finalResult, contentType); - } - }); - } - else if (processHandler != null) { - processHandler.notifyTextAvailable(result + '\n', ProcessOutputTypes.STDOUT); - } + final ConsoleViewContentType contentType = success ? + ConsoleViewContentType.NORMAL_OUTPUT : + ConsoleViewContentType.ERROR_OUTPUT; + final String finalResult = result; + assert project != null; + ApplicationManager.getApplication().invokeLater(new Runnable() { + @Override + public void run() { + printMessageToConsole(project, finalResult, contentType); + } + }); } } diff --git a/plugins/android/src/org/jetbrains/android/util/OutputProcessor.java b/plugins/android/src/org/jetbrains/android/util/OutputProcessor.java new file mode 100644 index 000000000000..8d32f59d8bd8 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/util/OutputProcessor.java @@ -0,0 +1,10 @@ +package org.jetbrains.android.util; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Eugene.Kudelevsky + */ +public interface OutputProcessor { + void onTextAvailable(@NotNull String text); +} diff --git a/plugins/android/src/org/jetbrains/android/util/StringBuildingOutputProcessor.java b/plugins/android/src/org/jetbrains/android/util/StringBuildingOutputProcessor.java new file mode 100644 index 000000000000..5d1cacc2e89a --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/util/StringBuildingOutputProcessor.java @@ -0,0 +1,20 @@ +package org.jetbrains.android.util; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Eugene.Kudelevsky + */ +public class StringBuildingOutputProcessor implements OutputProcessor { + private final StringBuffer myBuffer = new StringBuffer(); + + @Override + public void onTextAvailable(@NotNull String text) { + myBuffer.append(text); + } + + @NotNull + public String getMessage() { + return myBuffer.toString(); + } +} diff --git a/plugins/android/src/org/jetbrains/android/util/WaitingStrategies.java b/plugins/android/src/org/jetbrains/android/util/WaitingStrategies.java new file mode 100644 index 000000000000..8b1acecb9fe3 --- /dev/null +++ b/plugins/android/src/org/jetbrains/android/util/WaitingStrategies.java @@ -0,0 +1,55 @@ +package org.jetbrains.android.util; + +import org.jetbrains.annotations.NotNull; + +/** + * @author Eugene.Kudelevsky + */ +public class WaitingStrategies { + public static abstract class Strategy { + private Strategy() { + } + } + + public static class DoNotWait extends Strategy { + private static final DoNotWait INSTANCE = new DoNotWait(); + + private DoNotWait() { + } + + @NotNull + public static DoNotWait getInstance() { + return INSTANCE; + } + } + + public static class WaitForTime extends Strategy { + private final int myTimeMs; + + private WaitForTime(int timeMs) { + assert timeMs > 0; + myTimeMs = timeMs; + } + + @NotNull + public static WaitForTime getInstance(int timeMs) { + return new WaitForTime(timeMs); + } + + public int getTimeMs() { + return myTimeMs; + } + } + + public static class WaitForever extends Strategy { + private static final WaitForever INSTANCE = new WaitForever(); + + private WaitForever() { + } + + @NotNull + public static WaitForever getInstance() { + return INSTANCE; + } + } +}