Skip to content

Commit 3ed0dfa

Browse files
committed
Reland: Support multi-line environment variables
A standard Fedora install comes with 2 multiple line environment variables. Since `env` was previously split by '\n' this would break them, causing errors in the output pane and in terminals launched through the file explorer (see #3495). The original commit didn't work on OSX since `env` does not support the --null arg. This version can fail if a command line arg's 1+th line looks like an environment variable. There is no easy way to prevent this since `process.env` cannot be leveraged. Since the likelyhood of this happening is small, plus the chance of it causing any significant issue is also small it's a reasonable compromise for the time being. Fixes #3928 Fixes #4672
1 parent abfb016 commit 3ed0dfa

File tree

2 files changed

+78
-14
lines changed

2 files changed

+78
-14
lines changed

src/vs/base/node/env.ts

+36-14
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,45 @@ export function getUserEnvironment(): TPromise<IEnv> {
3535
return c({});
3636
}
3737

38-
let result: IEnv = Object.create(null);
38+
c(parseEnvOutput(buffer));
39+
});
40+
});
41+
}
3942

40-
buffer.split('\n').forEach(line => {
41-
let pos = line.indexOf('=');
42-
if (pos > 0) {
43-
let key = line.substring(0, pos);
44-
let value = line.substring(pos + 1);
43+
/**
44+
* Parse output from `env`, attempting to retain any multiple-line variables.
45+
*/
46+
export function parseEnvOutput(output): IEnv {
47+
let result: IEnv = Object.create(null);
48+
let vars = output.split('\n');
4549

46-
if (!key || typeof result[key] === 'string') {
47-
return;
48-
}
50+
// Rejoin lines to the preceeding line if it doesn't look like the line is a new variable
51+
let current = 0;
52+
for (let i = 1; i < vars.length; i++) {
53+
if (vars[i].match(/^[\w_][\w\d_]*=/) === null) {
54+
vars[current] += `\n${vars[i]}`;
55+
} else {
56+
vars[++current] = vars[i];
57+
}
58+
}
4959

50-
result[key] = value;
51-
}
52-
});
60+
// Trim any remaining vars that had been moved
61+
vars.length = current + 1;
5362

54-
c(result);
55-
});
63+
// Turn the array into a map
64+
vars.forEach(line => {
65+
let pos = line.indexOf('=');
66+
if (pos > 0) {
67+
let key = line.substring(0, pos);
68+
let value = line.substring(pos + 1);
69+
70+
if (!key || typeof result[key] === 'string') {
71+
return;
72+
}
73+
74+
result[key] = value;
75+
}
5676
});
77+
78+
return result;
5779
}

src/vs/base/test/node/env.test.ts

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
'use strict';
7+
8+
import * as assert from 'assert';
9+
import env = require('vs/base/node/env');
10+
11+
suite('Env', () => {
12+
test('Parses multi-line environment variables at end of env', function(done: () => void) {
13+
let vars = env.parseEnvOutput("a=first\nb=multiple\nlines");
14+
15+
assert.equal(Object.keys(vars).length, 2);
16+
assert.equal(vars['a'], "first");
17+
assert.equal(vars['b'], "multiple\nlines");
18+
19+
done();
20+
});
21+
22+
test('Parses multi-line environment variables at start of env', function(done: () => void) {
23+
let vars = env.parseEnvOutput("a=multiple\nlines\nb=second");
24+
25+
assert.equal(Object.keys(vars).length, 2);
26+
assert.equal(vars['a'], "multiple\nlines");
27+
assert.equal(vars['b'], "second");
28+
29+
done();
30+
});
31+
32+
test('Parses complex multi-line environment variables', function(done: () => void) {
33+
let vars = env.parseEnvOutput("a=1\nb=\n23 =4\n_5c=56\n d=7\nE =8");
34+
35+
assert.equal(Object.keys(vars).length, 3);
36+
assert.equal(vars['a'], "1");
37+
assert.equal(vars['b'], "\n23 =4");
38+
assert.equal(vars['_5c'], "56\n d=7\nE =8");
39+
40+
done();
41+
});
42+
});

0 commit comments

Comments
 (0)