From 440b1f7ef4cf59e1e2878699a3ce5aa01f74c85b Mon Sep 17 00:00:00 2001 From: Christian Leopoldseder Date: Thu, 9 Jun 2022 17:06:42 +0200 Subject: [PATCH 1/3] Implement optional default values in localEnv/containerEnv expansions (#50) --- src/spec-common/variableSubstitution.ts | 31 +++++++++++++++---------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/spec-common/variableSubstitution.ts b/src/spec-common/variableSubstitution.ts index c1dd969f9..f7d2c67ad 100644 --- a/src/spec-common/variableSubstitution.ts +++ b/src/spec-common/variableSubstitution.ts @@ -37,7 +37,7 @@ export function containerSubstitute(platform: NodeJS.Platform, return substitute0(replaceContainerEnv.bind(undefined, isWindows, configFile, normalizeEnv(isWindows, containerEnv)), value); } -type Replace = (match: string, variable: string, argument: string | undefined) => string; +type Replace = (match: string, variable: string, args: string[]) => string; function substitute0(replace: Replace, value: any): any { if (typeof value === 'string') { @@ -75,21 +75,21 @@ function resolveString(replace: Replace, value: string): string { function evaluateSingleVariable(replace: Replace, match: string, variable: string): string { // try to separate variable arguments from variable name - let argument: string | undefined; + let args: string[] = []; const parts = variable.split(':'); if (parts.length > 1) { variable = parts[0]; - argument = parts[1]; + args = parts.slice(1); } - return replace(match, variable, argument); + return replace(match, variable, args); } -function replaceWithContext(isWindows: boolean, context: SubstitutionContext, match: string, variable: string, argument: string | undefined) { +function replaceWithContext(isWindows: boolean, context: SubstitutionContext, match: string, variable: string, args: string[]) { switch (variable) { case 'env': case 'localEnv': - return lookupValue(isWindows, context.env, argument, match, context.configFile); + return lookupValue(isWindows, context.env, args, match, context.configFile); case 'localWorkspaceFolder': return context.localWorkspaceFolder !== undefined ? context.localWorkspaceFolder : match; @@ -108,25 +108,32 @@ function replaceWithContext(isWindows: boolean, context: SubstitutionContext, ma } } -function replaceContainerEnv(isWindows: boolean, configFile: URI | undefined, containerEnvObj: NodeJS.ProcessEnv, match: string, variable: string, argument: string | undefined) { +function replaceContainerEnv(isWindows: boolean, configFile: URI | undefined, containerEnvObj: NodeJS.ProcessEnv, match: string, variable: string, args: string[]) { switch (variable) { case 'containerEnv': - return lookupValue(isWindows, containerEnvObj, argument, match, configFile); + return lookupValue(isWindows, containerEnvObj, args, match, configFile); default: return match; } } -function lookupValue(isWindows: boolean, envObj: NodeJS.ProcessEnv, argument: string | undefined, match: string, configFile: URI | undefined) { - if (argument) { +function lookupValue(isWindows: boolean, envObj: NodeJS.ProcessEnv, args: string[], match: string, configFile: URI | undefined) { + if (args.length > 0) { + let envVariableName = args[0]; if (isWindows) { - argument = argument.toLowerCase(); + envVariableName = envVariableName.toLowerCase(); } - const env = envObj[argument]; + const env = envObj[envVariableName]; if (typeof env === 'string') { return env; } + + if (args.length > 1) { + const defaultValue = args[1]; + return defaultValue; + } + // For `env` we should do the same as a normal shell does - evaluates missing envs to an empty string #46436 return ''; } From 1dee83f713dbefe1ad8be086776bbd20dd5fc6a3 Mon Sep 17 00:00:00 2001 From: Christian Leopoldseder Date: Thu, 9 Jun 2022 17:10:10 +0200 Subject: [PATCH 2/3] Add tests for variableSubstitution --- src/test/variableSubstitution.test.ts | 136 ++++++++++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 src/test/variableSubstitution.test.ts diff --git a/src/test/variableSubstitution.test.ts b/src/test/variableSubstitution.test.ts new file mode 100644 index 000000000..c494cb3f3 --- /dev/null +++ b/src/test/variableSubstitution.test.ts @@ -0,0 +1,136 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + *--------------------------------------------------------------------------------------------*/ + +import * as assert from 'assert'; + +import { substitute } from '../spec-common/variableSubstitution'; +import { URI } from 'vscode-uri'; + +describe.only('Variable substitution', function () { + + it(`environment variables`, async () => { + const raw = { + foo: 'bar${env:baz}bar' + }; + const result = substitute({ + platform: 'linux', + localWorkspaceFolder: '/foo/bar', + containerWorkspaceFolder: '/baz/blue', + configFile: URI.file('/foo/bar/baz.json'), + env: { + baz: 'somevalue' + }, + }, raw); + assert.strictEqual(result.foo, 'barsomevaluebar'); + }); + + it(`localWorkspaceFolder`, async () => { + const raw = { + foo: 'bar${localWorkspaceFolder}bar' + }; + const result = substitute({ + platform: 'linux', + localWorkspaceFolder: '/foo/bar', + containerWorkspaceFolder: '/baz/blue', + configFile: URI.file('/foo/bar/baz.json'), + env: { + baz: 'somevalue' + }, + }, raw); + assert.strictEqual(result.foo, 'bar/foo/barbar'); + }); + + it(`containerWorkspaceFolder`, async () => { + const raw = { + foo: 'bar${containerWorkspaceFolder}bar' + }; + const result = substitute({ + platform: 'linux', + localWorkspaceFolder: '/foo/bar', + containerWorkspaceFolder: '/baz/blue', + configFile: URI.file('/foo/bar/baz.json'), + env: { + baz: 'somevalue' + }, + }, raw); + assert.strictEqual(result.foo, 'bar/baz/bluebar'); + }); + + it(`localWorkspaceFolderBasename and containerWorkspaceFolder`, async () => { + const raw = { + foo: 'bar${containerWorkspaceFolder}bar' + }; + const result = substitute({ + platform: 'linux', + localWorkspaceFolder: '/foo/red', + containerWorkspaceFolder: '/baz/${localWorkspaceFolderBasename}', + configFile: URI.file('/foo/bar/baz.json'), + env: { + baz: 'somevalue' + }, + }, raw); + assert.strictEqual(result.foo, 'bar/baz/redbar'); + }); + + it(`environment variables with default value if they do not exist`, async () => { + const raw = { + foo: 'bar${localEnv:baz:default}bar' + }; + const result = substitute({ + platform: 'linux', + localWorkspaceFolder: '/foo/bar', + containerWorkspaceFolder: '/baz/blue', + configFile: URI.file('/foo/bar/baz.json'), + env: { + }, + }, raw); + assert.strictEqual(result.foo, 'bardefaultbar'); + }); + + it(`environment variables without default value if they do not exist`, async () => { + const raw = { + foo: 'bar${localEnv:baz}bar' + }; + const result = substitute({ + platform: 'linux', + localWorkspaceFolder: '/foo/bar', + containerWorkspaceFolder: '/baz/blue', + configFile: URI.file('/foo/bar/baz.json'), + env: { + }, + }, raw); + assert.strictEqual(result.foo, 'barbar'); + }); + + it(`environment variables with default value if they do not exist`, async () => { + const raw = { + foo: 'bar${localEnv:baz:default}bar' + }; + const result = substitute({ + platform: 'linux', + localWorkspaceFolder: '/foo/bar', + containerWorkspaceFolder: '/baz/blue', + configFile: URI.file('/foo/bar/baz.json'), + env: { + baz: 'somevalue' + }, + }, raw); + assert.strictEqual(result.foo, 'barsomevaluebar'); + }); + + it(`environment variables without default value if they do not exist`, async () => { + const raw = { + foo: 'bar${localEnv:baz:default:a:b:c}bar' + }; + const result = substitute({ + platform: 'linux', + localWorkspaceFolder: '/foo/bar', + containerWorkspaceFolder: '/baz/blue', + configFile: URI.file('/foo/bar/baz.json'), + env: { + }, + }, raw); + assert.strictEqual(result.foo, 'bardefaultbar'); + }); +}); From 0230cc58845015d4a25a6a25c98f9e764200e7e7 Mon Sep 17 00:00:00 2001 From: Christof Marti Date: Thu, 11 Aug 2022 08:04:44 +0200 Subject: [PATCH 3/3] Remove .only --- src/test/variableSubstitution.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/variableSubstitution.test.ts b/src/test/variableSubstitution.test.ts index c494cb3f3..218bcc4d0 100644 --- a/src/test/variableSubstitution.test.ts +++ b/src/test/variableSubstitution.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { substitute } from '../spec-common/variableSubstitution'; import { URI } from 'vscode-uri'; -describe.only('Variable substitution', function () { +describe('Variable substitution', function () { it(`environment variables`, async () => { const raw = {