Skip to content

Commit 9be9832

Browse files
authored
Implement envFile (Issue #523) (#928)
* Implement envFile * Fix linting issues * Update README * Only merge envFile on launch type * Changes as requested by @testforstephen
1 parent 4f6951d commit 9be9832

File tree

10 files changed

+77
-6
lines changed

10 files changed

+77
-6
lines changed

Configuration.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ In case you want to manually edit the configuration, below are the explanation a
102102
}
103103
```
104104

105+
- `envFile` - Absolute path to a file containing environment variable definitions.
106+
```json
107+
"envFile": "${workspaceFolder}/.env"
108+
```
109+
105110
### Don't step into the specified classes or methods
106111

107112
- `stepFilters` - Skip the specified classes or methods you don't want to step into. Class names should be fully qualified. Wildcard is supported.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Please also check the documentation of [Language Support for Java by Red Hat](ht
5858
- `projectName` - The preferred project in which the debugger searches for classes. There could be duplicated class names in different projects. This setting also works when the debugger looks for the specified main class when launching a program. It is required when the workspace has multiple java projects, otherwise the expression evaluation and conditional breakpoint may not work.
5959
- `cwd` - The working directory of the program. Defaults to `${workspaceFolder}`.
6060
- `env` - The extra environment variables for the program.
61+
- `envFile` - Absolute path to a file containing environment variable definitions.
6162
- `stopOnEntry` - Automatically pause the program after launching.
6263
- `console` - The specified console to launch the program. If not specified, use the console specified by the `java.debug.settings.console` user setting.
6364
- `internalConsole` - VS Code debug console (input stream not supported).

TestPlan.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,7 @@ Exception in thread "main" java.lang.IllegalStateException
441441
```
442442
CustomEnv: This env is for test plan.
443443
SystemPath: <value of PATH >
444+
FileEnv: Successfully loaded an env from a file.
444445
```
445446
446447
## Runtime classpath entry

package.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,11 @@
294294
"description": "%java.debugger.launch.env.description%",
295295
"default": {}
296296
},
297+
"envFile": {
298+
"type": "string",
299+
"description": "%java.debugger.launch.envFile.description%",
300+
"default": "${workspaceFolder}/.env"
301+
},
297302
"stopOnEntry": {
298303
"type": "boolean",
299304
"description": "%java.debugger.launch.stopOnEntry.description%",

package.nls.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"java.debugger.launch.encoding.description": "The file.encoding setting for the JVM. If not specified, 'UTF-8' will be used. Possible values can be found in https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html.",
1010
"java.debugger.launch.cwd.description": "The working directory of the program. Defaults to the current workspace root.",
1111
"java.debugger.launch.env.description": "The extra environment variables for the program.",
12+
"java.debugger.launch.envFile.description": "Absolute path to a file containing environment variable definitions.",
1213
"java.debugger.launch.stopOnEntry.description": "Automatically pause the program after launching.",
1314
"java.debugger.launch.internalConsole.description": "VS Code debug console (input stream not supported).",
1415
"java.debugger.launch.integratedTerminal.description": "VS Code integrated terminal.",

package.nls.zh.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"java.debugger.launch.encoding.description": "JVM的file.encoding设置。如果未指定,将使用“UTF-8”。可以在http://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html中找到可能的值。",
1010
"java.debugger.launch.cwd.description": "应用程序的工作目录。默认为当前工作空间根目录。",
1111
"java.debugger.launch.env.description": "启动应用程序时自定义的环境变量。",
12+
"java.debugger.launch.envFile.description": "环境变量文件绝对路径。",
1213
"java.debugger.launch.stopOnEntry.description": "启动后自动暂停应用程序。",
1314
"java.debugger.launch.internalConsole.description": "VS Code调试控制台(不支持输入流)。",
1415
"java.debugger.launch.integratedTerminal.description": "VS Code集成终端。",

src/configurationProvider.ts

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { IProgressReporter } from "./progressAPI";
2020
import { progressProvider } from "./progressImpl";
2121
import * as utility from "./utility";
2222

23-
const platformNameMappings: {[key: string]: string} = {
23+
const platformNameMappings: { [key: string]: string } = {
2424
win32: "windows",
2525
linux: "linux",
2626
darwin: "osx",
@@ -103,7 +103,7 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
103103
const isOnStandardMode = await utility.waitForStandardMode(progressReporter);
104104
if (!isOnStandardMode) {
105105
resolve([defaultLaunchConfig]);
106-
return ;
106+
return;
107107
}
108108

109109
if (progressReporter.isCancelled()) {
@@ -154,7 +154,7 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
154154
}
155155
}
156156

157-
private constructLaunchConfigName(mainClass: string, cache: {[key: string]: any}) {
157+
private constructLaunchConfigName(mainClass: string, cache: { [key: string]: any }) {
158158
const name = `Launch ${mainClass.substr(mainClass.lastIndexOf(".") + 1)}`;
159159
if (cache[name] === undefined) {
160160
cache[name] = 0;
@@ -165,6 +165,25 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
165165
}
166166
}
167167

168+
private mergeEnvFile(config: vscode.DebugConfiguration) {
169+
const baseEnv = config.env || {};
170+
let result = baseEnv;
171+
if (config.envFile) {
172+
try {
173+
result = {
174+
...baseEnv,
175+
...readEnvFile(config.envFile),
176+
};
177+
} catch (e) {
178+
throw new utility.UserError({
179+
message: "Cannot load environment file.",
180+
type: Type.USAGEERROR,
181+
});
182+
}
183+
}
184+
config.env = result;
185+
}
186+
168187
private async resolveAndValidateDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration,
169188
token?: vscode.CancellationToken) {
170189
let progressReporter = progressProvider.getProgressReporter(config.__progressId);
@@ -198,6 +217,8 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
198217
}
199218

200219
if (config.request === "launch") {
220+
this.mergeEnvFile(config);
221+
201222
// If the user doesn't specify 'vmArgs' in launch.json, use the global setting to get the default vmArgs.
202223
if (config.vmArgs === undefined) {
203224
const debugSettings: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("java.debug.settings");
@@ -383,7 +404,7 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
383404
private async resolveAndValidateMainClass(folder: vscode.Uri | undefined, config: vscode.DebugConfiguration,
384405
progressReporter: IProgressReporter): Promise<lsPlugin.IMainClassOption | undefined> {
385406
if (!config.mainClass || this.isFile(config.mainClass)) {
386-
const currentFile = config.mainClass || _.get(vscode.window.activeTextEditor, "document.uri.fsPath");
407+
const currentFile = config.mainClass || _.get(vscode.window.activeTextEditor, "document.uri.fsPath");
387408
if (currentFile) {
388409
const mainEntries = await lsPlugin.resolveMainMethod(vscode.Uri.file(currentFile));
389410
if (progressReporter.isCancelled()) {
@@ -427,7 +448,7 @@ export class JavaDebugConfigurationProvider implements vscode.DebugConfiguration
427448

428449
private async fixMainClass(folder: vscode.Uri | undefined, config: vscode.DebugConfiguration,
429450
validationResponse: lsPlugin.ILaunchValidationResponse, progressReporter: IProgressReporter):
430-
Promise<lsPlugin.IMainClassOption | undefined> {
451+
Promise<lsPlugin.IMainClassOption | undefined> {
431452
const errors: string[] = [];
432453
if (!validationResponse.mainClass.isValid) {
433454
errors.push(String(validationResponse.mainClass.message));
@@ -576,3 +597,35 @@ function convertLogLevel(commonLogLevel: string) {
576597
return "FINE";
577598
}
578599
}
600+
601+
// from vscode-js-debug https://github.com/microsoft/vscode-js-debug/blob/master/src/targets/node/nodeLauncherBase.ts
602+
function readEnvFile(file: string): { [key: string]: string } {
603+
if (!fs.existsSync(file)) {
604+
return {};
605+
}
606+
607+
const buffer = stripBOM(fs.readFileSync(file, "utf8"));
608+
const env: { [key: string]: string } = {};
609+
for (const line of buffer.split("\n")) {
610+
const r = line.match(/^\s*([\w\.\-]+)\s*=\s*(.*)?\s*$/);
611+
if (!r) {
612+
continue;
613+
}
614+
615+
let value = r[2] || "";
616+
// .env variables never overwrite existing variables (see #21169)
617+
if (value.length > 0 && value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') {
618+
value = value.replace(/\\n/gm, "\n");
619+
}
620+
env[r[1]] = value.replace(/(^['"]|['"]$)/g, "");
621+
}
622+
623+
return env;
624+
}
625+
626+
function stripBOM(s: string): string {
627+
if (s && s[0] === "\uFEFF") {
628+
s = s.substr(1);
629+
}
630+
return s;
631+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
FILE_ENV_FOR_TEST_PLAN=Successfully loaded an env from a file.

testprojects/26.environmentVariables/.vscode/launch.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"projectName": "26.environmentVariables",
1818
"env": {
1919
"CUSTOM_ENV_FOR_TEST_PLAN": "This env is for test plan."
20-
}
20+
},
21+
"envFile": "${workspaceFolder}/.env"
2122
}
2223
]
2324
}

testprojects/26.environmentVariables/src/main/java/EnvrionmentVariable.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ public class EnvrionmentVariable {
22
public static void main(String[] args) {
33
String customEnv = System.getenv("CUSTOM_ENV_FOR_TEST_PLAN");
44
String systemPath = System.getenv("PATH");
5+
String envFromFile = System.getenv("FILE_ENV_FOR_TEST_PLAN");
56
System.out.println(String.format("CustomEnv: %s", customEnv));
67
System.out.println(String.format("SystemPath: %s", systemPath));
8+
System.out.println(String.format("FileEnv: %s", envFromFile));
79
}
810
}

0 commit comments

Comments
 (0)