Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/common/envFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import * as dotenv from 'dotenv';
import * as fs from 'fs-extra';
import * as path from 'path';
import { WorkspaceFolder } from 'vscode';
import { traceLog, traceWarn } from './logging';
import { getConfiguration } from './vscodeapi';

function expandTilde(filePath: string): string {
const home = process.env.HOME ?? process.env.USERPROFILE ?? '';
if (filePath === '~') {
return home;
}
if (filePath.startsWith('~/') || filePath.startsWith('~\\')) {
return path.join(home, filePath.slice(2));
}
return filePath;
}

/**
* Reads the env file configured via `python.envFile` (defaults to `${workspaceFolder}/.env`),
* parses it using dotenv, and returns the resulting environment variables.
* Returns an empty record if the file does not exist or cannot be read.
*/
export async function getEnvFileVars(workspace: WorkspaceFolder): Promise<Record<string, string>> {
const pythonConfig = getConfiguration('python', workspace.uri);
let envFilePath = pythonConfig.get<string>('envFile', '${workspaceFolder}/.env') ?? '${workspaceFolder}/.env';

// Resolve ${workspaceFolder}
envFilePath = envFilePath.replace(/\$\{workspaceFolder\}/g, workspace.uri.fsPath);

envFilePath = expandTilde(envFilePath);

if (!path.isAbsolute(envFilePath)) {
envFilePath = path.join(workspace.uri.fsPath, envFilePath);
}

try {
if (await fs.pathExists(envFilePath)) {
const content = await fs.readFile(envFilePath, 'utf-8');
const vars = dotenv.parse(content);
const count = Object.keys(vars).length;
if (count > 0) {
traceLog(`Loaded ${count} environment variable(s) from ${envFilePath}`);
}
return vars;
}
} catch (err) {
traceWarn(`Failed to read env file ${envFilePath}: ${err}`);
}
return {};
}
30 changes: 7 additions & 23 deletions src/common/server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

import * as dotenv from 'dotenv';
import * as fsapi from 'fs-extra';
import { Disposable, env, l10n, LanguageStatusSeverity, LogOutputChannel, Uri } from 'vscode';
import { State } from 'vscode-languageclient';
Expand All @@ -12,34 +11,16 @@ import {
ServerOptions,
} from 'vscode-languageclient/node';
import { DEBUG_SERVER_SCRIPT_PATH, SERVER_SCRIPT_PATH } from './constants';
import { getEnvFileVars } from './envFile';
import { traceError, traceInfo, traceVerbose } from './logging';
import { getDebuggerPath } from './python';
import { getExtensionSettings, getGlobalSettings, ISettings, isLintOnChangeEnabled } from './settings';
import { getLSClientTraceLevel, getDocumentSelector } from './utilities';
import { updateScore, updateStatus } from './status';
import { getConfiguration } from './vscodeapi';
import { getWorkspaceFolder } from './vscodeapi';

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

async function loadEnvVarsFromFile(workspace: Uri): Promise<Record<string, string>> {
const pythonConfig = getConfiguration('python', workspace);
let envFileSetting = pythonConfig.get<string>('envFile', '${workspaceFolder}/.env');
envFileSetting = envFileSetting.replace('${workspaceFolder}', workspace.fsPath);

if (!envFileSetting || !(await fsapi.pathExists(envFileSetting))) {
return {};
}

try {
const content = await fsapi.readFile(envFileSetting, 'utf-8');
traceInfo(`Loaded environment variables from ${envFileSetting}`);
return dotenv.parse(content);
} catch (ex) {
traceError(`Failed to read env file ${envFileSetting}: ${ex}`);
return {};
}
}

async function createServer(
settings: ISettings,
serverId: string,
Expand All @@ -55,8 +36,11 @@ async function createServer(

// Load environment variables from the envFile (python.envFile setting)
const workspaceUri = Uri.parse(settings.workspace);
const envFileVars = await loadEnvVarsFromFile(workspaceUri);
Object.assign(newEnv, envFileVars);
const workspaceFolder = getWorkspaceFolder(workspaceUri);
if (workspaceFolder) {
const envFileVars = await getEnvFileVars(workspaceFolder);
Object.assign(newEnv, envFileVars);
}

const debuggerPath = await getDebuggerPath();
const isDebugScript = await fsapi.pathExists(DEBUG_SERVER_SCRIPT_PATH);
Expand Down
Loading