Skip to content

Commit

Permalink
Implement optional default values in localEnv/containerEnv expansions (
Browse files Browse the repository at this point in the history
  • Loading branch information
leopoldsedev committed Aug 11, 2022
1 parent 41dfe5f commit 051f4ed
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 12 deletions.
31 changes: 19 additions & 12 deletions src/spec-common/variableSubstitution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function containerSubstitute<T extends object>(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') {
Expand Down Expand Up @@ -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;
Expand All @@ -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 '';
}
Expand Down
136 changes: 136 additions & 0 deletions src/test/variableSubstitution.test.ts
Original file line number Diff line number Diff line change
@@ -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('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');
});
});

0 comments on commit 051f4ed

Please sign in to comment.