From 3ed0dfae01caa9bfb09e582021cd80a6ffcbc871 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Fri, 25 Mar 2016 09:37:25 -0700 Subject: [PATCH] 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 --- src/vs/base/node/env.ts | 50 ++++++++++++++++++++++--------- src/vs/base/test/node/env.test.ts | 42 ++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 14 deletions(-) create mode 100644 src/vs/base/test/node/env.test.ts diff --git a/src/vs/base/node/env.ts b/src/vs/base/node/env.ts index 1d801a661d9af..524d61fb7cb49 100644 --- a/src/vs/base/node/env.ts +++ b/src/vs/base/node/env.ts @@ -35,23 +35,45 @@ export function getUserEnvironment(): TPromise { return c({}); } - let result: IEnv = Object.create(null); + c(parseEnvOutput(buffer)); + }); + }); +} - buffer.split('\n').forEach(line => { - let pos = line.indexOf('='); - if (pos > 0) { - let key = line.substring(0, pos); - let value = line.substring(pos + 1); +/** + * Parse output from `env`, attempting to retain any multiple-line variables. + */ +export function parseEnvOutput(output): IEnv { + let result: IEnv = Object.create(null); + let vars = output.split('\n'); - if (!key || typeof result[key] === 'string') { - return; - } + // Rejoin lines to the preceeding line if it doesn't look like the line is a new variable + let current = 0; + for (let i = 1; i < vars.length; i++) { + if (vars[i].match(/^[\w_][\w\d_]*=/) === null) { + vars[current] += `\n${vars[i]}`; + } else { + vars[++current] = vars[i]; + } + } - result[key] = value; - } - }); + // Trim any remaining vars that had been moved + vars.length = current + 1; - c(result); - }); + // Turn the array into a map + vars.forEach(line => { + let pos = line.indexOf('='); + if (pos > 0) { + let key = line.substring(0, pos); + let value = line.substring(pos + 1); + + if (!key || typeof result[key] === 'string') { + return; + } + + result[key] = value; + } }); + + return result; } diff --git a/src/vs/base/test/node/env.test.ts b/src/vs/base/test/node/env.test.ts new file mode 100644 index 0000000000000..1fb54f5b00e1f --- /dev/null +++ b/src/vs/base/test/node/env.test.ts @@ -0,0 +1,42 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import * as assert from 'assert'; +import env = require('vs/base/node/env'); + +suite('Env', () => { + test('Parses multi-line environment variables at end of env', function(done: () => void) { + let vars = env.parseEnvOutput("a=first\nb=multiple\nlines"); + + assert.equal(Object.keys(vars).length, 2); + assert.equal(vars['a'], "first"); + assert.equal(vars['b'], "multiple\nlines"); + + done(); + }); + + test('Parses multi-line environment variables at start of env', function(done: () => void) { + let vars = env.parseEnvOutput("a=multiple\nlines\nb=second"); + + assert.equal(Object.keys(vars).length, 2); + assert.equal(vars['a'], "multiple\nlines"); + assert.equal(vars['b'], "second"); + + done(); + }); + + test('Parses complex multi-line environment variables', function(done: () => void) { + let vars = env.parseEnvOutput("a=1\nb=\n23 =4\n_5c=56\n d=7\nE =8"); + + assert.equal(Object.keys(vars).length, 3); + assert.equal(vars['a'], "1"); + assert.equal(vars['b'], "\n23 =4"); + assert.equal(vars['_5c'], "56\n d=7\nE =8"); + + done(); + }); +}); \ No newline at end of file