mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-23 17:05:26 +02:00
Bug 564123 refactor terminal Env to use same code as EnvironmentReader
Env had a very old way of reading environment variables from before Java supported environemnt variables from System. This commit makes the code the same as core CDT's EnvironmentReader. Env holds a copy of the EnvironmentReader code to avoid dependency of terminal to other CDT. Change-Id: I8929bf427af99d3d62cca28ee8090aa423c9aded Signed-off-by: jantje <eclipse@baeyens.it>
This commit is contained in:
parent
3516a46a92
commit
65473abf07
2 changed files with 43 additions and 173 deletions
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.tm.terminal.view.core;singleton:=true
|
||||
Bundle-Version: 4.6.0.qualifier
|
||||
Bundle-Version: 4.6.100.qualifier
|
||||
Bundle-Activator: org.eclipse.tm.terminal.view.core.activator.CoreBundleActivator
|
||||
Bundle-Vendor: %providerName
|
||||
Require-Bundle: org.eclipse.core.expressions;bundle-version="3.4.400",
|
||||
|
|
|
@ -11,33 +11,20 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.view.core.utils;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.eclipse.core.runtime.Assert;
|
||||
import org.eclipse.core.runtime.Platform;
|
||||
import org.eclipse.osgi.service.environment.Constants;
|
||||
|
||||
/**
|
||||
* Environment handling utility methods.
|
||||
*/
|
||||
public class Env {
|
||||
|
||||
// Reference to the monitor to lock if determining the native environment
|
||||
private final static Object ENV_GET_MONITOR = new Object();
|
||||
|
||||
// Reference to the native environment with the case of the variable names preserved
|
||||
private static Map<String, String> nativeEnvironmentCasePreserved = null;
|
||||
|
||||
/**
|
||||
* Returns the merged environment of the native environment and the passed
|
||||
* in environment. Passed in variables will overwrite the native environment
|
||||
|
@ -54,187 +41,70 @@ public class Env {
|
|||
* @return The merged environment.
|
||||
*/
|
||||
public static String[] getEnvironment(String[] envp, boolean terminal) {
|
||||
// Get the cached native environment
|
||||
Map<String, String> nativeEnv = getNativeEnvironmentCasePreserved();
|
||||
// Make a copy of the native environment so it can be manipulated without changing
|
||||
// the cached environment
|
||||
Map<String, String> env = new LinkedHashMap<String, String>(nativeEnv);
|
||||
// Set the TERM environment variable if in terminal mode
|
||||
if (terminal)
|
||||
env.put("TERM", "xterm"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
// On Windows, the environment variable names are not case-sensitive. However,
|
||||
// we desire to preserve the original case. Build up a translation map between
|
||||
// an all lowercase name and the original environment name
|
||||
Map<String, String> k2n = null;
|
||||
if (Platform.OS_WIN32.equals(Platform.getOS())) {
|
||||
k2n = new HashMap<String, String>();
|
||||
for (String name : env.keySet()) {
|
||||
k2n.put(name.toLowerCase(), name);
|
||||
}
|
||||
}
|
||||
// Get a copy of the native environment variables
|
||||
Properties environmentVariables = getEnvVars();
|
||||
|
||||
// If a "local" environment is provided, merge it with the native
|
||||
// environment.
|
||||
if (envp != null) {
|
||||
for (int i = 0; i < envp.length; i++) {
|
||||
// The full provided variable in form "name=value"
|
||||
String envpPart = envp[i];
|
||||
// Split the variable
|
||||
int eqIdx = envpPart.indexOf('=');
|
||||
if (eqIdx < 1)
|
||||
continue;
|
||||
String name = envpPart.substring(0, eqIdx);
|
||||
// Map the variable name to the real environment name (Windows only)
|
||||
if (Platform.OS_WIN32.equals(Platform.getOS())) {
|
||||
if (k2n.containsKey(name.toLowerCase())) {
|
||||
String candidate = k2n.get(name.toLowerCase());
|
||||
Assert.isNotNull(candidate);
|
||||
name = candidate;
|
||||
}
|
||||
// Filter out environment variables with bad names
|
||||
if ("".equals(name.trim()) || name.contains(":")) { //$NON-NLS-1$ //$NON-NLS-2$
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Get the variable value
|
||||
String value = envpPart.substring(eqIdx + 1);
|
||||
// Don't overwrite the TERM variable if in terminal mode
|
||||
if (terminal && "TERM".equals(name)) //$NON-NLS-1$
|
||||
continue;
|
||||
// If a variable with the name does not exist, just append it
|
||||
if (!env.containsKey(name) && !"<unset>".equals(value)) { //$NON-NLS-1$
|
||||
env.put(name, value);
|
||||
} else if (env.containsKey(name)) {
|
||||
// If the value contains the special placeholder "<unset>", remove the variable from the environment
|
||||
if ("<unset>".equals(value)) {//$NON-NLS-1$
|
||||
env.remove(name);
|
||||
for (String keyValue : envp) {
|
||||
// keyValue is the full provided variable in form "name=value"
|
||||
String[] parts = keyValue.split("=", 2); //$NON-NLS-1$
|
||||
if (parts.length == 2) {
|
||||
String name = parts[0];
|
||||
String value = parts[1];
|
||||
|
||||
if ("<unset>".equals(value)) { //$NON-NLS-1$
|
||||
environmentVariables.remove(name);
|
||||
} else {
|
||||
// A variable with the name already exist, check if the value is different
|
||||
String oldValue = env.get(name);
|
||||
if (oldValue != null && !oldValue.equals(value) || oldValue == null && value != null) {
|
||||
env.put(name, value);
|
||||
}
|
||||
environmentVariables.put(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Set the TERM environment variable if in terminal mode
|
||||
if (terminal)
|
||||
environmentVariables.put("TERM", "xterm");//$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
// Convert into an array of strings
|
||||
List<String> keys = new ArrayList<String>(env.keySet());
|
||||
List<String> keys = new ArrayList<>(environmentVariables.stringPropertyNames());
|
||||
// On Windows hosts, sort the environment keys
|
||||
if (Platform.OS_WIN32.equals(Platform.getOS()))
|
||||
Collections.sort(keys);
|
||||
Iterator<String> iter = keys.iterator();
|
||||
List<String> strings = new ArrayList<String>(env.size());
|
||||
StringBuilder buffer = null;
|
||||
while (iter.hasNext()) {
|
||||
String key = iter.next();
|
||||
buffer = new StringBuilder(key);
|
||||
buffer.append('=').append(env.get(key));
|
||||
strings.add(buffer.toString());
|
||||
List<String> strings = new ArrayList<>(keys.size());
|
||||
for (String key : keys) {
|
||||
String value = environmentVariables.getProperty(key);
|
||||
strings.add(key + "=" + value); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
return strings.toArray(new String[strings.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the native environment.
|
||||
*
|
||||
* @return The native environment, or an empty map.
|
||||
*/
|
||||
private static Map<String, String> getNativeEnvironmentCasePreserved() {
|
||||
synchronized (ENV_GET_MONITOR) {
|
||||
if (nativeEnvironmentCasePreserved == null) {
|
||||
nativeEnvironmentCasePreserved = new LinkedHashMap<String, String>();
|
||||
cacheNativeEnvironment(nativeEnvironmentCasePreserved);
|
||||
//WARNING
|
||||
//Below is a copy of org.eclipse.cdt.utils.spawner.EnvironmentReader to make the terminal independent from CDT
|
||||
//This is supposed to be a straight copy (no modifications)
|
||||
//except for making getEnvVars private to avoid errors/warnings
|
||||
private static Properties envVars;
|
||||
private static List<String> toUppercaseEnvironmentVars = Arrays.asList("PATH"); //$NON-NLS-1$
|
||||
|
||||
static {
|
||||
boolean isWindows = Platform.OS_WIN32.equals(Platform.getOS());
|
||||
envVars = new Properties();
|
||||
Map<String, String> envMap = System.getenv();
|
||||
for (Map.Entry<String, String> curEnvVar : envMap.entrySet()) {
|
||||
String key = curEnvVar.getKey();
|
||||
String value = curEnvVar.getValue();
|
||||
if (isWindows && toUppercaseEnvironmentVars.contains(key.toUpperCase())) {
|
||||
key = key.toUpperCase();
|
||||
}
|
||||
return new LinkedHashMap<String, String>(nativeEnvironmentCasePreserved);
|
||||
envVars.setProperty(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the native environment and store it to the specified cache.
|
||||
*
|
||||
* @param cache The environment cache. Must not be <code>null</code>.
|
||||
* @return a clone of the list of environment variables.
|
||||
*/
|
||||
private static void cacheNativeEnvironment(Map<String, String> cache) {
|
||||
Assert.isNotNull(cache);
|
||||
|
||||
try {
|
||||
String nativeCommand = null;
|
||||
if (Platform.getOS().equals(Constants.OS_WIN32)) {
|
||||
nativeCommand = "cmd.exe /C set"; //$NON-NLS-1$
|
||||
} else if (!Platform.getOS().equals(Constants.OS_UNKNOWN)) {
|
||||
nativeCommand = "env"; //$NON-NLS-1$
|
||||
}
|
||||
if (nativeCommand == null) {
|
||||
return;
|
||||
}
|
||||
Process process = Runtime.getRuntime().exec(nativeCommand);
|
||||
|
||||
// read process directly on other platforms
|
||||
// we need to parse out matching '{' and '}' for function declarations in .bash environments
|
||||
// pattern is [function name]=() { and we must find the '}' on its own line with no trailing ';'
|
||||
InputStream stream = process.getInputStream();
|
||||
InputStreamReader isreader = new InputStreamReader(stream);
|
||||
BufferedReader reader = new BufferedReader(isreader);
|
||||
try {
|
||||
String line = reader.readLine();
|
||||
while (line != null) {
|
||||
String key = null;
|
||||
String value = null;
|
||||
int func = line.indexOf("=()"); //$NON-NLS-1$
|
||||
if (func > 0) {
|
||||
key = line.substring(0, func);
|
||||
// scan until we find the closing '}' with no following chars
|
||||
value = line.substring(func + 1);
|
||||
do {
|
||||
line = reader.readLine();
|
||||
if (line == null)
|
||||
break;
|
||||
if (line.equals("}")) //$NON-NLS-1$
|
||||
value += ';';
|
||||
value += ' ' + line;
|
||||
} while (!line.equals("}")); //$NON-NLS-1$
|
||||
line = reader.readLine();
|
||||
} else {
|
||||
int separator = line.indexOf('=');
|
||||
if (separator > 0) {
|
||||
key = line.substring(0, separator);
|
||||
value = line.substring(separator + 1);
|
||||
StringBuilder bufValue = new StringBuilder(value);
|
||||
line = reader.readLine();
|
||||
if (line != null) {
|
||||
// this line has a '=' read ahead to check next line for '=', might be broken on more
|
||||
// than one line
|
||||
separator = line.indexOf('=');
|
||||
while (separator < 0) {
|
||||
bufValue.append(line.trim());
|
||||
line = reader.readLine();
|
||||
if (line == null) {
|
||||
// if next line read is the end of the file quit the loop
|
||||
break;
|
||||
}
|
||||
separator = line.indexOf('=');
|
||||
}
|
||||
}
|
||||
value = bufValue.toString();
|
||||
}
|
||||
}
|
||||
if (key != null) {
|
||||
cache.put(key, value);
|
||||
} else {
|
||||
line = reader.readLine();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Native environment-fetching code failed.
|
||||
// This can easily happen and is not useful to log.
|
||||
}
|
||||
private static Properties getEnvVars() {
|
||||
return (Properties) envVars.clone();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue