Skip to content

Commit 64ac13f

Browse files
edvilmeCopilot
andauthored
refactor: extract envFile.ts module from server.ts (#464)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent f09c7cc commit 64ac13f

File tree

2 files changed

+58
-25
lines changed

2 files changed

+58
-25
lines changed

src/common/envFile.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import * as dotenv from 'dotenv';
5+
import * as fsapi from 'fs-extra';
6+
import * as path from 'path';
7+
import { WorkspaceFolder } from 'vscode';
8+
import { traceInfo, traceWarn } from './logging';
9+
import { getConfiguration } from './vscodeapi';
10+
11+
function expandTilde(value: string): string {
12+
const home = process.env.HOME || process.env.USERPROFILE || '';
13+
if (value === '~') {
14+
return home;
15+
}
16+
if (value.startsWith('~/') || value.startsWith('~\\')) {
17+
return path.join(home, value.slice(2));
18+
}
19+
return value;
20+
}
21+
22+
/**
23+
* Reads the env file configured via `python.envFile` (defaults to `${workspaceFolder}/.env`),
24+
* parses it using dotenv, and returns the resulting environment variables.
25+
* Returns an empty record if the file does not exist or cannot be read.
26+
*/
27+
export async function getEnvFileVars(workspace: WorkspaceFolder): Promise<Record<string, string>> {
28+
const pythonConfig = getConfiguration('python', workspace.uri);
29+
let envFilePath = pythonConfig.get<string>('envFile', '${workspaceFolder}/.env') ?? '${workspaceFolder}/.env';
30+
31+
envFilePath = envFilePath.replace(/\$\{workspaceFolder\}/g, workspace.uri.fsPath);
32+
33+
envFilePath = expandTilde(envFilePath);
34+
35+
if (!path.isAbsolute(envFilePath)) {
36+
envFilePath = path.join(workspace.uri.fsPath, envFilePath);
37+
}
38+
39+
try {
40+
if (await fsapi.pathExists(envFilePath)) {
41+
const content = await fsapi.readFile(envFilePath, 'utf-8');
42+
const vars = dotenv.parse(content);
43+
const count = Object.keys(vars).length;
44+
if (count > 0) {
45+
traceInfo(`Loaded ${count} environment variable(s) from ${envFilePath}`);
46+
}
47+
return vars;
48+
}
49+
} catch (err) {
50+
traceWarn(`Failed to read env file ${envFilePath}: ${err}`);
51+
}
52+
return {};
53+
}

src/common/server.ts

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright (c) Microsoft Corporation. All rights reserved.
22
// Licensed under the MIT License.
33

4-
import * as dotenv from 'dotenv';
54
import * as fsapi from 'fs-extra';
65
import * as path from 'path';
76
import { Disposable, env, l10n, LanguageStatusSeverity, LogOutputChannel, Uri } from 'vscode';
@@ -13,36 +12,16 @@ import {
1312
ServerOptions,
1413
} from 'vscode-languageclient/node';
1514
import { DEBUG_SERVER_SCRIPT_PATH, SERVER_SCRIPT_PATH } from './constants';
15+
import { getEnvFileVars } from './envFile';
1616
import { traceError, traceInfo, traceVerbose } from './logging';
1717
import { getDebuggerPath } from './python';
1818
import { getExtensionSettings, getGlobalSettings, ISettings } from './settings';
1919
import { getLSClientTraceLevel, getDocumentSelector } from './utilities';
2020
import { updateStatus } from './status';
21-
import { getConfiguration } from './vscodeapi';
21+
import { getWorkspaceFolder } from './vscodeapi';
2222

2323
export type IInitOptions = { settings: ISettings[]; globalSettings: ISettings };
2424

25-
async function loadEnvFile(workspacePath: string): Promise<Record<string, string>> {
26-
try {
27-
const pythonConfig = getConfiguration('python', Uri.file(workspacePath));
28-
let envFilePath = pythonConfig.get<string>('envFile', '${workspaceFolder}/.env');
29-
envFilePath = envFilePath.replace('${workspaceFolder}', workspacePath);
30-
31-
if (await fsapi.pathExists(envFilePath)) {
32-
const content = await fsapi.readFile(envFilePath, 'utf-8');
33-
const envVars = dotenv.parse(content);
34-
const count = Object.keys(envVars).length;
35-
if (count > 0) {
36-
traceInfo(`Loaded ${count} environment variable(s) from ${envFilePath}`);
37-
}
38-
return envVars;
39-
}
40-
} catch (ex) {
41-
traceError(`Failed to load envFile: ${ex}`);
42-
}
43-
return {};
44-
}
45-
4625
/**
4726
* Resolves the CWD for spawning the server process.
4827
*
@@ -70,8 +49,9 @@ async function createServer(
7049
const newEnv = { ...process.env };
7150

7251
// Load environment variables from python.envFile (.env)
73-
const workspacePath = Uri.parse(settings.workspace).fsPath;
74-
const envFileVars = await loadEnvFile(workspacePath);
52+
const workspaceUri = Uri.parse(settings.workspace);
53+
const workspaceFolder = getWorkspaceFolder(workspaceUri);
54+
const envFileVars = workspaceFolder ? await getEnvFileVars(workspaceFolder) : {};
7555
for (const [key, val] of Object.entries(envFileVars)) {
7656
if ((key === 'PYTHONPATH' || key === 'PATH') && newEnv[key]) {
7757
newEnv[key] = newEnv[key] + path.delimiter + val;

0 commit comments

Comments
 (0)