Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support usage of env vars for Kit.toolchainFile #991

Merged
merged 11 commits into from
Oct 7, 2020
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# What's New?

## 1.5.0
Improvements:
- Support variables for Kit.toolchainFile. [#991](https://github.com/microsoft/vscode-cmake-tools/pull/991)[#1056](https://github.com/microsoft/vscode-cmake-tools/issues/1056) [@blakehurd](https://github.com/blakehurd)/[@bobbrow](https://github.com/bobbrow)

## 1.4.2
Improvements:
- Added new variable substitution command: `${command:cmake.launchTargetFilename}`. [#632](https://github.com/microsoft/vscode-cmake-tools/issues/632) [@ebai101](https://github.com/ebai101)
Expand Down
20 changes: 16 additions & 4 deletions src/expand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,25 +92,37 @@ export async function expandString(tmpl: string, opts: ExpansionOptions) {
}
}

const env_re = /\$\{env:(.+?)\}/g;
const env_re = /\$\{env:(.+)\}/g;
while ((mat = env_re.exec(tmpl))) {
const full = mat[0];
const varname = mat[1];
const repl = fixPaths(env[normalizeEnvironmentVarname(varname)]) || '';
subs.set(full, repl);
}

const env_re2 = /\$\{env\.(.+?)\}/g;
const env_re2 = /\$\{env\.(.+)\}/g;
while ((mat = env_re2.exec(tmpl))) {
const full = mat[0];
const varname = mat[1];
const repl = fixPaths(env[normalizeEnvironmentVarname(varname)]) || '';
subs.set(full, repl);
}

if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
const folder_re = /\$\{workspaceFolder:(.+)\}/g;
while (mat = folder_re.exec(tmpl)) {
const full = mat[0];
const folderName = mat[1];
const f = vscode.workspace.workspaceFolders.find(folder => folder.name.toLocaleLowerCase() === folderName.toLocaleLowerCase());
if (f) {
subs.set(full, f.uri.fsPath);
}
}
}

if (opts.variantVars) {
const variants = opts.variantVars;
const variant_regex = /\$\{variant:(.+?)\}/g;
const variant_regex = /\$\{variant:(.+)\}/g;
while ((mat = variant_regex.exec(tmpl))) {
const full = mat[0];
const varname = mat[1];
Expand All @@ -119,7 +131,7 @@ export async function expandString(tmpl: string, opts: ExpansionOptions) {
}
}

const command_re = /\$\{command:(.+?)\}/g;
const command_re = /\$\{command:(.+)\}/g;
while ((mat = command_re.exec(tmpl))) {
const full = mat[0];
const command = mat[1];
Expand Down
20 changes: 19 additions & 1 deletion src/kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,24 @@ export async function descriptionForKit(kit: Kit): Promise<string> {
return localize('unspecified.let.cmake.guess', 'Unspecified (Let CMake guess what compilers and environment to use)');
}

async function expandKitVariables(kit: Kit): Promise<Kit> {
if (kit.toolchainFile) {
kit.toolchainFile = await expand.expandString(kit.toolchainFile, {
vars: {
buildKit: kit.name,
buildType: '${buildType}', // Unsupported variable substitutions use identity.
generator: '${generator}',
userHome: paths.userHome,
workspaceFolder: '${workspaceFolder}',
workspaceFolderBasename: '${workspaceFolderBasename}',
workspaceRoot: '${workspaceRoot}',
workspaceRootFolderName: '${workspaceRootFolderName}'
}
});
}
return kit;
}

export async function readKitsFile(filepath: string): Promise<Kit[]> {
if (!await fs.exists(filepath)) {
log.debug(localize('not.reading.nonexistent.kit', 'Not reading non-existent kits file: {0}', filepath));
Expand All @@ -1062,7 +1080,7 @@ export async function readKitsFile(filepath: string): Promise<Kit[]> {
}
const kits = kits_raw as Kit[];
log.info(localize('successfully.loaded.kits', 'Successfully loaded {0} kits from {1}', kits.length, filepath));
return dropNulls(kits);
return Promise.all(dropNulls(kits).map(expandKitVariables));
}

function convertMingwDirsToSearchPaths(mingwDirs: string[]): string[] {
Expand Down
20 changes: 19 additions & 1 deletion test/unit-tests/kitmanager.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {readKitsFile, getShellScriptEnvironment} from '@cmt/kit';
import {expect} from '@test/util';
import * as path from 'path';
import * as vscode from 'vscode';
import paths from '@cmt/paths';
import {fs} from '@cmt/pr';

Expand All @@ -11,8 +12,14 @@ function getTestResourceFilePath(filename: string): string {
return path.normalize(path.join(here, '../../../test/unit-tests', filename));
}

// for safety, ensure we reset the state of the process.env after every test since we're manipulating it in this suite.
const env = {...process.env};

suite('Kits test', async () => {
teardown(() => {
process.env = env;
});

test('Test load of kit from test file', async () => {
const kits = await readKitsFile(getTestResourceFilePath('test_kit.json'));
const names = kits.map(k => k.name);
Expand All @@ -21,11 +28,22 @@ suite('Kits test', async () => {
'CompilerKit 2',
'CompilerKit 3 with PreferredGenerator',
'ToolchainKit 1',
'ToolchainKit 2',
'ToolchainKit 3',
'VSCode Kit 1',
'VSCode Kit 2',
]);
});

test('Test use of env var in toolchain kit specified from test file', async () => {
process.env.CMAKE_TOOLS_TEST_SOME_ENV_VAR = "Test";
const folderName = vscode.workspace.workspaceFolders ? vscode.workspace.workspaceFolders[0].uri.fsPath : "";
const kits = await readKitsFile(getTestResourceFilePath('test_kit.json'));

expect(kits.filter(k => "ToolchainKit 2" === k.name)[0].toolchainFile).to.eq("Test/toolchain.cmake");
expect(kits.filter(k => "ToolchainKit 3" === k.name)[0].toolchainFile).to.eq(`${folderName}/toolchain.cmake`);
});

test('Test load env vars from shell script', async() => {
const fname_extension = process.platform == 'win32' ? 'bat' : 'sh';
const fname = `cmake-kit-test-${Math.random().toString()}.${fname_extension}`;
Expand All @@ -50,4 +68,4 @@ suite('Kits test', async () => {
expect(env_vars_arr).to.deep.include(['TESTVAR13', 'cde']);
}
});
});
});
8 changes: 8 additions & 0 deletions test/unit-tests/test_kit.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@
"name": "ToolchainKit 1",
"toolchainFile": "toolchain.cmake"
},
{
"name": "ToolchainKit 2",
"toolchainFile": "${env:CMAKE_TOOLS_TEST_SOME_ENV_VAR}/toolchain.cmake"
},
{
"name": "ToolchainKit 3",
"toolchainFile": "${workspaceFolder:test-project-without-cmakelists}/toolchain.cmake"
},
{
"name": "VSCode Kit 1",
"visualStudio": "Visual Studio 2015",
Expand Down