Skip to content
Open
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
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,11 @@
"description": "Additional environment variables to pass to the debugging (and debugged) process",
"default": {}
},
"envFile": {
"type": "string",
"description": "Path to a file containing environment variable definitions (e.g., .env file). Variables defined in 'env' will override those in envFile.",
"default": ""
},
"showProtocolLog": {
"type": "boolean",
"description": "Show a log of DAP requests, events, and responses",
Expand Down
1 change: 1 addition & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface LaunchConfiguration extends DebugConfiguration {
cwd?: string;
args?: string[];
env?: { [key: string]: string };
envFile?: string;

debugPort?: string;
waitLaunchTime?: number;
Expand Down
52 changes: 46 additions & 6 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
import { DebugProtocol } from "@vscode/debugprotocol";
import { registerInspectorView } from "./inspector";
import { AttachConfiguration, LaunchConfiguration } from "./config";
import { VersionChecker, fullPath } from "./utils";
import { VersionChecker, fullPath, parseEnvFile } from "./utils";

const asyncExec = promisify(child_process.exec);

Expand Down Expand Up @@ -64,6 +64,41 @@ function customPath(workingDirectory: string): string {
}
}

/**
* Merge environment variables from envFile and config.env
* Variables in config.env take precedence over those in envFile
* @param config Launch configuration
* @returns Merged environment variables, or undefined if neither envFile nor env is specified
*/
function mergeEnvVariables(config: LaunchConfiguration): { [key: string]: string } | undefined {
let mergedEnv: { [key: string]: string } | undefined;

if (config.envFile) {
const envFilePath = path.isAbsolute(config.envFile)
? config.envFile
: path.join(config.cwd ? customPath(config.cwd) : workspaceFolder() || "", config.envFile);

const envFromFile = parseEnvFile(envFilePath);
if (envFromFile === undefined) {

outputChannel.appendLine(`Warning: Could not read envFile: ${envFilePath}`);
vscode.window.showWarningMessage(`Could not read envFile: ${envFilePath}`);
} else {
mergedEnv = { ...envFromFile };
}
}

if (config.env) {
if (mergedEnv) {
mergedEnv = { ...mergedEnv, ...config.env };
} else {
mergedEnv = { ...config.env };
}
}

return mergedEnv;
}

function pp(obj: any) {
outputChannel.appendLine(JSON.stringify(obj));
}
Expand Down Expand Up @@ -513,9 +548,10 @@ class RdbgAdapterDescriptorFactory implements DebugAdapterDescriptorFactory, Ver
getSockPath(config: LaunchConfiguration): Promise<string | undefined> {
return new Promise((resolve) => {
const command = this.makeShellCommand(this.rdbgBin(config) + " --util=gen-sockpath");
const mergedEnv = mergeEnvVariables(config);
const p = child_process.exec(command, {
cwd: config.cwd ? customPath(config.cwd) : workspaceFolder(),
env: { ...process.env, ...config.env }
env: { ...process.env, ...mergedEnv }
});
let path: string;

Expand Down Expand Up @@ -544,9 +580,10 @@ class RdbgAdapterDescriptorFactory implements DebugAdapterDescriptorFactory, Ver
getTcpPortFile(config: LaunchConfiguration): Promise<string | undefined> {
return new Promise((resolve) => {
const command = this.makeShellCommand(this.rdbgBin(config) + " --util=gen-portpath");
const mergedEnv = mergeEnvVariables(config);
const p = child_process.exec(command, {
cwd: config.cwd ? customPath(config.cwd) : workspaceFolder(),
env: { ...process.env, ...config.env }
env: { ...process.env, ...mergedEnv }
});
let path: string;

Expand All @@ -568,9 +605,10 @@ class RdbgAdapterDescriptorFactory implements DebugAdapterDescriptorFactory, Ver
getVersion(config: LaunchConfiguration): Promise<string | null> {
return new Promise((resolve) => {
const command = this.makeShellCommand(this.rdbgBin(config) + " --version");
const mergedEnv = mergeEnvVariables(config);
const p = child_process.exec(command, {
cwd: config.cwd ? customPath(config.cwd) : workspaceFolder(),
env: { ...process.env, ...config.env }
env: { ...process.env, ...mergedEnv }
});
let version: string;

Expand Down Expand Up @@ -748,7 +786,8 @@ class RdbgAdapterDescriptorFactory implements DebugAdapterDescriptorFactory, Ver
throw error;
}

let cmdline = this.envPrefix(config.env);
const mergedEnv = mergeEnvVariables(config);
let cmdline = this.envPrefix(mergedEnv);

if (config.noDebug) {
cmdline += execCommand;
Expand Down Expand Up @@ -879,8 +918,9 @@ class RdbgAdapterDescriptorFactory implements DebugAdapterDescriptorFactory, Ver
}
throw error;
}
const mergedEnv = mergeEnvVariables(config);
const options: child_process.SpawnOptionsWithoutStdio = {
env: { ...process.env, ...config.env },
env: { ...process.env, ...mergedEnv },
cwd: customPath(config.cwd || ""),
};
if (process.platform === "win32") options.shell = "powershell";
Expand Down
51 changes: 51 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,54 @@ export function fullPath(p: string, session: vscode.DebugSession | undefined) {
}
return p;
}

/**
* Parse a .env file and return environment variables as key-value pairs
* Supports:
* - KEY=VALUE format
* - Comments (lines starting with #)
* - Quoted values (single and double quotes)
* - Empty lines
* @param envFilePath Path to the .env file
* @returns Object containing environment variables, or undefined if file doesn't exist
*/
export function parseEnvFile(envFilePath: string): { [key: string]: string } | undefined {
if (!fs.existsSync(envFilePath)) {
return undefined;
}

try {
const content = fs.readFileSync(envFilePath, "utf8");
const env: { [key: string]: string } = {};
const lines = content.split(/\r?\n/);

for (let line of lines) {
line = line.trim();

if (line === "" || line.startsWith("#")) {
continue;
}

const equalIndex = line.indexOf("=");
if (equalIndex === -1) {
continue;
}

const key = line.substring(0, equalIndex).trim();
let value = line.substring(equalIndex + 1).trim();

if ((value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))) {
value = value.substring(1, value.length - 1);
}

if (key) {
env[key] = value;
}
}

return env;
} catch (error) {
return undefined;
}
}