Workaround for IDEA-99154 Mac IDE launcher doesn't pass correct environment variables

This commit is contained in:
Sergey Simonchik
2013-01-30 17:12:58 +04:00
parent 24e17b7bc2
commit 084eb952e7
3 changed files with 97 additions and 37 deletions
@@ -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<String, String> unmodifiable = System.getenv();
Class<?> cu = unmodifiable.getClass();
Field m = cu.getDeclaredField("m");
m.setAccessible(true);
Map<String, String> map = (Map<String, String>)m.get(unmodifiable);
if (ourFixedMacPathEnvVarValue != null) {
map.put(PATH_ENV_VAR_NAME, ourFixedMacPathEnvVarValue);
}
}
catch (Exception ignore) {
}
}
}
@@ -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:
* <pre>Cannot run program ...: error=2, No such file or directory</pre>
* that occurs when {@code exePath} isn't absolute path, so {@code exePath} is searched in PATH environment variable. <p/>
*
* There is OSX specific issue that environment variables aren't passed to IDE, if the IDE isn't launched from Terminal.
* See <a href="http://youtrack.jetbrains.com/issue/IDEA-99154">IDEA-99154</a> . <p/>
*
* The workaround for OSX is to execute the command inside shell.
* For example if {@code exePath} is {@code "nodemon"}, standby command would be:
* <pre>
* /bin/bash -c "nodemon"
* </pre>
*
* 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,
@@ -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 {