diff --git a/plugins/sh/resources/META-INF/plugin.xml b/plugins/sh/resources/META-INF/plugin.xml
index 7cfd92e05b12..a1d9ec14b4e0 100644
--- a/plugins/sh/resources/META-INF/plugin.xml
+++ b/plugins/sh/resources/META-INF/plugin.xml
@@ -37,7 +37,9 @@ Adds support for working with shell script files
+
+
diff --git a/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskProvider.java b/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskProvider.java
new file mode 100644
index 000000000000..ac8ad2cb0246
--- /dev/null
+++ b/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskProvider.java
@@ -0,0 +1,167 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.sh.run;
+
+import com.intellij.execution.BeforeRunTask;
+import com.intellij.execution.BeforeRunTaskProvider;
+import com.intellij.execution.RunnerAndConfigurationSettings;
+import com.intellij.execution.compound.ConfigurationSelectionUtil;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.impl.RunConfigurationBeforeRunProvider;
+import com.intellij.execution.impl.RunManagerImpl;
+import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.actionSystem.DataContext;
+import com.intellij.openapi.components.PersistentStateComponent;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
+import com.intellij.sh.ShLanguage;
+import com.intellij.util.containers.ContainerUtil;
+import icons.SHIcons;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.jetbrains.concurrency.AsyncPromise;
+import org.jetbrains.concurrency.Promise;
+
+import javax.swing.*;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class ShBeforeRunTaskProvider extends BeforeRunTaskProvider {
+ private static final String SH_BEFORE_KEY_PREFIX = "Sh.BeforeRunTask";
+ private static final Key ID = Key.create(SH_BEFORE_KEY_PREFIX);
+ private static final Map> KEY_MAP = new HashMap<>();
+
+ @Override
+ public Key getId() {
+ return ID;
+ }
+
+ @Override
+ public String getName() {
+ return "Run " + ShLanguage.INSTANCE.getID();
+ }
+
+ @Override
+ public String getDescription(ShBeforeRunTask task) {
+ RunnerAndConfigurationSettings configurationSettings = task.getSettings();
+ return configurationSettings != null ? "Run " + ShLanguage.INSTANCE.getID() + " '" + configurationSettings.getName() + "'"
+ : "Run " + ShLanguage.INSTANCE.getID();
+ }
+
+ @Nullable
+ @Override
+ public Icon getIcon() {
+ return SHIcons.ShFile;
+ }
+
+ @Nullable
+ @Override
+ public Icon getTaskIcon(ShBeforeRunTask task) {
+ return SHIcons.ShFile;
+ }
+
+ @Nullable
+ @Override
+ public ShBeforeRunTask createTask(@NotNull RunConfiguration runConfiguration) {
+ return new ShBeforeRunTask(runConfiguration.getProject());
+ }
+
+ @Override
+ public boolean isConfigurable() {
+ return true;
+ }
+
+ @Override
+ public Promise configureTask(@NotNull DataContext context,
+ @NotNull RunConfiguration currentConfig,
+ @NotNull ShBeforeRunTask task) {
+ AsyncPromise result = new AsyncPromise<>();
+ Project project = currentConfig.getProject();
+ if (project == null || !project.isInitialized()) {
+ result.setResult(false);
+ return result;
+ }
+
+ RunManagerImpl runManager = RunManagerImpl.getInstanceImpl(project);
+ List configurations = RunManagerImpl.getInstanceImpl(project).getAllSettings().stream()
+ .map(RunnerAndConfigurationSettings::getConfiguration)
+ .filter(config -> config instanceof ShRunConfiguration && config != currentConfig)
+ .collect(Collectors.toList());
+
+ ConfigurationSelectionUtil.createPopup(project, runManager, configurations, (selectedConfigs, selectedTarget) -> {
+ RunConfiguration selectedConfig = ContainerUtil.getFirstItem(selectedConfigs);
+ RunnerAndConfigurationSettings selectedSettings = selectedConfig == null ? null : runManager.getSettings(selectedConfig);
+
+ if (selectedSettings != null) {
+ task.setSettings(selectedSettings);
+ result.setResult(true);
+ }
+ else {
+ result.setResult(false);
+ }
+ }).showInBestPositionFor(context);
+ return result;
+ }
+
+ @Override
+ public boolean executeTask(@NotNull DataContext context,
+ @NotNull RunConfiguration configuration,
+ @NotNull ExecutionEnvironment env,
+ @NotNull ShBeforeRunTask task) {
+ RunnerAndConfigurationSettings configurationSettings = task.getSettings();
+ if (configurationSettings == null) return false;
+
+ Key userDataKey = getRunBeforeUserDataKey(configurationSettings.getConfiguration());
+ configuration.getProject().putUserData(userDataKey, true);
+ boolean result = RunConfigurationBeforeRunProvider.doExecuteTask(env, configurationSettings, null);
+ configuration.getProject().putUserData(userDataKey, false);
+ return result;
+ }
+
+ static Key getRunBeforeUserDataKey(@NotNull RunConfiguration runConfiguration) {
+ return KEY_MAP.computeIfAbsent(runConfiguration.getName(), key -> Key.create(SH_BEFORE_KEY_PREFIX + "_" + key));
+ }
+
+ static class ShBeforeRunTask extends BeforeRunTask implements PersistentStateComponent {
+ private ShBeforeRunTaskState myState = new ShBeforeRunTaskState();
+ private RunnerAndConfigurationSettings mySettings;
+ private final Project myProject;
+
+ protected ShBeforeRunTask(@NotNull Project project) {
+ super(ID);
+ myProject = project;
+ }
+
+ @Nullable
+ @Override
+ public ShBeforeRunTaskState getState() {
+ return myState;
+ }
+
+ @Override
+ public void loadState(@NotNull ShBeforeRunTaskState state) {
+ state.resetModificationCount();
+ myState = state;
+ }
+
+ public void setSettings(@Nullable RunnerAndConfigurationSettings settings) {
+ mySettings = settings;
+ if (settings == null) {
+ myState.setRunConfigType("");
+ myState.setRunConfigName("");
+ return;
+ }
+ myState.setRunConfigType(settings.getType().getId());
+ myState.setRunConfigName(settings.getName());
+ }
+
+ @Nullable
+ public RunnerAndConfigurationSettings getSettings() {
+ if (mySettings != null) return mySettings;
+ return myState != null && myState.getRunConfigType() != null && myState.getRunConfigName() != null
+ ? mySettings = RunManagerImpl.getInstanceImpl(myProject).findConfigurationByTypeAndName(myState.getRunConfigType(), myState.getRunConfigName())
+ : null;
+ }
+ }
+}
diff --git a/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskState.kt b/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskState.kt
new file mode 100644
index 000000000000..94fef1b2f35a
--- /dev/null
+++ b/plugins/sh/src/com/intellij/sh/run/ShBeforeRunTaskState.kt
@@ -0,0 +1,12 @@
+// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.sh.run
+
+import com.intellij.openapi.components.BaseState
+import com.intellij.util.xmlb.annotations.Attribute
+
+class ShBeforeRunTaskState : BaseState() {
+ @get:Attribute("RUN_CONFIG_TYPE")
+ var runConfigType by string()
+ @get:Attribute("RUN_CONFIG_NAME")
+ var runConfigName by string()
+}
\ No newline at end of file
diff --git a/plugins/sh/src/com/intellij/sh/run/ShRunConfigurationProfileState.java b/plugins/sh/src/com/intellij/sh/run/ShRunConfigurationProfileState.java
index e77a6c566466..59cbb6b70e86 100644
--- a/plugins/sh/src/com/intellij/sh/run/ShRunConfigurationProfileState.java
+++ b/plugins/sh/src/com/intellij/sh/run/ShRunConfigurationProfileState.java
@@ -1,11 +1,7 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.sh.run;
-import com.intellij.execution.DefaultExecutionResult;
-import com.intellij.execution.ExecutionException;
-import com.intellij.execution.ExecutionResult;
-import com.intellij.execution.Executor;
-import com.intellij.execution.Platform;
+import com.intellij.execution.*;
import com.intellij.execution.configurations.GeneralCommandLine;
import com.intellij.execution.configurations.PtyCommandLine;
import com.intellij.execution.configurations.RunProfileState;
@@ -16,6 +12,7 @@ import com.intellij.execution.runners.ProgramRunner;
import com.intellij.execution.ui.ConsoleView;
import com.intellij.openapi.components.ServiceManager;
import com.intellij.openapi.project.Project;
+import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
@@ -32,7 +29,6 @@ import java.util.Arrays;
import static com.intellij.sh.ShStringUtil.quote;
public class ShRunConfigurationProfileState implements RunProfileState {
- private static final String WHITESPACE = " ";
private final Project myProject;
private final ShRunConfiguration myRunConfiguration;
@@ -44,8 +40,11 @@ public class ShRunConfigurationProfileState implements RunProfileState {
@Nullable
@Override
public ExecutionResult execute(Executor executor, @NotNull ProgramRunner runner) throws ExecutionException {
+ Key userDataKey = ShBeforeRunTaskProvider.getRunBeforeUserDataKey(myRunConfiguration);
+ Boolean userDataValue = myProject.getUserData(userDataKey);
+ boolean isRunBeforeConfig = userDataValue != null && userDataValue.booleanValue();
ShRunner shRunner = ServiceManager.getService(myProject, ShRunner.class);
- if (shRunner == null || !shRunner.isAvailable(myProject)) {
+ if (shRunner == null || !shRunner.isAvailable(myProject) || isRunBeforeConfig) {
return buildExecutionResult();
}
shRunner.run(buildCommand(), myRunConfiguration.getScriptWorkingDirectory());