1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IProcessEnvironment, isWindows } from 'vs/base/common/platform';
import { EnvironmentVariableMutatorType, IEnvironmentVariableCollection, IExtensionOwnedEnvironmentVariableMutator, IMergedEnvironmentVariableCollection, IMergedEnvironmentVariableCollectionDiff } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { VariableResolver } from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
export class MergedEnvironmentVariableCollection implements IMergedEnvironmentVariableCollection {
readonly map: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> = new Map();
constructor(collections: Map<string, IEnvironmentVariableCollection>) {
collections.forEach((collection, extensionIdentifier) => {
const it = collection.map.entries();
let next = it.next();
while (!next.done) {
const variable = next.value[0];
let entry = this.map.get(variable);
if (!entry) {
entry = [];
this.map.set(variable, entry);
}
// If the first item in the entry is replace ignore any other entries as they would
// just get replaced by this one.
if (entry.length > 0 && entry[0].type === EnvironmentVariableMutatorType.Replace) {
next = it.next();
continue;
}
// Mutators get applied in the reverse order than they are created
const mutator = next.value[1];
entry.unshift({
extensionIdentifier,
value: mutator.value,
type: mutator.type
});
next = it.next();
}
});
}
async applyToProcessEnvironment(env: IProcessEnvironment, variableResolver?: VariableResolver): Promise<void> {
let lowerToActualVariableNames: { [lowerKey: string]: string | undefined } | undefined;
if (isWindows) {
lowerToActualVariableNames = {};
Object.keys(env).forEach(e => lowerToActualVariableNames![e.toLowerCase()] = e);
}
for (const [variable, mutators] of this.map) {
const actualVariable = isWindows ? lowerToActualVariableNames![variable.toLowerCase()] || variable : variable;
for (const mutator of mutators) {
const value = variableResolver ? await variableResolver(mutator.value) : mutator.value;
switch (mutator.type) {
case EnvironmentVariableMutatorType.Append:
env[actualVariable] = (env[actualVariable] || '') + value;
break;
case EnvironmentVariableMutatorType.Prepend:
env[actualVariable] = value + (env[actualVariable] || '');
break;
case EnvironmentVariableMutatorType.Replace:
env[actualVariable] = value;
break;
}
}
}
}
diff(other: IMergedEnvironmentVariableCollection): IMergedEnvironmentVariableCollectionDiff | undefined {
const added: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> = new Map();
const changed: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> = new Map();
const removed: Map<string, IExtensionOwnedEnvironmentVariableMutator[]> = new Map();
// Find added
other.map.forEach((otherMutators, variable) => {
const currentMutators = this.map.get(variable);
const result = getMissingMutatorsFromArray(otherMutators, currentMutators);
if (result) {
added.set(variable, result);
}
});
// Find removed
this.map.forEach((currentMutators, variable) => {
const otherMutators = other.map.get(variable);
const result = getMissingMutatorsFromArray(currentMutators, otherMutators);
if (result) {
removed.set(variable, result);
}
});
// Find changed
this.map.forEach((currentMutators, variable) => {
const otherMutators = other.map.get(variable);
const result = getChangedMutatorsFromArray(currentMutators, otherMutators);
if (result) {
changed.set(variable, result);
}
});
if (added.size === 0 && changed.size === 0 && removed.size === 0) {
return undefined;
}
return { added, changed, removed };
}
}
function getMissingMutatorsFromArray(
current: IExtensionOwnedEnvironmentVariableMutator[],
other: IExtensionOwnedEnvironmentVariableMutator[] | undefined
): IExtensionOwnedEnvironmentVariableMutator[] | undefined {
// If it doesn't exist, all are removed
if (!other) {
return current;
}
// Create a map to help
const otherMutatorExtensions = new Set<string>();
other.forEach(m => otherMutatorExtensions.add(m.extensionIdentifier));
// Find entries removed from other
const result: IExtensionOwnedEnvironmentVariableMutator[] = [];
current.forEach(mutator => {
if (!otherMutatorExtensions.has(mutator.extensionIdentifier)) {
result.push(mutator);
}
});
return result.length === 0 ? undefined : result;
}
function getChangedMutatorsFromArray(
current: IExtensionOwnedEnvironmentVariableMutator[],
other: IExtensionOwnedEnvironmentVariableMutator[] | undefined
): IExtensionOwnedEnvironmentVariableMutator[] | undefined {
// If it doesn't exist, none are changed (they are removed)
if (!other) {
return undefined;
}
// Create a map to help
const otherMutatorExtensions = new Map<string, IExtensionOwnedEnvironmentVariableMutator>();
other.forEach(m => otherMutatorExtensions.set(m.extensionIdentifier, m));
// Find entries that exist in both but are not equal
const result: IExtensionOwnedEnvironmentVariableMutator[] = [];
current.forEach(mutator => {
const otherMutator = otherMutatorExtensions.get(mutator.extensionIdentifier);
if (otherMutator && (mutator.type !== otherMutator.type || mutator.value !== otherMutator.value)) {
// Return the new result, not the old one
result.push(otherMutator);
}
});
return result.length === 0 ? undefined : result;
}
|