From 084eb952e70bb692f61b802d22d82e3824470a82 Mon Sep 17 00:00:00 2001 From: Sergey Simonchik Date: Wed, 30 Jan 2013 17:12:58 +0400 Subject: [PATCH] Workaround for IDEA-99154 Mac IDE launcher doesn't pass correct environment variables --- .../PathEnvironmentVariableUtil.java | 21 ---- .../execution/process/ScriptRunnerUtil.java | 97 +++++++++++++++++++ .../execution/process/UnixProcessManager.java | 16 --- 3 files changed, 97 insertions(+), 37 deletions(-) diff --git a/platform/platform-api/src/com/intellij/execution/configurations/PathEnvironmentVariableUtil.java b/platform/platform-api/src/com/intellij/execution/configurations/PathEnvironmentVariableUtil.java index d4d05fa21498..45adbaa61dfe 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/PathEnvironmentVariableUtil.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/PathEnvironmentVariableUtil.java @@ -9,7 +9,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.lang.reflect.Field; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; @@ -67,24 +66,4 @@ public class PathEnvironmentVariableUtil { return StringUtil.join(paths, File.pathSeparator); } - public static void setPathEnvVarAtProcessLevel() { - if (ourFixedMacPathEnvVarValue != null) { - UnixProcessManager.setEnv(PATH_ENV_VAR_NAME, ourFixedMacPathEnvVarValue, true); - } - } - - public static void setPathEnvVarInSystemEnv() { - try { - Map unmodifiable = System.getenv(); - Class cu = unmodifiable.getClass(); - Field m = cu.getDeclaredField("m"); - m.setAccessible(true); - Map map = (Map)m.get(unmodifiable); - if (ourFixedMacPathEnvVarValue != null) { - map.put(PATH_ENV_VAR_NAME, ourFixedMacPathEnvVarValue); - } - } - catch (Exception ignore) { - } - } } diff --git a/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java b/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java index 364c11ddbca6..a3c5bf893181 100644 --- a/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java +++ b/platform/platform-impl/src/com/intellij/execution/process/ScriptRunnerUtil.java @@ -22,6 +22,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.Condition; import com.intellij.openapi.util.Conditions; import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.encoding.EncodingManager; @@ -29,6 +30,8 @@ import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.io.File; + /** * @author Elena Shaverdova * @author Nikolay Matveev @@ -94,6 +97,100 @@ public final class ScriptRunnerUtil { return outputBuilder.toString(); } + @Nullable + private static File getShell() { + final String shell = System.getenv("SHELL"); + if (shell != null && (shell.contains("bash") || shell.contains("zsh"))) { + File file = new File(shell); + if (file.isAbsolute() && file.isFile() && file.canExecute()) { + return file; + } + } + return null; + } + + /** + * Executes a process with given parameters. + * This method tries to work around the following error: + *
Cannot run program ...: error=2, No such file or directory
+ * that occurs when {@code exePath} isn't absolute path, so {@code exePath} is searched in PATH environment variable.

+ * + * There is OSX specific issue that environment variables aren't passed to IDE, if the IDE isn't launched from Terminal. + * See IDEA-99154 .

+ * + * The workaround for OSX is to execute the command inside shell. + * For example if {@code exePath} is {@code "nodemon"}, standby command would be: + *

+   *   /bin/bash -c "nodemon"
+   * 
+ * + * This method is to be removed as IDEA-99154 is fixed. + * + * @param exePath path to executable (it must not be absolute) + * @param workingDirectory + * @param scriptFile + * @param parameters + * @return + * @throws ExecutionException + */ + @NotNull + public static OSProcessHandler executeSafelyOnMac(@NotNull String exePath, + @Nullable String workingDirectory, + @Nullable VirtualFile scriptFile, + @NotNull String[] parameters) throws ExecutionException { + if (!SystemInfo.isMac) { + return execute(exePath, workingDirectory, scriptFile, parameters); + } + ExecutionException firstException; + try { + return execute(exePath, workingDirectory, scriptFile, parameters); + } + catch (ExecutionException e) { + firstException = e; + } + File shell = getShell(); + if (shell == null) { + throw firstException; + } + try { + GeneralCommandLine appCommandLine = new GeneralCommandLine(); + appCommandLine.setExePath(exePath); + if (scriptFile != null) { + appCommandLine.addParameter(scriptFile.getPresentableUrl()); + } + appCommandLine.addParameters(parameters); + + GeneralCommandLine commandLine = new GeneralCommandLine(); + commandLine.setPassParentEnvs(true); + commandLine.setExePath(shell.getAbsolutePath()); + commandLine.addParameter("-c"); + commandLine.addParameter(appCommandLine.getCommandLineString()); + + if (workingDirectory != null) { + commandLine.setWorkDirectory(workingDirectory); + } + + LOG.info("Standby command line: " + commandLine.getCommandLineString()); + + final OSProcessHandler processHandler = new ColoredProcessHandler(commandLine.createProcess(), commandLine.getCommandLineString(), + EncodingManager.getInstance().getDefaultCharset()); + if (LOG.isDebugEnabled()) { + processHandler.addProcessListener(new ProcessAdapter() { + @Override + public void onTextAvailable(ProcessEvent event, Key outputType) { + LOG.debug(outputType + ": " + event.getText()); + } + }); + } + + return processHandler; + } catch (ExecutionException e) { + LOG.info("Standby command failed", e); + throw firstException; + } + } + + @NotNull public static OSProcessHandler execute(@NotNull String exePath, @Nullable String workingDirectory, @Nullable VirtualFile scriptFile, diff --git a/platform/util/src/com/intellij/execution/process/UnixProcessManager.java b/platform/util/src/com/intellij/execution/process/UnixProcessManager.java index 56b6d8e6180b..424dd381a10c 100644 --- a/platform/util/src/com/intellij/execution/process/UnixProcessManager.java +++ b/platform/util/src/com/intellij/execution/process/UnixProcessManager.java @@ -88,21 +88,6 @@ public class UnixProcessManager { C_LIB.kill(pid, signal); } - - /** - * Adds or changes an environment variable. - * @param name string that contains the name of the environment variable to be added or changed - * @param value the value of the environment variable - * @param overwrite change the existing entry. If {@code name} has already been defined and exists in the environment variable table, - * its value will be updated with {@code value}. If {@code name} was previously undefined, it will be appended to the table. - */ - public static void setEnv(@NotNull String name, @NotNull String value, boolean overwrite) { - if (C_LIB != null) { - checkCLib(); - C_LIB.setenv(name, value, overwrite ? 1 : 0); - } - } - private static void checkCLib() { if (C_LIB == null) { throw new IllegalStateException("System is not unix(couldn't load c library)"); @@ -308,7 +293,6 @@ public class UnixProcessManager { private interface CLib extends Library { int getpid(); int kill(int pid, int signal); - int setenv(String name, String value, int overwrite); } public static class ProcessInfo {