-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathterminalEnvVarInjector.ts
More file actions
180 lines (159 loc) · 7.28 KB
/
terminalEnvVarInjector.ts
File metadata and controls
180 lines (159 loc) · 7.28 KB
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
import * as fse from 'fs-extra';
import * as path from 'path';
import {
Disposable,
EnvironmentVariableScope,
GlobalEnvironmentVariableCollection,
workspace,
WorkspaceFolder,
} from 'vscode';
import { traceError, traceVerbose } from '../../common/logging';
import { resolveVariables } from '../../common/utils/internalVariables';
import { getConfiguration, getWorkspaceFolder } from '../../common/workspace.apis';
import { EnvVarManager } from '../execution/envVariableManager';
/**
* Manages injection of workspace-specific environment variables into VS Code terminals
* using the GlobalEnvironmentVariableCollection API.
*/
export class TerminalEnvVarInjector implements Disposable {
private disposables: Disposable[] = [];
constructor(
private readonly envVarCollection: GlobalEnvironmentVariableCollection,
private readonly envVarManager: EnvVarManager,
) {
this.initialize();
}
/**
* Initialize the injector by setting up watchers and injecting initial environment variables.
*/
private async initialize(): Promise<void> {
traceVerbose('TerminalEnvVarInjector: Initializing environment variable injection');
// Listen for environment variable changes from the manager
this.disposables.push(
this.envVarManager.onDidChangeEnvironmentVariables((args) => {
if (!args.uri) {
// No specific URI, reload all workspaces
this.updateEnvironmentVariables().catch((error) => {
traceError('Failed to update environment variables:', error);
});
return;
}
const affectedWorkspace = getWorkspaceFolder(args.uri);
if (!affectedWorkspace) {
// No workspace folder found for this URI, reloading all workspaces
this.updateEnvironmentVariables().catch((error) => {
traceError('Failed to update environment variables:', error);
});
return;
}
if (args.changeType === 2) {
// FileChangeType.Deleted
this.clearWorkspaceVariables(affectedWorkspace);
} else {
this.updateEnvironmentVariables(affectedWorkspace).catch((error) => {
traceError('Failed to update environment variables:', error);
});
}
}),
);
// Initial load of environment variables
await this.updateEnvironmentVariables();
}
/**
* Update environment variables in the terminal collection.
*/
private async updateEnvironmentVariables(workspaceFolder?: WorkspaceFolder): Promise<void> {
try {
if (workspaceFolder) {
// Update only the specified workspace
traceVerbose(
`TerminalEnvVarInjector: Updating environment variables for workspace: ${workspaceFolder.uri.fsPath}`,
);
await this.injectEnvironmentVariablesForWorkspace(workspaceFolder);
} else {
// No provided workspace - update all workspaces
this.envVarCollection.clear();
const workspaceFolders = workspace.workspaceFolders;
if (!workspaceFolders || workspaceFolders.length === 0) {
traceVerbose('TerminalEnvVarInjector: No workspace folders found, skipping env var injection');
return;
}
traceVerbose('TerminalEnvVarInjector: Updating environment variables for all workspaces');
for (const folder of workspaceFolders) {
await this.injectEnvironmentVariablesForWorkspace(folder);
}
}
traceVerbose('TerminalEnvVarInjector: Environment variable injection completed');
} catch (error) {
traceError('TerminalEnvVarInjector: Error updating environment variables:', error);
}
}
/**
* Inject environment variables for a specific workspace.
*/
private async injectEnvironmentVariablesForWorkspace(workspaceFolder: WorkspaceFolder): Promise<void> {
const workspaceUri = workspaceFolder.uri;
try {
const envVars = await this.envVarManager.getEnvironmentVariables(workspaceUri);
// use scoped environment variable collection
const envVarScope = this.getEnvironmentVariableCollectionScoped({ workspaceFolder });
envVarScope.clear(); // Clear existing variables for this workspace
// Track which .env file is being used for logging
const config = getConfiguration('python', workspaceUri);
const envFilePath = config.get<string>('envFile');
const resolvedEnvFilePath: string | undefined = envFilePath
? path.resolve(resolveVariables(envFilePath, workspaceUri))
: undefined;
const defaultEnvFilePath: string = path.join(workspaceUri.fsPath, '.env');
let activeEnvFilePath: string = resolvedEnvFilePath || defaultEnvFilePath;
if (activeEnvFilePath && (await fse.pathExists(activeEnvFilePath))) {
traceVerbose(`TerminalEnvVarInjector: Using env file: ${activeEnvFilePath}`);
} else {
traceVerbose(
`TerminalEnvVarInjector: No .env file found for workspace: ${workspaceUri.fsPath}, not injecting environment variables.`,
);
return; // No .env file to inject
}
for (const [key, value] of Object.entries(envVars)) {
if (value === undefined) {
// Remove the environment variable if the value is undefined
envVarScope.delete(key);
} else {
envVarScope.replace(key, value);
}
}
} catch (error) {
traceError(
`TerminalEnvVarInjector: Error injecting environment variables for workspace ${workspaceUri.fsPath}:`,
error,
);
}
}
/**
* Dispose of the injector and clean up resources.
*/
dispose(): void {
traceVerbose('TerminalEnvVarInjector: Disposing');
this.disposables.forEach((disposable) => disposable.dispose());
this.disposables = [];
// Clear all environment variables from the collection
this.envVarCollection.clear();
}
private getEnvironmentVariableCollectionScoped(scope: EnvironmentVariableScope = {}) {
const envVarCollection = this.envVarCollection as GlobalEnvironmentVariableCollection;
return envVarCollection.getScoped(scope);
}
/**
* Clear all environment variables for a workspace.
*/
private clearWorkspaceVariables(workspaceFolder: WorkspaceFolder): void {
try {
const scope = this.getEnvironmentVariableCollectionScoped({ workspaceFolder });
scope.clear();
} catch (error) {
traceError(`Failed to clear environment variables for workspace ${workspaceFolder.uri.fsPath}:`, error);
}
}
}