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 $penv{} in include paths #3377

Merged
merged 3 commits into from Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -10,6 +10,7 @@ Improvements:
- In multi-root workspace, the Project Outline View now shows all configured projects. [PR #3270](https://github.com/microsoft/vscode-cmake-tools/pull/3270) [@vlavati](https://github.com/vlavati)
- Added script mode and ability to connect to externally launched CMake processes. [PR #3277](https://github.com/microsoft/vscode-cmake-tools/pull/3277)
- Added buttons to the project nodes in the Project Outline View. [PR #3354](https://github.com/microsoft/vscode-cmake-tools/pull/3354) [@vlavati](https://github.com/vlavati)
- `$penv{}` macros are expanded in `include` paths in CMakePresets.json as long as `version` is 7 or higher. [#3310](https://github.com/microsoft/vscode-cmake-tools/issues/3310)

Bug Fixes:
- Fix Unhandled Exception if no args are specified in `cmake.getLaunchTargetFilename` inside an input context of a task. [PR #3348](https://github.com/microsoft/vscode-cmake-tools/issues/3348) [@vlavati](https://github.com/vlavati)
Expand Down
48 changes: 30 additions & 18 deletions src/expand.ts
Expand Up @@ -126,6 +126,11 @@ export async function expandString<T>(input: string | T, opts: ExpansionOptions)
return replaceAll(result, '${dollar}', '$');
}

// Regular expression for variable value (between the variable suffix and the next ending curly bracket):
// .+? matches any character (except line terminators) between one and unlimited times,
// as few times as possible, expanding as needed (lazy)
const varValueRegexp = ".+?";

async function expandStringHelper(input: string, opts: ExpansionOptions) {
const envPreNormalize = opts.envOverride ? opts.envOverride : process.env;
const env = EnvironmentUtils.create(envPreNormalize);
Expand Down Expand Up @@ -153,10 +158,6 @@ async function expandStringHelper(input: string, opts: ExpansionOptions) {
}
}

// Regular expression for variable value (between the variable suffix and the next ending curly bracket):
// .+? matches any character (except line terminators) between one and unlimited times,
// as few times as possible, expanding as needed (lazy)
const varValueRegexp = ".+?";
const envRegex1 = RegExp(`\\$\\{env:(${varValueRegexp})\\}`, "g");
while ((mat = envRegex1.exec(input))) {
const full = mat[0];
Expand Down Expand Up @@ -189,13 +190,7 @@ async function expandStringHelper(input: string, opts: ExpansionOptions) {
subs.set(full, replacement);
}

const parentEnvRegex = RegExp(`\\$penv\\{(${varValueRegexp})\\}`, "g");
while ((mat = parentEnvRegex.exec(input))) {
const full = mat[0];
const varName = mat[1];
const replacement = fixPaths(process.env[varName]) || '';
subs.set(full, replacement);
}
getParentEnvSubstitutions(input, subs);

if (vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) {
const folderRegex = RegExp(`\\$\\{workspaceFolder:(${varValueRegexp})\\}`, "g");
Expand Down Expand Up @@ -241,6 +236,19 @@ async function expandStringHelper(input: string, opts: ExpansionOptions) {
}
}

return { ...substituteAll(input, subs), circularReference };
}

export async function expandStrings(inputs: string[], opts: ExpansionOptions): Promise<string[]> {
const expandedInputs: string[] = [];
for (const input of inputs) {
const expandedInput: string = await expandString(input, opts);
expandedInputs.push(expandedInput);
}
return expandedInputs;
}

export function substituteAll(input: string, subs: Map<string, string>) {
let finalString = input;
let didReplacement = false;
subs.forEach((value, key) => {
Expand All @@ -249,14 +257,18 @@ async function expandStringHelper(input: string, opts: ExpansionOptions) {
didReplacement = true;
}
});
return { result: finalString, didReplacement, circularReference };
return { result: finalString, didReplacement };
}

export async function expandStrings(inputs: string[], opts: ExpansionOptions): Promise<string[]> {
const expandedInputs: string[] = [];
for (const input of inputs) {
const expandedInput: string = await expandString(input, opts);
expandedInputs.push(expandedInput);
export function getParentEnvSubstitutions(input: string, subs: Map<string, string>): Map<string, string> {
let mat: RegExpMatchArray | null = null;
const parentEnvRegex = RegExp(`\\$penv\\{(${varValueRegexp})\\}`, "g");
while ((mat = parentEnvRegex.exec(input))) {
const full = mat[0];
const varName = mat[1];
const replacement = fixPaths(process.env[varName]) || '';
subs.set(full, replacement);
}
return expandedInputs;

return subs;
}
9 changes: 7 additions & 2 deletions src/presetsController.ts
Expand Up @@ -9,7 +9,7 @@ import { fs } from '@cmt/pr';
import * as preset from '@cmt/preset';
import * as util from '@cmt/util';
import rollbar from '@cmt/rollbar';
import { ExpansionOptions } from '@cmt/expand';
import { ExpansionOptions, getParentEnvSubstitutions, substituteAll } from '@cmt/expand';
import paths from '@cmt/paths';
import { KitsController } from '@cmt/kitsController';
import { descriptionForKit, Kit, SpecialKits } from '@cmt/kit';
Expand Down Expand Up @@ -1025,7 +1025,12 @@ export class PresetsController {

// Merge the includes in reverse order so that the final presets order is correct
for (let i = presetsFile.include.length - 1; i >= 0; i--) {
const fullIncludePath = path.normalize(path.resolve(path.dirname(file), presetsFile.include[i]));
const rawInclude = presetsFile.include[i];
const includePath = presetsFile.version >= 7 ?
// Version 7 and later support $penv{} expansions in include paths
substituteAll(rawInclude, getParentEnvSubstitutions(rawInclude, new Map<string, string>())).result :
presetsFile.include[i];
benmcmorran marked this conversation as resolved.
Show resolved Hide resolved
const fullIncludePath = path.normalize(path.resolve(path.dirname(file), includePath));

// Do not include files more than once
if (referencedFiles.has(fullIncludePath)) {
Expand Down