-
Notifications
You must be signed in to change notification settings - Fork 29.8k
/
environmentVariableService.ts
119 lines (101 loc) · 5.15 KB
/
environmentVariableService.ts
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
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Event, Emitter } from 'vs/base/common/event';
import { debounce, throttle } from 'vs/base/common/decorators';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { MergedEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableCollection';
import { deserializeEnvironmentVariableCollection, serializeEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariableShared';
import { IEnvironmentVariableCollectionWithPersistence, IEnvironmentVariableService, IMergedEnvironmentVariableCollection, ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
import { TerminalStorageKeys } from 'vs/workbench/contrib/terminal/common/terminalStorageKeys';
interface ISerializableExtensionEnvironmentVariableCollection {
extensionIdentifier: string,
collection: ISerializableEnvironmentVariableCollection
}
/**
* Tracks and persists environment variable collections as defined by extensions.
*/
export class EnvironmentVariableService implements IEnvironmentVariableService {
declare readonly _serviceBrand: undefined;
collections: Map<string, IEnvironmentVariableCollectionWithPersistence> = new Map();
mergedCollection: IMergedEnvironmentVariableCollection;
private readonly _onDidChangeCollections = new Emitter<IMergedEnvironmentVariableCollection>();
get onDidChangeCollections(): Event<IMergedEnvironmentVariableCollection> { return this._onDidChangeCollections.event; }
constructor(
@IExtensionService private readonly _extensionService: IExtensionService,
@IStorageService private readonly _storageService: IStorageService
) {
const serializedPersistedCollections = this._storageService.get(TerminalStorageKeys.EnvironmentVariableCollections, StorageScope.WORKSPACE);
if (serializedPersistedCollections) {
const collectionsJson: ISerializableExtensionEnvironmentVariableCollection[] = JSON.parse(serializedPersistedCollections);
collectionsJson.forEach(c => this.collections.set(c.extensionIdentifier, {
persistent: true,
map: deserializeEnvironmentVariableCollection(c.collection)
}));
// Asynchronously invalidate collections where extensions have been uninstalled, this is
// async to avoid making all functions on the service synchronous and because extensions
// being uninstalled is rare.
this._invalidateExtensionCollections();
}
this.mergedCollection = this._resolveMergedCollection();
// Listen for uninstalled/disabled extensions
this._extensionService.onDidChangeExtensions(() => this._invalidateExtensionCollections());
}
set(extensionIdentifier: string, collection: IEnvironmentVariableCollectionWithPersistence): void {
this.collections.set(extensionIdentifier, collection);
this._updateCollections();
}
delete(extensionIdentifier: string): void {
this.collections.delete(extensionIdentifier);
this._updateCollections();
}
private _updateCollections(): void {
this._persistCollectionsEventually();
this.mergedCollection = this._resolveMergedCollection();
this._notifyCollectionUpdatesEventually();
}
@throttle(1000)
private _persistCollectionsEventually(): void {
this._persistCollections();
}
protected _persistCollections(): void {
const collectionsJson: ISerializableExtensionEnvironmentVariableCollection[] = [];
this.collections.forEach((collection, extensionIdentifier) => {
if (collection.persistent) {
collectionsJson.push({
extensionIdentifier,
collection: serializeEnvironmentVariableCollection(this.collections.get(extensionIdentifier)!.map)
});
}
});
const stringifiedJson = JSON.stringify(collectionsJson);
this._storageService.store(TerminalStorageKeys.EnvironmentVariableCollections, stringifiedJson, StorageScope.WORKSPACE, StorageTarget.MACHINE);
}
@debounce(1000)
private _notifyCollectionUpdatesEventually(): void {
this._notifyCollectionUpdates();
}
protected _notifyCollectionUpdates(): void {
this._onDidChangeCollections.fire(this.mergedCollection);
}
private _resolveMergedCollection(): IMergedEnvironmentVariableCollection {
return new MergedEnvironmentVariableCollection(this.collections);
}
private async _invalidateExtensionCollections(): Promise<void> {
await this._extensionService.whenInstalledExtensionsRegistered();
const registeredExtensions = await this._extensionService.getExtensions();
let changes = false;
this.collections.forEach((_, extensionIdentifier) => {
const isExtensionRegistered = registeredExtensions.some(r => r.identifier.value === extensionIdentifier);
if (!isExtensionRegistered) {
this.collections.delete(extensionIdentifier);
changes = true;
}
});
if (changes) {
this._updateCollections();
}
}
}