added setenv method from "c" lib

This commit is contained in:
Sergey Simonchik
2013-01-29 17:20:38 +04:00
parent ecd44b969b
commit eb93725b1f
2 changed files with 51 additions and 84 deletions
@@ -1,44 +1,37 @@
package com.intellij.execution.configurations;
import com.intellij.execution.ExecutionException;
import com.intellij.execution.process.CapturingProcessHandler;
import com.intellij.execution.process.ProcessOutput;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.execution.process.UnixProcessManager;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.CharsetToolkit;
import com.intellij.util.EnvironmentUtil;
import com.intellij.util.containers.ContainerUtil;
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;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
/**
* @author Sergey Simonchik
*/
public class PathEnvironmentVariableUtil {
private static final Logger LOG = Logger.getInstance(PathEnvironmentVariableUtil.class);
public static final String PATH_ENV_VAR_NAME = "PATH";
private static final int BLOCK_TIMEOUT_MILLIS = 50;
private static volatile String ourFixedMacPathEnvVarValue;
private static final String ourFixedMacPathEnvVarValue;
static {
asyncCalcFixedMacPathEnvVarValue();
ourFixedMacPathEnvVarValue = calcFixedMacPathEnvVarValue();
}
private PathEnvironmentVariableUtil() {}
private PathEnvironmentVariableUtil() {
}
/**
* Tries to return a real value for PATH environment variable by parsing the result of
* {@code /usr/libexec/path_helper -s} command execution.
* Tries to return a real value for PATH environment variable.
* Workaround for http://youtrack.jetbrains.com/issue/IDEA-99154
*/
@Nullable
@@ -46,78 +39,17 @@ public class PathEnvironmentVariableUtil {
return ourFixedMacPathEnvVarValue;
}
@Nullable
private static String getOriginalPathEnvVarValue() {
Map<String, String> envVars = EnvironmentUtil.getEnvironmentProperties();
return envVars.get(PATH_ENV_VAR_NAME);
}
private static void asyncCalcFixedMacPathEnvVarValue() {
private static String calcFixedMacPathEnvVarValue() {
if (SystemInfo.isMac) {
final String originalValue = getOriginalPathEnvVarValue();
final Semaphore semaphore = new Semaphore(0, true);
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@SuppressWarnings("AssignmentToStaticFieldFromInstanceMethod")
@Override
public void run() {
try {
ourFixedMacPathEnvVarValue = findFixedPathEnvVarValue(originalValue);
}
finally {
semaphore.release();
}
}
});
try {
semaphore.tryAcquire(BLOCK_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
}
catch (InterruptedException e) {
LOG.info("Unexpected thread interruption", e);
}
}
}
@Nullable
private static String findFixedPathEnvVarValue(@Nullable String originalValue) {
File executable = new File("/usr/libexec/path_helper");
if (executable.isFile() && executable.canExecute()) {
GeneralCommandLine commandLine = new GeneralCommandLine();
try {
commandLine.setExePath(executable.getAbsolutePath());
commandLine.addParameter("-s");
List<String> stdout = executeAndGetStdout(commandLine);
final String prefix = "PATH=\"";
final String suffix = "\"; export PATH;";
for (String line : stdout) {
if (line.startsWith(prefix) && line.endsWith(suffix)) {
String value = line.substring(prefix.length(), line.length() - suffix.length());
return mergePaths(ContainerUtil.newArrayList(originalValue, value));
}
}
} catch (Exception e) {
LOG.info("Can't execute '" + commandLine.getCommandLineString() + "'", e);
}
Map<String, String> originalEnvVars = EnvironmentUtil.getEnvironmentProperties();
final String originalPath = originalEnvVars.get(PATH_ENV_VAR_NAME);
Map<? extends String, ? extends String> envVars = UnixProcessManager.getOrLoadConsoleEnvironment();
String consolePath = envVars.get(PATH_ENV_VAR_NAME);
return mergePaths(ContainerUtil.newArrayList(originalPath, consolePath));
}
return null;
}
@NotNull
public static List<String> executeAndGetStdout(@NotNull GeneralCommandLine commandLine) throws ExecutionException {
final Process process = commandLine.createProcess();
CapturingProcessHandler processHandler = new CapturingProcessHandler(process, CharsetToolkit.UTF8_CHARSET);
ProcessOutput output = processHandler.runProcess(2000);
int exitCode = output.getExitCode();
if (exitCode != 0) {
throw new ExecutionException("Exit code of '" + commandLine.getCommandLineString()
+ "' is " + exitCode);
}
if (!output.getStderr().isEmpty()) {
throw new ExecutionException("Stderr of '" + commandLine.getCommandLineString()
+ "': " + output.getStderr());
}
return output.getStdoutLines();
}
@Nullable
private static String mergePaths(@NotNull List<String> pathStrings) {
LinkedHashSet<String> paths = ContainerUtil.newLinkedHashSet();
@@ -135,4 +67,24 @@ 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) {
}
}
}
@@ -88,6 +88,21 @@ 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)");
@@ -290,10 +305,10 @@ public class UnixProcessManager {
}
public interface CLib extends Library {
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 {