diff --git a/images/src/org/intellij/images/actions/EditExternallyAction.java b/images/src/org/intellij/images/actions/EditExternallyAction.java index 945edb5c2e85..db8e0fee6a74 100644 --- a/images/src/org/intellij/images/actions/EditExternallyAction.java +++ b/images/src/org/intellij/images/actions/EditExternallyAction.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,7 +28,7 @@ import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.VfsUtil; +import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.util.EnvironmentUtil; import org.intellij.images.ImagesBundle; @@ -39,7 +39,6 @@ import org.intellij.images.options.impl.OptionsConfigurabe; import java.io.File; import java.util.Map; -import java.util.Set; /** * Open image file externally. @@ -60,9 +59,8 @@ public final class EditExternallyAction extends AnAction { } else { if (files != null) { - Map env = EnvironmentUtil.getEnvironmentProperties(); - Set varNames = env.keySet(); - for (String varName : varNames) { + Map env = EnvironmentUtil.getEnvironmentMap(); + for (String varName : env.keySet()) { if (SystemInfo.isWindows) { executablePath = StringUtil.replace(executablePath, "%" + varName + "%", env.get(varName), true); } @@ -85,7 +83,7 @@ public final class EditExternallyAction extends AnAction { ImageFileTypeManager typeManager = ImageFileTypeManager.getInstance(); for (VirtualFile file : files) { if (file.isInLocalFileSystem() && typeManager.isImage(file)) { - commandLine.addParameter(VfsUtil.virtualToIoFile(file).getAbsolutePath()); + commandLine.addParameter(VfsUtilCore.virtualToIoFile(file).getAbsolutePath()); } } commandLine.setWorkDirectory(new File(executablePath).getParentFile()); @@ -94,9 +92,7 @@ public final class EditExternallyAction extends AnAction { commandLine.createProcess(); } catch (ExecutionException ex) { - Messages.showErrorDialog(project, - ex.getLocalizedMessage(), - ImagesBundle.message("error.title.launching.external.editor")); + Messages.showErrorDialog(project, ex.getLocalizedMessage(), ImagesBundle.message("error.title.launching.external.editor")); OptionsConfigurabe.show(project); } } diff --git a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java index 0ed3764bb5b6..6bb0fa2002a6 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/GeneralCommandLine.java @@ -25,6 +25,7 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.UserDataHolder; 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 com.intellij.util.text.CaseInsensitiveStringHashingStrategy; import gnu.trove.THashMap; @@ -252,8 +253,10 @@ public class GeneralCommandLine implements UserDataHolder { } private void setupEnvironment(final Map environment) { - if (!myPassParentEnvironment) { - environment.clear(); + environment.clear(); + + if (myPassParentEnvironment) { + environment.putAll(EnvironmentUtil.getEnvironmentMap()); } if (!myEnvParams.isEmpty()) { diff --git a/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java b/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java index 87ad2361c067..56e5b43dfc12 100644 --- a/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java +++ b/platform/platform-api/src/com/intellij/execution/configurations/ParametersList.java @@ -22,7 +22,6 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.ArrayUtil; import com.intellij.util.EnvironmentUtil; -import com.intellij.util.containers.ContainerUtil; import com.intellij.util.execution.ParametersListUtil; import gnu.trove.THashMap; import org.jetbrains.annotations.NonNls; @@ -303,7 +302,7 @@ public class ParametersList implements Cloneable { } } } - final Map env = EnvironmentUtil.getEnvironmentProperties(); + final Map env = EnvironmentUtil.getEnvironmentMap(); for (String name : env.keySet()) { final String key = "${" + name + "}"; if (!myMacroMap.containsKey(key)) { diff --git a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java index 8575ab1d0b0f..45398a1617b9 100644 --- a/platform/platform-impl/src/com/intellij/idea/StartupUtil.java +++ b/platform/platform-impl/src/com/intellij/idea/StartupUtil.java @@ -29,6 +29,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.io.win32.IdeaWin32; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.Consumer; +import com.intellij.util.EnvironmentUtil; import com.intellij.util.SystemProperties; import com.intellij.util.text.DateFormatUtilRt; import com.sun.jna.Native; @@ -37,14 +38,13 @@ import org.xerial.snappy.Snappy; import org.xerial.snappy.SnappyLoader; import javax.swing.*; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; -import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.util.*; +import java.util.Arrays; +import java.util.List; /** * @author yole @@ -55,8 +55,6 @@ public class StartupUtil { public static final boolean NO_SNAPPY = SystemProperties.getBooleanProperty("idea.no.snappy", false) || SystemInfo.isMac && SystemInfo.is32Bit; // todo[maxim] drop once available - private static final boolean FIX_MAC_ENV = SystemProperties.getBooleanProperty("idea.fix.mac.env", false); - static boolean isHeadless; private static SocketLock ourLock; @@ -180,101 +178,7 @@ public class StartupUtil { static void fixProcessEnvironment(Logger log) { - if (!SystemInfo.isMac || !FIX_MAC_ENV) return; - - Map envDiff = getEnvironmentDifference(log); - if (!envDiff.isEmpty()) { - updateEnvironment(log, envDiff); - } - } - - private static Map getEnvironmentDifference(Logger log) { - try { - String shell = System.getenv("SHELL"); - if (shell != null && new File(shell).canExecute()) { - String[] command = {shell, "-l", "-c", "/usr/bin/printenv"}; - Process process = Runtime.getRuntime().exec(command); - - InputStream input = process.getInputStream(); - List lines = new ArrayList(); - ByteArrayOutputStream lineBuf = new ByteArrayOutputStream(); - int b; - while ((b = input.read()) >= 0) { - if (b != '\n') { - lineBuf.write(b); - } - else { - String line = new String(lineBuf.toByteArray()); - lines.add(line); - lineBuf = new ByteArrayOutputStream(); - } - } - input.close(); - - int rv; - try { - rv = process.exitValue(); - } - catch (IllegalThreadStateException e) { - process.destroy(); - rv = -1; - } - if (rv != 0 || lines.isEmpty()) { - throw new Exception("rv:" + rv + " lines:" + lines.size()); - } - - Map env = System.getenv(); - Map envDiff = new HashMap(); - Set varsToIgnore = new HashSet(Arrays.asList("_", "PWD", "SHLVL")); - - for (String line : lines) { - int pos = line.indexOf('='); - if (pos > 0) { - String name = line.substring(0, pos); - if (!varsToIgnore.contains(name)) { - String value = line.substring(pos + 1); - if (!env.containsKey(name) || !value.equals(env.get(name))) { - envDiff.put(name, value); - } - } - } - } - - return envDiff; - } - } - catch (Throwable t) { - log.warn("can't get shell environment", t); - } - - return Collections.emptyMap(); - } - - @SuppressWarnings({"PrimitiveArrayArgumentToVariableArgMethod", "SSBasedInspection", "unchecked"}) - private static void updateEnvironment(Logger log, Map envDiff) { - try { - Class envClass = Class.forName("java.lang.ProcessEnvironment"); - Field theEnvironment = envClass.getDeclaredField("theEnvironment"); - theEnvironment.setAccessible(true); - - Class varClass = Class.forName("java.lang.ProcessEnvironment$Variable"); - Method makeVar = varClass.getDeclaredMethod("valueOf", byte[].class); - makeVar.setAccessible(true); - - Class valClass = Class.forName("java.lang.ProcessEnvironment$Value"); - Method makeVal = valClass.getDeclaredMethod("valueOf", byte[].class); - makeVal.setAccessible(true); - - Map envMap = (Map)theEnvironment.get(null); - for (Map.Entry entry : envDiff.entrySet()) { - Object name = makeVar.invoke(null, entry.getKey().getBytes()); - Object value = makeVal.invoke(null, entry.getValue().getBytes()); - envMap.put(name, value); - } - } - catch (Throwable t) { - log.warn("can't update environment", t); - } + log.info("initializing " + EnvironmentUtil.class.getName()); } diff --git a/platform/util/src/com/intellij/execution/process/UnixProcessManager.java b/platform/util/src/com/intellij/execution/process/UnixProcessManager.java index c5fdb7ecb8da..06ecc569329b 100644 --- a/platform/util/src/com/intellij/execution/process/UnixProcessManager.java +++ b/platform/util/src/com/intellij/execution/process/UnixProcessManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2011 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,9 +22,11 @@ import com.intellij.util.Processor; import com.sun.jna.Library; import com.sun.jna.Native; import com.sun.jna.Platform; -import org.jetbrains.annotations.NotNull; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; import java.lang.reflect.Field; import java.util.*; @@ -54,15 +56,7 @@ public class UnixProcessManager { } } - private static Map ourCachedConsoleEnv; - - private UnixProcessManager() { - } - - public static int getProcessPid() { - checkCLib(); - return C_LIB.getpid(); - } + private UnixProcessManager() { } public static int getProcessPid(Process process) { try { @@ -78,11 +72,6 @@ public class UnixProcessManager { } } - public static void sendSignal(Process process, int signal) { - int process_pid = getProcessPid(process); - sendSignal(process_pid, signal); - } - public static void sendSignal(int pid, int signal) { checkCLib(); C_LIB.kill(pid, signal); @@ -109,32 +98,33 @@ public class UnixProcessManager { */ public static boolean sendSignalToProcessTree(Process process, int signal) { try { - checkCLib(); + checkCLib(); - final int our_pid = C_LIB.getpid(); - final int process_pid = getProcessPid(process); + final int our_pid = C_LIB.getpid(); + final int process_pid = getProcessPid(process); - final Ref foundPid = new Ref(); - final ProcessInfo processInfo = new ProcessInfo(); - final List childrenPids = new ArrayList(); + final Ref foundPid = new Ref(); + final ProcessInfo processInfo = new ProcessInfo(); + final List childrenPids = new ArrayList(); - findChildProcesses(our_pid, process_pid, foundPid, processInfo, childrenPids); + findChildProcesses(our_pid, process_pid, foundPid, processInfo, childrenPids); - // result is true if signal was sent to at least one process - final boolean result; - if (!foundPid.isNull()) { - processInfo.killProcTree(foundPid.get(), signal, UNIX_KILLER); - result = true; - } - else { - for (Integer pid : childrenPids) { - processInfo.killProcTree(pid, signal, UNIX_KILLER); + // result is true if signal was sent to at least one process + final boolean result; + if (!foundPid.isNull()) { + processInfo.killProcTree(foundPid.get(), signal, UNIX_KILLER); + result = true; + } + else { + for (Integer pid : childrenPids) { + processInfo.killProcTree(pid, signal, UNIX_KILLER); + } + result = !childrenPids.isEmpty(); //we've tried to kill at least one process } - result = !childrenPids.isEmpty(); //we've tried to kill at least one process - } - return result; - } catch (Exception e) { + return result; + } + catch (Exception e) { //If we fail somehow just return false LOG.warn("Error killing the process", e); return false; @@ -186,7 +176,6 @@ public class UnixProcessManager { public static void processCommandOutput(String[] cmd, Processor processor, boolean skipFirstLine, boolean throwOnError) { try { Process p = Runtime.getRuntime().exec(cmd); - processCommandOutput(p, processor, skipFirstLine, throwOnError); } catch (IOException e) { @@ -194,36 +183,36 @@ public class UnixProcessManager { } } - private static void processCommandOutput(Process psProcess, Processor processor, boolean skipFirstLine, boolean throwOnError) throws IOException { - @SuppressWarnings({"IOResourceOpenedButNotSafelyClosed"}) - BufferedReader stdOutput = new BufferedReader(new - InputStreamReader(psProcess.getInputStream())); - BufferedReader stdError = new BufferedReader(new - InputStreamReader(psProcess.getErrorStream())); - + private static void processCommandOutput(Process process, Processor processor, boolean skipFirstLine, boolean throwOnError) throws IOException { + BufferedReader stdOutput = new BufferedReader(new InputStreamReader(process.getInputStream())); try { - String s; - if (skipFirstLine) { - stdOutput.readLine(); //ps output header - } - while ((s = stdOutput.readLine()) != null) { - processor.process(s); - } + BufferedReader stdError = new BufferedReader(new InputStreamReader(process.getErrorStream())); + try { + if (skipFirstLine) { + stdOutput.readLine(); //ps output header + } + String s; + while ((s = stdOutput.readLine()) != null) { + processor.process(s); + } - StringBuilder errorStr = new StringBuilder(); - while ((s = stdError.readLine()) != null) { - if (s.contains("environment variables being ignored")) { // PY-8160 - continue; + StringBuilder errorStr = new StringBuilder(); + while ((s = stdError.readLine()) != null) { + if (s.contains("environment variables being ignored")) { // PY-8160 + continue; + } + errorStr.append(s).append("\n"); + } + if (throwOnError && errorStr.length() > 0) { + throw new IOException("Error reading ps output:" + errorStr.toString()); } - errorStr.append(s).append("\n"); } - if (throwOnError && errorStr.length() > 0) { - throw new IOException("Error reading ps output:" + errorStr.toString()); + finally { + stdError.close(); } } finally { stdOutput.close(); - stdError.close(); } } @@ -248,42 +237,6 @@ public class UnixProcessManager { } } - @NotNull - public static String readProcEnviron(int child_pid) throws FileNotFoundException { - StringBuffer res = new StringBuffer(); - Scanner s = new Scanner(new File("/proc/" + child_pid + "/environ")); - while (s.hasNextLine()) { - res.append(s).append("\n"); - } - return res.toString(); - } - - public static Map getOrLoadConsoleEnvironment() { - if (ourCachedConsoleEnv == null) { - loadConsoleEnvironment(); - } - return ourCachedConsoleEnv; - } - - private static void loadConsoleEnvironment() { - final Map env = new HashMap(); - final String shell = System.getenv("SHELL"); - if (shell != null && (shell.contains("bash") || shell.contains("zsh"))) { - processCommandOutput(new String[] {shell, "--login", "-c", "printenv"}, new Processor() { - @Override - public boolean process(String s) { - final String[] split = s.split("=", 2); - if (split.length > 1) { - env.put(split[0], split[1]); - } - return false; - } - }, false, false); - } - ourCachedConsoleEnv = !env.isEmpty() ? Collections.unmodifiableMap(env) : System.getenv(); - } - - private interface CLib extends Library { int getpid(); int kill(int pid, int signal); diff --git a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java index 3a07356c5b09..07f6a21b14e4 100644 --- a/platform/util/src/com/intellij/openapi/util/io/FileUtil.java +++ b/platform/util/src/com/intellij/openapi/util/io/FileUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2012 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.text.StringUtil; import com.intellij.util.*; +import com.intellij.util.concurrency.FixedFuture; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.containers.Convertor; import com.intellij.util.io.URLUtil; @@ -345,7 +346,7 @@ public class FileUtil extends FileUtilRt { if (!tempFiles.isEmpty()) { return startDeletionThread(tempFiles.toArray(new File[tempFiles.size()])); } - return new CompletedFuture(); + return new FixedFuture(null); } private static Future startDeletionThread(@NotNull final File... tempFiles) { @@ -1337,6 +1338,28 @@ public class FileUtil extends FileUtilRt { return FileUtilRt.loadText(reader, length); } + @NotNull + public static List loadLines(@NotNull InputStream stream) throws IOException { + //noinspection IOResourceOpenedButNotSafelyClosed + return loadLines(new InputStreamReader(stream)); + } + + @NotNull + public static List loadLines(@NotNull Reader reader) throws IOException { + List lines = new ArrayList(); + BufferedReader bufferedReader = new BufferedReader(reader); + try { + String line; + while ((line = bufferedReader.readLine()) != null) { + lines.add(line); + } + } + finally { + bufferedReader.close(); + } + return lines; + } + @NotNull public static byte[] loadBytes(@NotNull InputStream stream) throws IOException { return FileUtilRt.loadBytes(stream); @@ -1359,28 +1382,4 @@ public class FileUtil extends FileUtilRt { list.add(path.substring(index, path.length())); return list; } - - private static final class CompletedFuture implements Future { - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - public boolean isCancelled() { - return false; - } - - public boolean isDone() { - return true; - } - - @Nullable - public T get() throws InterruptedException, ExecutionException { - return null; - } - - @Nullable - public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { - return null; - } - } } diff --git a/platform/util/src/com/intellij/util/EnvironmentUtil.java b/platform/util/src/com/intellij/util/EnvironmentUtil.java index 1303c471ca2f..82ca97651d05 100644 --- a/platform/util/src/com/intellij/util/EnvironmentUtil.java +++ b/platform/util/src/com/intellij/util/EnvironmentUtil.java @@ -15,41 +15,84 @@ */ package com.intellij.util; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.openapi.util.AtomicNotNullLazyValue; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.util.SystemInfo; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.concurrency.FixedFuture; import com.intellij.util.text.CaseInsensitiveStringHashingStrategy; import gnu.trove.THashMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Collections; -import java.util.Map; +import java.io.File; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; public class EnvironmentUtil { - private static final Map ourEnvironmentProperties; - private static final Map ourEnvironmentVariablesOsSpecific; + private static final Logger LOG = Logger.getInstance("#com.intellij.util.EnvironmentUtil"); + private static final int SHELL_ENV_READING_TIMEOUT = 10000; + + private static final Future> ourEnvGetter; static { - ourEnvironmentProperties = Collections.unmodifiableMap(new ProcessBuilder().environment()); - if (SystemInfo.isWindows) { - ourEnvironmentVariablesOsSpecific = Collections.unmodifiableMap( - new THashMap(ourEnvironmentProperties, CaseInsensitiveStringHashingStrategy.INSTANCE)); + boolean readShellEnv = SystemInfo.isMac && SystemProperties.getBooleanProperty("idea.fix.mac.env", false); // todo: UI setting? + if (readShellEnv) { + ExecutorService executor = Executors.newSingleThreadExecutor(); + ourEnvGetter = executor.submit(new Callable>() { + @Override + public Map call() throws Exception { + return getShellEnv(); + } + }); + executor.shutdown(); } else { - ourEnvironmentVariablesOsSpecific = ourEnvironmentProperties; + ourEnvGetter = new FixedFuture>(System.getenv()); } } + private static final NotNullLazyValue> ourEnvironment = new AtomicNotNullLazyValue>() { + @NotNull + @Override + protected Map compute() { + try { + return ourEnvGetter.get(); + } + catch (Exception e) { + LOG.warn(e); + return System.getenv(); + } + } + }; + + private static final NotNullLazyValue> ourEnvironmentOsSpecific = new AtomicNotNullLazyValue>() { + @NotNull + @Override + protected Map compute() { + Map env = ourEnvironment.getValue(); + if (SystemInfo.isWindows) { + env = Collections.unmodifiableMap(new THashMap(env, CaseInsensitiveStringHashingStrategy.INSTANCE)); + } + return env; + } + }; + private EnvironmentUtil() { } - /** @deprecated use {@link #getEnvironmentProperties()} (to remove in IDEA 14) */ - @SuppressWarnings({"UnusedDeclaration", "SpellCheckingInspection"}) - public static Map getEnviromentProperties() { - return getEnvironmentProperties(); - } - + /** + * Returns the process environment. On Mac OS X, a shell environment is returned if + * todo: some property is set. + * + * @return unmodifiable map of the process environment. + */ @NotNull - public static Map getEnvironmentProperties() { - return ourEnvironmentProperties; + public static Map getEnvironmentMap() { + return ourEnvironment.getValue(); } /** @@ -62,19 +105,125 @@ public class EnvironmentUtil { */ @Nullable public static String getValue(@NotNull String name) { - return ourEnvironmentVariablesOsSpecific.get(name); + return ourEnvironmentOsSpecific.getValue().get(name); } public static String[] getEnvironment() { - return flattenEnvironment(getEnvironmentProperties()); + return flattenEnvironment(getEnvironmentMap()); } public static String[] flattenEnvironment(Map environment) { String[] array = new String[environment.size()]; int i = 0; - for (String name : environment.keySet()) { - array[i++] = name + "=" + environment.get(name); + for (Map.Entry entry : environment.entrySet()) { + array[i++] = entry.getKey() + "=" + entry.getValue(); } return array; } + + @SuppressWarnings("SpellCheckingInspection") + private static Map getShellEnv() { + try { + String shell = System.getenv("SHELL"); + if (shell == null || !new File(shell).canExecute()) { + throw new Exception("shell:" + shell); + } + + String[] command = {shell, "-l", "-c", "/usr/bin/printenv"}; + Process process = Runtime.getRuntime().exec(command); + ProcessKiller processKiller = new ProcessKiller(process); + processKiller.killAfter(SHELL_ENV_READING_TIMEOUT); + List lines = FileUtil.loadLines(process.getInputStream()); + processKiller.stopWaiting(); + int rv = process.exitValue(); + if (rv != 0 || lines.isEmpty()) { + throw new Exception("rv:" + rv + " lines:" + lines.size()); + } + + Set toIgnore = new HashSet(Arrays.asList("_", "PWD", "SHLVL")); + Map env = System.getenv(); + Map newEnv = new HashMap(); + for (String line : lines) { + int pos = line.indexOf('='); + if (pos <= 0) { + LOG.warn("malformed:" + line); + continue; + } + String name = line.substring(0, pos); + if (!toIgnore.contains(name)) { + newEnv.put(name, line.substring(pos + 1)); + } + else if (env.containsKey(name)) { + newEnv.put(name, env.get(name)); + } + } + if (newEnv.size() < lines.size() - toIgnore.size()) { + throw new Exception("env:" + newEnv.size() + " lines:" + lines.size()); + } + + return Collections.unmodifiableMap(newEnv); + } + catch (Throwable t) { + LOG.warn("can't get shell environment", t); + return System.getenv(); + } + } + + private static class ProcessKiller { + private final Process myProcess; + private final Object myWaiter = new Object(); + + public ProcessKiller(Process process) { + myProcess = process; + } + + public void killAfter(long timeout) { + final long stop = System.currentTimeMillis() + timeout; + new Thread() { + @Override + public void run() { + synchronized (myWaiter) { + while (System.currentTimeMillis() < stop) { + try { + myProcess.exitValue(); + break; + } + catch (IllegalThreadStateException ignore) { } + + try { + myWaiter.wait(100); + } + catch (InterruptedException ignore) { } + } + } + + try { + myProcess.exitValue(); + } + catch (IllegalThreadStateException e) { + myProcess.destroy(); + LOG.warn("timed out"); + } + } + }.start(); + } + + public void stopWaiting() { + synchronized (myWaiter) { + myWaiter.notifyAll(); + } + } + } + + /** @deprecated use {@link #getEnvironmentMap()} (to remove in IDEA 14) */ + @SuppressWarnings({"UnusedDeclaration", "SpellCheckingInspection"}) + public static Map getEnviromentProperties() { + return getEnvironmentMap(); + } + + /** @deprecated use {@link #getEnvironmentMap()} (to remove in IDEA 14) */ + @SuppressWarnings({"UnusedDeclaration", "SpellCheckingInspection"}) + public static Map getEnvironmentProperties() { + return getEnvironmentMap(); + } } diff --git a/platform/util/src/com/intellij/util/concurrency/FixedFuture.java b/platform/util/src/com/intellij/util/concurrency/FixedFuture.java new file mode 100644 index 000000000000..0af4e03ee91a --- /dev/null +++ b/platform/util/src/com/intellij/util/concurrency/FixedFuture.java @@ -0,0 +1,54 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.concurrency; + +import org.jetbrains.annotations.NotNull; + +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +public class FixedFuture implements Future { + private final T myValue; + + public FixedFuture(T value) { + myValue = value; + } + + @Override + public boolean cancel(boolean mayInterruptIfRunning) { + return false; + } + + @Override + public boolean isCancelled() { + return false; + } + + @Override + public boolean isDone() { + return true; + } + + @Override + public T get() { + return myValue; + } + + @Override + public T get(long timeout, @NotNull TimeUnit unit) { + return myValue; + } +} diff --git a/platform/util/testSrc/com/intellij/util/EnvironmentUtilTest.java b/platform/util/testSrc/com/intellij/util/EnvironmentUtilTest.java index 9f9c8171ff83..049682efc356 100644 --- a/platform/util/testSrc/com/intellij/util/EnvironmentUtilTest.java +++ b/platform/util/testSrc/com/intellij/util/EnvironmentUtilTest.java @@ -25,9 +25,14 @@ import static org.junit.Assert.assertNotNull; * @since Sep 19, 2002 */ public class EnvironmentUtilTest { + @Test(timeout = 60000) + public void map() throws Exception { + System.setProperty("idea.fix.mac.env", "true"); + assertNotNull(EnvironmentUtil.getEnvironmentMap()); + } + @Test - public void basic() { - assertNotNull(EnvironmentUtil.getEnvironmentProperties()); + public void path() { assertNotNull(EnvironmentUtil.getValue("PATH")); if (SystemInfo.isWindows) { assertNotNull(EnvironmentUtil.getValue("Path")); diff --git a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ConnectionOnProcess.java b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ConnectionOnProcess.java index b866d1cd9136..69110fc00c0a 100644 --- a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ConnectionOnProcess.java +++ b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ConnectionOnProcess.java @@ -21,7 +21,6 @@ import com.intellij.openapi.application.Application; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.vfs.encoding.EncodingManager; -import com.intellij.util.EnvironmentUtil; import com.intellij.util.concurrency.Semaphore; import org.netbeans.lib.cvsclient.connection.AuthenticationException; import org.netbeans.lib.cvsclient.connection.IConnection; @@ -142,8 +141,7 @@ public abstract class ConnectionOnProcess implements IConnection { protected synchronized void execute(GeneralCommandLine commandLine) throws AuthenticationException { try { - commandLine.getEnvironment().clear(); - commandLine.getEnvironment().putAll(EnvironmentUtil.getEnvironmentProperties()); + commandLine.setPassParentEnvironment(true); myProcess = commandLine.createProcess(); myErrThread = new ReadProcessThread( diff --git a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ext/ExtConnection.java b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ext/ExtConnection.java index 3ce20c706b55..f9b797cd1c58 100644 --- a/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ext/ExtConnection.java +++ b/plugins/cvs/cvs-core/src/com/intellij/cvsSupport2/connections/ext/ExtConnection.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -64,11 +64,7 @@ public class ExtConnection extends ConnectionOnProcess { if (isOpen()) throw new RuntimeException(CvsBundle.message("error.message.connection.already.open")); GeneralCommandLine command = createRshCommand(myHost, myUserName, myConfiguration); - - for (String command1 : commands) { - command.addParameter(command1); - } - + command.addParameters(commands); execute(command); if (expectedResult != null) { diff --git a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsoperations/common/CvsOperation.java b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsoperations/common/CvsOperation.java index 7c779f40f915..57d000b54171 100644 --- a/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsoperations/common/CvsOperation.java +++ b/plugins/cvs/cvs-plugin/src/com/intellij/cvsSupport2/cvsoperations/common/CvsOperation.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2009 JetBrains s.r.o. + * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,8 @@ import com.intellij.cvsSupport2.config.CvsApplicationLevelConfiguration; import com.intellij.cvsSupport2.connections.CvsEnvironment; import com.intellij.cvsSupport2.cvshandlers.CvsHandler; import com.intellij.cvsSupport2.errorHandling.CannotFindCvsRootException; +import com.intellij.openapi.util.AtomicNotNullLazyValue; +import com.intellij.openapi.util.NotNullLazyValue; import com.intellij.openapi.vcs.VcsException; import com.intellij.util.EnvironmentUtil; import org.jetbrains.annotations.NotNull; @@ -32,54 +34,30 @@ import java.util.HashMap; import java.util.Map; public abstract class CvsOperation { - private final static String[] ourKnownToCvs = {"CVSIGNORE", - "CVSWRAPPERS", - "CVSREAD", - "CVSREADONLYFS", - "CVSUMASK", + private static final NotNullLazyValue> ourCvsEnvironment = new AtomicNotNullLazyValue>() { + @NotNull + @Override + protected Map compute() { + Map cvsEnv = new HashMap(); - "CVSROOT", - "CVSEDITOR", - "EDITOR", - "VISUAL", - "PATH", - //10 - "HOME", - "HOMEPATH", - "HOMEDRIVE", - "CVS_RSH", - "CVS_SERVER", - - "CVS_PASSFILE", - "CVS_CLIENT_PORT", - "CVS_PROXY_PORT", - "CVS_RCMD_PORT", - "CVS_CLIENT_LOG", - - "CVS_SERVER_SLEEP", - "CVS_IGNORE_REMOTE_ROOT", - "CVS_LOCAL_BRANCH_NUM", - "COMSPEC", - "TMPDIR", - - "CVS_PID", - "COMSPEC", - "CVS_VERIFY_TEMPLATE", - "CVS_NOBASES", - "CVS_SIGN_COMMITS", - - "CVS_VERIFY_CHECKOUTS" - }; - private final static Map ourEnvironmentVariablesMap = new HashMap(); - static { - final Map environmentProperties = EnvironmentUtil.getEnvironmentProperties(); - for (String name : ourKnownToCvs) { - final String value = environmentProperties.get(name); - if (value != null) { - ourEnvironmentVariablesMap.put(name, value); + Map knownToCvs = EnvironmentUtil.getEnvironmentMap(); + @SuppressWarnings("SpellCheckingInspection") String[] toCvs = { + "CVSIGNORE", "CVSWRAPPERS", "CVSREAD", "CVSREADONLYFS", "CVSUMASK", + "CVSROOT", "CVSEDITOR", "EDITOR", "VISUAL", "PATH", "HOME", "HOMEPATH", "HOMEDRIVE", "CVS_RSH", "CVS_SERVER", + "CVS_PASSFILE", "CVS_CLIENT_PORT", "CVS_PROXY_PORT", "CVS_RCMD_PORT", "CVS_CLIENT_LOG", + "CVS_SERVER_SLEEP", "CVS_IGNORE_REMOTE_ROOT", "CVS_LOCAL_BRANCH_NUM", "COMSPEC", "TMPDIR", + "CVS_PID", "COMSPEC", "CVS_VERIFY_TEMPLATE", "CVS_NOBASES", "CVS_SIGN_COMMITS", "CVS_VERIFY_CHECKOUTS" + }; + for (String name : toCvs) { + String value = knownToCvs.get(name); + if (value != null) { + cvsEnv.put(name, value); + } } + + return cvsEnv; } - } + }; private final Collection myFinishActions = new ArrayList(); @@ -100,7 +78,7 @@ public abstract class CvsOperation { protected void modifyOptions(GlobalOptions options) { options.setUseGzip(CvsApplicationLevelConfiguration.getInstance().USE_GZIP); if (CvsApplicationLevelConfiguration.getInstance().SEND_ENVIRONMENT_VARIABLES_TO_SERVER) { - options.setEnvVariables(ourEnvironmentVariablesMap); + options.setEnvVariables(ourCvsEnvironment.getValue()); } }