From 8fc232367f4d0d55645f6c3666f8b277e8efb226 Mon Sep 17 00:00:00 2001 From: "Dmitry.Krasilschikov" Date: Wed, 18 Apr 2018 15:08:39 +0300 Subject: [PATCH] IDEA-188810 move command execution to RunAnythingCommandCustomizer --- .../ruby/ruby/actions/RunAnythingAction.java | 16 +- .../ruby/actions/RunAnythingActionItem.java | 4 +- .../ruby/actions/RunAnythingCommandItem.java | 114 ++------------- .../ruby/ruby/actions/RunAnythingItem.java | 5 +- .../RunAnythingRunConfigurationItem.java | 9 +- .../ruby/ruby/actions/RunAnythingUtil.java | 3 +- .../RubyRunAnythingCommandCustomizer.java | 137 ++++++++++++++++++ .../RunAnythingCommandCustomizer.java | 65 +++++++++ 8 files changed, 243 insertions(+), 110 deletions(-) create mode 100644 ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/commands/RubyRunAnythingCommandCustomizer.java create mode 100644 ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/commands/RunAnythingCommandCustomizer.java diff --git a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingAction.java b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingAction.java index 0bd74748a301..b016af1d52a3 100644 --- a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingAction.java +++ b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingAction.java @@ -31,6 +31,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.actions.TextComponentEditorAction; import com.intellij.openapi.editor.ex.util.EditorUtil; +import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.keymap.impl.ModifierKeyDoubleClickHandler; import com.intellij.openapi.module.Module; @@ -431,8 +432,9 @@ public class RunAnythingAction extends AnAction implements CustomComponentAction return; } VirtualFile directory = getWorkDirectory(module); + DataContext dataContext = createDataContext(directory, null, null, module, project); if (value instanceof RunAnythingCommandItem) { - onDone = () -> ((RunAnythingCommandItem)value).run(project, createDataContext(directory, null, null)); + onDone = () -> ((RunAnythingCommandItem)value).run(dataContext); } else if (value == null) { onDone = () -> RunAnythingUtil.runOrCreateRunConfiguration(myDataContext, pattern, directory); @@ -456,14 +458,16 @@ public class RunAnythingAction extends AnAction implements CustomComponentAction Component c = comp; if (c == null) c = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner(); - value.run(project, createDataContext(null, c, event)); + value.run(createDataContext(null, c, event, null, project)); }); } @NotNull private static DataContext createDataContext(@Nullable VirtualFile directory, @Nullable Component focusOwner, - @Nullable AnActionEvent event) { + @Nullable AnActionEvent event, + @Nullable Module module, + @NotNull Project project) { HashMap map = ContainerUtil.newHashMap(); if (directory != null) { map.put(CommonDataKeys.VIRTUAL_FILE.getName(), directory); @@ -479,6 +483,12 @@ public class RunAnythingAction extends AnAction implements CustomComponentAction map.put(FOCUS_COMPONENT_KEY_NAME.getName(), focusOwner); } + if (module != null) { + map.put(LangDataKeys.MODULE.getName(), module); + } + + map.put(CommonDataKeys.PROJECT.getName(), project); + return SimpleDataContext.getSimpleContext(map, DataContext.EMPTY_CONTEXT); } diff --git a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingActionItem.java b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingActionItem.java index abd3cf72180c..d371f5cebc42 100644 --- a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingActionItem.java +++ b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingActionItem.java @@ -3,6 +3,7 @@ package org.jetbrains.plugins.ruby.ruby.actions; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; import com.intellij.openapi.project.Project; import com.intellij.util.ObjectUtils; @@ -22,9 +23,10 @@ public class RunAnythingActionItem extends RunAnythingItem { } @Override - public void run(@NotNull Project project, @NotNull DataContext dataContext) { + public void run(@NotNull DataContext dataContext) { Component focusOwner = dataContext.getData(RunAnythingAction.FOCUS_COMPONENT_KEY_NAME); AnActionEvent event = dataContext.getData(RunAnythingAction.RUN_ANYTHING_EVENT_KEY); + Project project = dataContext.getData(CommonDataKeys.PROJECT); RunAnythingUtil.performRunAnythingAction(myAction, project, focusOwner, event); } diff --git a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingCommandItem.java b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingCommandItem.java index 435362dcecac..2eb60730a45c 100644 --- a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingCommandItem.java +++ b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingCommandItem.java @@ -7,38 +7,27 @@ import com.intellij.execution.runners.ExecutionEnvironmentBuilder; import com.intellij.execution.util.ExecUtil; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.actionSystem.LangDataKeys; -import com.intellij.openapi.actionSystem.impl.SimpleDataContext; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; -import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.SystemInfoRt; -import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.registry.Registry; -import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.containers.ContainerUtil; -import com.intellij.util.execution.ParametersListUtil; import icons.RubyIcons; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.plugins.ruby.RBundle; -import org.jetbrains.plugins.ruby.gem.GemsDataKeys; -import org.jetbrains.plugins.ruby.remote.RubyRemoteInterpreterManager; -import org.jetbrains.plugins.ruby.ruby.RModuleUtil; +import org.jetbrains.plugins.ruby.ruby.actions.commands.RunAnythingCommandCustomizer; import org.jetbrains.plugins.ruby.ruby.actions.execution.RunAnythingRunProfile; -import org.jetbrains.plugins.ruby.ruby.run.RubyAbstractRunner; -import org.jetbrains.plugins.ruby.rvm.RVMSupportUtil; -import org.jetbrains.plugins.ruby.utils.OSUtil; -import org.jetbrains.plugins.ruby.version.management.rbenv.gemsets.RbenvGemsetManager; import javax.swing.*; import java.awt.*; import java.io.File; -import java.util.*; +import java.util.Collection; import java.util.List; +import java.util.Objects; public class RunAnythingCommandItem extends RunAnythingItem { private static final Logger LOG = Logger.getInstance(RunAnythingCommandItem.class); @@ -54,62 +43,33 @@ public class RunAnythingCommandItem extends RunAnythingItem { } @Override - public void run(@NotNull Project project, @NotNull DataContext dataContext) { - super.run(project, dataContext); + public void run(@NotNull DataContext dataContext) { + super.run(dataContext); VirtualFile workDirectory = dataContext.getData(CommonDataKeys.VIRTUAL_FILE); Executor executor = dataContext.getData(RunAnythingAction.EXECUTOR_KEY); LOG.assertTrue(workDirectory != null); LOG.assertTrue(executor != null); - runCommand(workDirectory, project, myCommandLine, myModule, executor); + runCommand(workDirectory, myCommandLine, executor, dataContext); } public static void runCommand(@NotNull VirtualFile workDirectory, - @NotNull Project project, @NotNull String commandString, - @Nullable Module module, - @NotNull Executor executor) { + @NotNull Executor executor, + @NotNull DataContext dataContext) { + final Project project = CommonDataKeys.PROJECT.getData(dataContext); + LOG.assertTrue(project != null); + Collection commands = RunAnythingCache.getInstance(project).getState().getCommands(); commands.remove(commandString); commands.add(commandString); - Sdk sdk = RModuleUtil.getInstance().findRubySdkForModule(module); - - GeneralCommandLine commandLine = new GeneralCommandLine().withParentEnvironmentType(GeneralCommandLine.ParentEnvironmentType.CONSOLE); - - String command = commandString; - Map env = ContainerUtil.newHashMap(commandLine.getEffectiveEnvironment()); - if (sdk != null && !RubyRemoteInterpreterManager.getInstance().isRemoteSdk(sdk)) { - if (RVMSupportUtil.isRVMInterpreter(sdk)) { - command = getRVMAwareCommand(sdk, commandString, project); - } - else if (RbenvGemsetManager.isRbenvSdk(sdk)) { - command = getRbenvAwareCommand(sdk, env, commandString, project, module); - } - else { - command = getRubyAwareCommand(sdk, env, commandString); - } - } - - List shellCommand = ContainerUtil.newArrayList(getShellCommand()); - if (shellCommand.isEmpty()) { - shellCommand = ParametersListUtil.parse(command, false, true); - } - else { - shellCommand.add(command); - } - - commandLine = new GeneralCommandLine(shellCommand) - .withEnvironment(env) - .withWorkDirectory(workDirectory.getPath()); - - HashMap dataMap = new HashMap<>(); - dataMap.put(LangDataKeys.MODULE.getName(), module); - dataMap.put(GemsDataKeys.SDK.getName(), sdk); + dataContext = RunAnythingCommandCustomizer.customizeContext(dataContext); + GeneralCommandLine commandLine = RunAnythingCommandCustomizer.customizeCommandLine(dataContext, workDirectory, commandString); try { ExecutionEnvironmentBuilder.create(project, executor, new RunAnythingRunProfile(commandLine, commandString)) - .dataContext(SimpleDataContext.getSimpleContext(dataMap, DataContext.EMPTY_CONTEXT)) + .dataContext(dataContext) .buildAndExecute(); } catch (ExecutionException e) { @@ -119,7 +79,7 @@ public class RunAnythingCommandItem extends RunAnythingItem { } @NotNull - private static List getShellCommand() { + public static List getShellCommand() { if (SystemInfoRt.isWindows) return ContainerUtil.immutableList(ExecUtil.getWindowsShellName(), "/c"); String shell = System.getenv("SHELL"); @@ -137,50 +97,6 @@ public class RunAnythingCommandItem extends RunAnythingItem { return commands; } - private static String getRubyAwareCommand(@NotNull Sdk sdk, @NotNull Map env, @NotNull String commandLine) { - VirtualFile sdkHomeDirectory = sdk.getHomeDirectory(); - if (sdkHomeDirectory == null) return commandLine; - - VirtualFile parent = sdkHomeDirectory.getParent(); - if (parent == null) return commandLine; - - final String path = FileUtil.toSystemDependentName(parent.getPath()); - final String envName = OSUtil.getPathEnvVariableName(); - final String newPath = OSUtil.prependToPathEnvVariable(env.get(envName), path); - env.put(envName, newPath); - - return commandLine; - } - - private static String getRbenvAwareCommand(@NotNull Sdk sdk, - @NotNull Map env, - @NotNull String commandLine, - @NotNull Project project, - @Nullable Module module) { - String exeCommand = commandLine.contains(" ") ? StringUtil.substringBefore(commandLine, " ") : commandLine; - String shimsExec = RbenvGemsetManager.getShimsCommandPath(Objects.requireNonNull(exeCommand)); - if (shimsExec == null || !RunAnythingCache.getInstance(project).CAN_RUN_RBENV) return commandLine; - - RubyAbstractRunner.patchRbenvEnv(env, module, sdk); - - return shimsExec + (commandLine.contains(" ") ? " " + StringUtil.substringAfter(commandLine, " ") : ""); - } - - @NotNull - private static String getRVMAwareCommand(@NotNull Sdk sdk, @NotNull String commandLine, @NotNull Project project) { - if (commandLine.startsWith("rvm ")) return commandLine; - - String version = RVMSupportUtil.getRVMSdkVersion(sdk); - String gemset = RVMSupportUtil.getGemset(sdk); - - if (version == null) return commandLine; - if (gemset != null) version += '@' + gemset; - - if (!RunAnythingCache.getInstance(project).CAN_RUN_RVM) return commandLine; - - return "rvm " + version + " do " + commandLine; - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingItem.java b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingItem.java index e16f6ae715ab..6e401fd08e22 100644 --- a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingItem.java +++ b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingItem.java @@ -1,7 +1,6 @@ package org.jetbrains.plugins.ruby.ruby.actions; import com.intellij.openapi.actionSystem.DataContext; -import com.intellij.openapi.project.Project; import org.jetbrains.annotations.NotNull; import javax.swing.*; @@ -53,9 +52,9 @@ public abstract class RunAnythingItem { /** * Executes specific action on choosing current item in the list * - * @param dataContext Use {@link DataContext} to extract focus owner component, original action event, working directory + * @param dataContext Use {@link DataContext} to extract focus owner component, original action event, working directory, module and project */ - public void run(@NotNull Project project, @NotNull DataContext dataContext) { + public void run(@NotNull DataContext dataContext) { triggerUsage(); } } diff --git a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingRunConfigurationItem.java b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingRunConfigurationItem.java index 69c5918d4b78..d1d08b6d9cc0 100644 --- a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingRunConfigurationItem.java +++ b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/RunAnythingRunConfigurationItem.java @@ -4,7 +4,9 @@ import com.intellij.execution.Executor; import com.intellij.execution.RunnerAndConfigurationSettings; import com.intellij.execution.actions.ChooseRunConfigurationPopup; import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.util.ObjectUtils; import org.jetbrains.annotations.NotNull; @@ -14,6 +16,7 @@ import java.awt.*; import java.util.Objects; public class RunAnythingRunConfigurationItem extends RunAnythingItem { + private static final Logger LOG = Logger.getInstance(RunAnythingRunConfigurationItem.class); static final String RUN_ANYTHING_RUN_CONFIGURATION_AD_TEXT = RunAnythingAction.AD_MODULE_CONTEXT + " , " + RunAnythingAction.AD_DEBUG_TEXT; @NotNull private final ChooseRunConfigurationPopup.ItemWrapper myWrapper; @@ -23,8 +26,10 @@ public class RunAnythingRunConfigurationItem extends RunAnythingItem env = ContainerUtil.newHashMap(commandLine.getEffectiveEnvironment()); + if (sdk != null && !RubyRemoteInterpreterManager.getInstance().isRemoteSdk(sdk)) { + if (RVMSupportUtil.isRVMInterpreter(sdk)) { + command = getRVMAwareCommand(sdk, command, project); + } + else if (RbenvGemsetManager.isRbenvSdk(sdk)) { + command = getRbenvAwareCommand(sdk, env, command, project, module); + } + else { + command = getRubyAwareCommand(sdk, env, command); + } + } + + List shellCommand = ContainerUtil.newArrayList(getShellCommand()); + if (shellCommand.isEmpty()) { + shellCommand = ParametersListUtil.parse(command, false, true); + } + else { + shellCommand.add(command); + } + + commandLine = new GeneralCommandLine(shellCommand) + .withEnvironment(env) + .withWorkDirectory(workDirectory.getPath()); + + return commandLine; + } + + @NotNull + @Override + public DataContext customizeDataContext(@NotNull DataContext dataContext) { + final Module module = LangDataKeys.MODULE.getData(dataContext); + + Sdk sdk = RModuleUtil.getInstance().findRubySdkForModule(module); + HashMap dataMap = new HashMap<>(); + + if (sdk != null) { + dataMap.put(GemsDataKeys.SDK.getName(), sdk); + } + + return SimpleDataContext.getSimpleContext(dataMap, dataContext); + } + + private static String getRubyAwareCommand(@NotNull Sdk sdk, @NotNull Map env, @NotNull String commandLine) { + VirtualFile sdkHomeDirectory = sdk.getHomeDirectory(); + if (sdkHomeDirectory == null) return commandLine; + + VirtualFile parent = sdkHomeDirectory.getParent(); + if (parent == null) return commandLine; + + final String path = FileUtil.toSystemDependentName(parent.getPath()); + final String envName = OSUtil.getPathEnvVariableName(); + final String newPath = OSUtil.prependToPathEnvVariable(env.get(envName), path); + env.put(envName, newPath); + + return commandLine; + } + + private static String getRbenvAwareCommand(@NotNull Sdk sdk, + @NotNull Map env, + @NotNull String commandLine, + @NotNull Project project, + @Nullable Module module) { + String exeCommand = commandLine.contains(" ") ? StringUtil.substringBefore(commandLine, " ") : commandLine; + String shimsExec = RbenvGemsetManager.getShimsCommandPath(Objects.requireNonNull(exeCommand)); + if (shimsExec == null || !RunAnythingCache.getInstance(project).CAN_RUN_RBENV) return commandLine; + + RubyAbstractRunner.patchRbenvEnv(env, module, sdk); + + return shimsExec + (commandLine.contains(" ") ? " " + StringUtil.substringAfter(commandLine, " ") : ""); + } + + @NotNull + private static String getRVMAwareCommand(@NotNull Sdk sdk, @NotNull String commandLine, @NotNull Project project) { + if (commandLine.startsWith("rvm ")) return commandLine; + + String version = RVMSupportUtil.getRVMSdkVersion(sdk); + String gemset = RVMSupportUtil.getGemset(sdk); + + if (version == null) return commandLine; + if (gemset != null) version += '@' + gemset; + + if (!RunAnythingCache.getInstance(project).CAN_RUN_RVM) return commandLine; + + return "rvm " + version + " do " + commandLine; + } +} diff --git a/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/commands/RunAnythingCommandCustomizer.java b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/commands/RunAnythingCommandCustomizer.java new file mode 100644 index 000000000000..d4480584d7a9 --- /dev/null +++ b/ruby/ruby-ext/src/org/jetbrains/plugins/ruby/ruby/actions/commands/RunAnythingCommandCustomizer.java @@ -0,0 +1,65 @@ +package org.jetbrains.plugins.ruby.ruby.actions.commands; + +import com.intellij.execution.configurations.GeneralCommandLine; +import com.intellij.openapi.actionSystem.DataContext; +import com.intellij.openapi.extensions.ExtensionPointName; +import com.intellij.openapi.vfs.VirtualFile; +import org.jetbrains.annotations.NotNull; + +/** + * This class customizes 'Run Anything' command line and its data context. + * E.g. it's possible to wrap command into a shell or/and patch environment variables. + */ +public abstract class RunAnythingCommandCustomizer { + public static final ExtensionPointName EP_NAME = + ExtensionPointName.create("org.jetbrains.plugins.ruby.runAnythingCommandCustomizer"); + + /** + * Customizes command line and pass it to others customizers + * + * @param workDirectory the working directory the command will be executed in + * @param dataContext {@link DataContext} to fetch module, project etc. + * @param commandLine command line to be executed + * @return customized command line + */ + @NotNull + public GeneralCommandLine customizeCommandLine(@NotNull VirtualFile workDirectory, + @NotNull DataContext dataContext, + @NotNull GeneralCommandLine commandLine) { + return commandLine; + } + + /** + * Customizes data context and pass it to others providers + * + * @param dataContext {@link DataContext} to fetch module, project etc. + * @return customized {@link DataContext} + */ + @NotNull + public DataContext customizeDataContext(@NotNull DataContext dataContext) { + return dataContext; + } + + @NotNull + public static GeneralCommandLine customizeCommandLine(@NotNull DataContext dataContext, + @NotNull VirtualFile workDirectory, + @NotNull String command) { + GeneralCommandLine commandLine = new GeneralCommandLine(command) + .withParentEnvironmentType(GeneralCommandLine.ParentEnvironmentType.CONSOLE); + + for (RunAnythingCommandCustomizer customizer : EP_NAME.getExtensions()) { + commandLine = customizer.customizeCommandLine(workDirectory, dataContext, commandLine); + } + + return commandLine; + } + + @NotNull + public static DataContext customizeContext(@NotNull DataContext dataContext) { + for (RunAnythingCommandCustomizer customizer : EP_NAME.getExtensions()) { + dataContext = customizer.customizeDataContext(dataContext); + } + + return dataContext; + } +} \ No newline at end of file