Skip to content

Commit 4602546

Browse files
committed
fix #686
1 parent 3b253c6 commit 4602546

File tree

11 files changed

+161
-41
lines changed

11 files changed

+161
-41
lines changed

.vscode/settings.json

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
"out": true // set this to false to include "out" folder in search results
1010
},
1111
"typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version
12-
"tslint.enable": true,
12+
"tslint.enable": true,
1313
"python.linting.enabled": false,
14-
"python.formatting.formatOnSave": false,
15-
"python.unitTest.promptToConfigure": false
16-
}
14+
"python.formatting.formatOnSave": false,
15+
"python.unitTest.promptToConfigure": false,
16+
"python.workspaceSymbols.enabled": false
17+
}

package.json

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,8 @@
282282
"pythonPath": "$${{config.python.pythonPath}}",
283283
"program": "$${{file}}",
284284
"cwd": "$${{workspaceRoot}}",
285+
"env": null,
286+
"envFile": "$${{workspaceRoot}}.env",
285287
"debugOptions": [
286288
"WaitOnAbnormalExit",
287289
"WaitOnNormalExit",
@@ -308,6 +310,8 @@
308310
},
309311
"program": "$${{file}}",
310312
"cwd": "$${{workspaceRoot}}",
313+
"env": null,
314+
"envFile": "$${{workspaceRoot}}.env",
311315
"debugOptions": [
312316
"WaitOnAbnormalExit",
313317
"WaitOnNormalExit",
@@ -326,6 +330,8 @@
326330
"pythonPath": "$${{config.python.pythonPath}}",
327331
"module": "module.name",
328332
"cwd": "$${{workspaceRoot}}",
333+
"env": null,
334+
"envFile": "$${{workspaceRoot}}.env",
329335
"debugOptions": [
330336
"WaitOnAbnormalExit",
331337
"WaitOnNormalExit",
@@ -345,6 +351,8 @@
345351
"program": "$${{file}}",
346352
"cwd": "null",
347353
"console": "integratedTerminal",
354+
"env": null,
355+
"envFile": "$${{workspaceRoot}}.env",
348356
"debugOptions": [
349357
"WaitOnAbnormalExit",
350358
"WaitOnNormalExit"
@@ -363,6 +371,8 @@
363371
"program": "${{file}}",
364372
"cwd": "null",
365373
"console": "externalTerminal",
374+
"env": null,
375+
"envFile": "$${{workspaceRoot}}.env",
366376
"debugOptions": [
367377
"WaitOnAbnormalExit",
368378
"WaitOnNormalExit"
@@ -384,6 +394,8 @@
384394
"runserver",
385395
"--noreload"
386396
],
397+
"env": null,
398+
"envFile": "$${{workspaceRoot}}.env",
387399
"debugOptions": [
388400
"WaitOnAbnormalExit",
389401
"WaitOnNormalExit",
@@ -411,6 +423,7 @@
411423
"--no-debugger",
412424
"--no-reload"
413425
],
426+
"envFile": "$${{workspaceRoot}}.env",
414427
"debugOptions": [
415428
"WaitOnAbnormalExit",
416429
"WaitOnNormalExit",
@@ -430,6 +443,8 @@
430443
"program": "$${{workspaceRoot}}/run.py",
431444
"cwd": "$${{workspaceRoot}}",
432445
"args": [],
446+
"env": null,
447+
"envFile": "$${{workspaceRoot}}.env",
433448
"debugOptions": [
434449
"WaitOnAbnormalExit",
435450
"WaitOnNormalExit",
@@ -453,6 +468,8 @@
453468
"runserver",
454469
"--noreload=True"
455470
],
471+
"env": null,
472+
"envFile": "$${{workspaceRoot}}.env",
456473
"debugOptions": [
457474
"WaitOnAbnormalExit",
458475
"WaitOnNormalExit",
@@ -583,6 +600,11 @@
583600
"type": "object",
584601
"description": "Environment variables defined as a key value pair. Property ends up being the Environment Variable and the value of the property ends up being the value of the Env Variable.",
585602
"default": null
603+
},
604+
"envFile": {
605+
"type": "string",
606+
"description": "Absolute path to a file containing environment variable definitions.",
607+
"default": null
586608
}
587609
}
588610
},
@@ -628,6 +650,8 @@
628650
"pythonPath": "${config.python.pythonPath}",
629651
"program": "${file}",
630652
"cwd": "${workspaceRoot}",
653+
"env": null,
654+
"envFile": "$${{workspaceRoot}}.env",
631655
"debugOptions": [
632656
"WaitOnAbnormalExit",
633657
"WaitOnNormalExit",
@@ -650,6 +674,8 @@
650674
},
651675
"program": "${file}",
652676
"cwd": "${workspaceRoot}",
677+
"env": null,
678+
"envFile": "$${{workspaceRoot}}.env",
653679
"debugOptions": [
654680
"WaitOnAbnormalExit",
655681
"WaitOnNormalExit",
@@ -664,6 +690,8 @@
664690
"pythonPath": "${config.python.pythonPath}",
665691
"module": "module.name",
666692
"cwd": "${workspaceRoot}",
693+
"env": null,
694+
"envFile": "$${{workspaceRoot}}.env",
667695
"debugOptions": [
668696
"WaitOnAbnormalExit",
669697
"WaitOnNormalExit",
@@ -679,6 +707,8 @@
679707
"program": "${file}",
680708
"cwd": "null",
681709
"console": "integratedTerminal",
710+
"env": null,
711+
"envFile": "$${{workspaceRoot}}.env",
682712
"debugOptions": [
683713
"WaitOnAbnormalExit",
684714
"WaitOnNormalExit"
@@ -693,6 +723,8 @@
693723
"program": "${file}",
694724
"cwd": "null",
695725
"console": "externalTerminal",
726+
"env": null,
727+
"envFile": "$${{workspaceRoot}}.env",
696728
"debugOptions": [
697729
"WaitOnAbnormalExit",
698730
"WaitOnNormalExit"
@@ -710,6 +742,8 @@
710742
"runserver",
711743
"--noreload"
712744
],
745+
"env": null,
746+
"envFile": "$${{workspaceRoot}}.env",
713747
"debugOptions": [
714748
"WaitOnAbnormalExit",
715749
"WaitOnNormalExit",
@@ -733,6 +767,7 @@
733767
"--no-debugger",
734768
"--no-reload"
735769
],
770+
"envFile": "$${{workspaceRoot}}.env",
736771
"debugOptions": [
737772
"WaitOnAbnormalExit",
738773
"WaitOnNormalExit",
@@ -748,6 +783,8 @@
748783
"program": "${workspaceRoot}/run.py",
749784
"cwd": "${workspaceRoot}",
750785
"args": [],
786+
"env": null,
787+
"envFile": "$${{workspaceRoot}}.env",
751788
"debugOptions": [
752789
"WaitOnAbnormalExit",
753790
"WaitOnNormalExit",
@@ -767,6 +804,8 @@
767804
"runserver",
768805
"--noreload=True"
769806
],
807+
"env": null,
808+
"envFile": "$${{workspaceRoot}}.env",
770809
"debugOptions": [
771810
"WaitOnAbnormalExit",
772811
"WaitOnNormalExit",
@@ -794,16 +833,21 @@
794833
"default": "python",
795834
"description": "Path to Python, you can use a custom version of Python by modifying this setting to include the full path."
796835
},
836+
"python.envFile": {
837+
"type": "string",
838+
"description": "Absolute path to a file containing environment variable definitions.",
839+
"default": null
840+
},
797841
"python.jediPath": {
798842
"type": "string",
799843
"default": "",
800844
"description": "Path to directory containing the Jedi library (this path will contain the 'Jedi' sub directory)."
801845
},
802-
"python.sortImports.path": {
803-
"type": "string",
804-
"description": "Path to isort script, default using inner version",
805-
"default": ""
806-
},
846+
"python.sortImports.path": {
847+
"type": "string",
848+
"description": "Path to isort script, default using inner version",
849+
"default": ""
850+
},
807851
"python.sortImports.args": {
808852
"type": "array",
809853
"description": "Arguments passed in. Each argument is a separate item in the array.",
@@ -1271,4 +1315,4 @@
12711315
"vscode": "^1.0.0",
12721316
"webpack": "^1.13.2"
12731317
}
1274-
}
1318+
}

src/client/common/configSettings.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ export interface IPythonSettings {
2020
jupyter: JupyterSettings;
2121
sortImports: ISortImportSettings;
2222
workspaceSymbols: IWorkspaceSymbolSettings;
23+
envFile: string;
2324
}
24-
2525
export interface ISortImportSettings {
2626
path: string;
2727
args: string[];
@@ -140,6 +140,7 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
140140
else {
141141
this.jediPath = '';
142142
}
143+
this.envFile = systemVariables.resolveAny(pythonSettings.get<string>('envFile'));
143144
this.devOptions = systemVariables.resolveAny(pythonSettings.get<any[]>('devOptions'));
144145
this.devOptions = Array.isArray(this.devOptions) ? this.devOptions : [];
145146
let lintingSettings = systemVariables.resolveAny(pythonSettings.get<ILintingSettings>('linting'));
@@ -304,6 +305,7 @@ export class PythonSettings extends EventEmitter implements IPythonSettings {
304305
}
305306
}
306307
public jediPath: string;
308+
public envFile: string;
307309
public devOptions: string[];
308310
public linting: ILintingSettings;
309311
public formatting: IFormattingSettings;
@@ -336,7 +338,7 @@ function getPythonExecutable(pythonPath: string): string {
336338
}
337339
// Keep python right on top, for backwards compatibility
338340
const KnownPythonExecutables = ['python', 'python4', 'python3.6', 'python3.5', 'python3', 'python2.7', 'python2'];
339-
341+
340342
for (let executableName of KnownPythonExecutables) {
341343
// Suffix with 'python' for linux and 'osx', and 'python.exe' for 'windows'
342344
if (IS_WINDOWS) {

src/client/common/envFileParser.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as fs from 'fs';
2+
3+
export function parseEnvFile(envFile: string): any {
4+
const buffer = fs.readFileSync(envFile, 'utf8');
5+
const env = {};
6+
buffer.split('\n').forEach(line => {
7+
const r = line.match(/^\s*([\w\.\-]+)\s*=\s*(.*)?\s*$/);
8+
if (r !== null) {
9+
let value = r[2] || '';
10+
if (value.length > 0 && value.charAt(0) === '"' && value.charAt(value.length - 1) === '"') {
11+
value = value.replace(/\\n/gm, '\n');
12+
}
13+
env[r[1]] = value.replace(/(^['"]|['"]$)/g, '');
14+
}
15+
});
16+
return mergeEnvVariables(env);
17+
}
18+
19+
export function mergeEnvVariables(newVariables: { [key: string]: string }, mergeWith: any = process.env): any {
20+
for (let setting in mergeWith) {
21+
if (!newVariables[setting]) {
22+
newVariables[setting] = mergeWith[setting];
23+
}
24+
}
25+
26+
return newVariables;
27+
}

src/client/common/utils.ts

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import * as child_process from 'child_process';
1010
import * as settings from './configSettings';
1111
import { CancellationToken } from 'vscode';
1212
import { isNotInstalledError } from './helpers';
13+
import { mergeEnvVariables, parseEnvFile } from './envFileParser';
1314

1415
export const IS_WINDOWS = /^win/.test(process.platform);
1516
export const PATH_VARIABLE_NAME = IS_WINDOWS ? 'Path' : 'PATH';
@@ -113,19 +114,21 @@ export function execPythonFile(file: string, args: string[], cwd: string, includ
113114
}
114115

115116
if (customEnvVariables === null) {
117+
customEnvVariables = getCustomEnvVars();
118+
customEnvVariables = customEnvVariables ? customEnvVariables : {};
116119
// Ensure to include the path of the current python
117120
let newPath = '';
121+
let currentPath = typeof customEnvVariables[PATH_VARIABLE_NAME] === 'string' ? customEnvVariables[PATH_VARIABLE_NAME] : process.env[PATH_VARIABLE_NAME];
118122
if (IS_WINDOWS) {
119-
newPath = pyPath + '\\' + path.delimiter + path.join(pyPath, 'Scripts\\') + path.delimiter + process.env[PATH_VARIABLE_NAME];
123+
newPath = pyPath + '\\' + path.delimiter + path.join(pyPath, 'Scripts\\') + path.delimiter + currentPath;
120124
// This needs to be done for windows
121125
process.env[PATH_VARIABLE_NAME] = newPath;
122126
}
123127
else {
124-
newPath = pyPath + path.delimiter + process.env[PATH_VARIABLE_NAME];
128+
newPath = pyPath + path.delimiter + currentPath;
125129
}
126-
let customSettings = <{ [key: string]: string }>{};
127-
customSettings[PATH_VARIABLE_NAME] = newPath;
128-
customEnvVariables = mergeEnvVariables(customSettings);
130+
customEnvVariables = mergeEnvVariables(customEnvVariables, process.env);
131+
customEnvVariables[PATH_VARIABLE_NAME] = newPath;
129132
}
130133

131134
if (stdOut) {
@@ -224,16 +227,6 @@ function execInternal(command: string, args: string[], options: child_process.Ex
224227
});
225228
}
226229

227-
export function mergeEnvVariables(newVariables: { [key: string]: string }): any {
228-
for (let setting in process.env) {
229-
if (!newVariables[setting]) {
230-
newVariables[setting] = process.env[setting];
231-
}
232-
}
233-
234-
return newVariables;
235-
}
236-
237230
export function formatErrorForLogging(error: Error | string): string {
238231
let message: string = '';
239232
if (typeof error === 'string') {
@@ -279,4 +272,22 @@ export function getSubDirectories(rootDir: string): Promise<string[]> {
279272
resolve(subDirs);
280273
});
281274
});
275+
}
276+
277+
export function getCustomEnvVars(): any {
278+
const envFile = settings.PythonSettings.getInstance().envFile;
279+
if (typeof envFile === 'string' &&
280+
envFile.length > 0 &&
281+
fs.existsSync(envFile)) {
282+
283+
try {
284+
return parseEnvFile(envFile);
285+
}
286+
catch (ex) {
287+
console.error('Failed to load env file');
288+
console.error(ex);
289+
return null;
290+
}
291+
}
292+
return null;
282293
}

src/client/debugger/Common/Contracts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArgum
5353
cwd?: string;
5454
debugOptions?: string[];
5555
env?: Object;
56+
envFile: string;
5657
exceptionHandling?: ExceptionHandling;
5758
console?: "none" | "integratedTerminal" | "externalTerminal";
5859
}

0 commit comments

Comments
 (0)