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
1 change: 1 addition & 0 deletions Extension/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
* Reduce CPU usage when resolving headers in large Windows workspaces.

### Bug Fixes
* Fix `${VAR}` interpolation in `.env` files used by `envFile`: references to variables defined earlier in the same file (or in the OS environment) are now resolved. [#13781](https://github.com/microsoft/vscode-cpptools/issues/13781)
* Fix 'Go to Declaration' and 'Go to Definition' returning the current location instead of an available counterpart. [#14509](https://github.com/microsoft/vscode-cpptools/issues/14509)
* Update MIEngine to fix debugger failures with synthetic GDB stack frames. [#14741](https://github.com/microsoft/vscode-cpptools/issues/14741)
* Thanks for the contribution. [@tzcnt](https://github.com/tzcnt) [PR MIEngine#1605](https://github.com/microsoft/MIEngine/pull/1605)
Expand Down
11 changes: 11 additions & 0 deletions Extension/src/Debugger/ParsedEnvironmentFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,17 @@ export class ParsedEnvironmentFile {

value = value.replace(/(^['"]|['"]$)/g, "");

// Resolve ${VAR} references against the variables defined so far in the file
// (and the process environment), following the dotenv interpolation rules.
// A reference to a name we don't know is left as-is instead of being dropped.
value = value.replace(/\$\{([\w\.\-]+)\}/g, (full: string, name: string): string => {
if (env.has(name)) {
return env.get(name);
}
const processValue: string | undefined = process.env[name];
return processValue !== undefined ? processValue : full;
});

env.set(key, value);
} else {
// Blank lines and lines starting with # are no parse errors
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,31 @@ MyName2=Value2
assertEnvironmentEqual(result.Env, "MyName1", "Value1");
assertEnvironmentEqual(result.Env, "MyName2", "Value2");
});

test("Resolve a reference to a variable defined earlier in the file", () => {
const content: string = `USER=admin
EMAIL=\${USER}@example.org`;
const result: ParsedEnvironmentFile = ParsedEnvironmentFile.CreateFromContent(content, "TestEnvFileName", []);

assert(!result.Warning, `Failed to assert that Warning was empty: ${result.Warning}`);
assertEnvironmentEqual(result.Env, "USER", "admin");
assertEnvironmentEqual(result.Env, "EMAIL", "admin@example.org");
});

test("Resolve a reference from the initial environment", () => {
const initialEnv: Environment[] = [{ name: "USER", value: "admin" }];
const content: string = `EMAIL=\${USER}@example.org`;
const result: ParsedEnvironmentFile = ParsedEnvironmentFile.CreateFromContent(content, "TestEnvFileName", initialEnv);

assert(!result.Warning, `Failed to assert that Warning was empty: ${result.Warning}`);
assertEnvironmentEqual(result.Env, "EMAIL", "admin@example.org");
});

test("Leave an unknown reference untouched", () => {
const content: string = `EMAIL=\${UNKNOWN_USER}@example.org`;
const result: ParsedEnvironmentFile = ParsedEnvironmentFile.CreateFromContent(content, "TestEnvFileName", []);

assert(!result.Warning, `Failed to assert that Warning was empty: ${result.Warning}`);
assertEnvironmentEqual(result.Env, "EMAIL", "${UNKNOWN_USER}@example.org");
});
});