From 05d3731cd10fa60468b73992499dadf2a330cf40 Mon Sep 17 00:00:00 2001 From: Garrett Campbell <86264750+gcampbell-msft@users.noreply.github.com> Date: Wed, 4 Oct 2023 07:20:50 -0400 Subject: [PATCH] Add pre/post configure script arguments globally and per configuration (#495) * initial code for pre/post-configure script arguments * fix typo in troubleshooting.md * add makefile.configurations[].preConfigureArgs and makefile.configurations[].postConfigureArgs * fix typo * only add a space after {scriptFile} if there are args * fix * slight rename --- docs/troubleshooting.md | 2 ++ package.json | 32 +++++++++++++++++ package.nls.json | 2 ++ src/configuration.ts | 78 ++++++++++++++++++++++++++++++++++++++++- src/make.ts | 25 +++++++------ 5 files changed, 127 insertions(+), 12 deletions(-) diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 3033388..37de32a 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -63,6 +63,7 @@ If the repository needs any special commands before make is successful: - Write any commands (./configure, ./bootstrap, etc...) in a script and point to it via **makefile.preconfigureScript** - In the script, we recommend you concatenate all commands into one line, separated by && (for better return code analysis) +- Any arguments that you'd like to pass to the preConfigureScript should be set via **makefile.preConfigureArgs** - From the Command Pallette, run the **Makefile: Pre-Configure** command once before configuring your project. - If you need this every time, set **makefile.alwaysPreConfigure** to `true` @@ -70,6 +71,7 @@ If the repository or build needs any special commands to clean up after a build: - Write any commands in a script and point it via **makefile.postConfigureScript** - In the script, we recommend you concatentate all commands into one line, seperated by && (for better return code analysis) +- Any arguments that you'd like to pass to the postConfigureScript should be set via **makefile.postConfigureArgs** - From the Command Pallette, run the **Makefile: Post-Configure** command once after configuring your project. - If you need this every time, set **makefile.alwaysPostConfigure** to `true` diff --git a/package.json b/package.json index 9b5d9ac..fb8ad86 100644 --- a/package.json +++ b/package.json @@ -293,6 +293,22 @@ "buildLog": { "type": "string", "description": "%makefile-tools.configuration.makefile.configurations.buildLog.description%" + }, + "preConfigureArgs": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "%makefile-tools.configuration.makefile.preConfigureArgs.description%" + }, + "postConfigureArgs": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "%makefile-tools.configuration.makefile.postConfigureArgs.description%" } } }, @@ -482,12 +498,28 @@ "default": null, "scope": "resource" }, + "makefile.preConfigureArgs": { + "type": "array", + "description": "%makefile-tools.configuration.makefile.preConfigureArgs.description%", + "items": { + "type": "string" + }, + "default": [] + }, "makefile.postConfigureScript": { "type": "string", "description": "%makefile-tools.configuration.makefile.postConfigureScript.description%", "default": null, "scope": "resource" }, + "makefile.postConfigureArgs": { + "type": "array", + "description": "%makefile-tools.configuration.makefile.postConfigureArgs.description%", + "items": { + "type": "string" + }, + "default": [] + }, "makefile.alwaysPreConfigure": { "type": "boolean", "description": "%makefile-tools.configuration.makefile.alwaysPreConfigure.description%", diff --git a/package.nls.json b/package.nls.json index 70aa16c..61e3e55 100644 --- a/package.nls.json +++ b/package.nls.json @@ -56,7 +56,9 @@ "makefile-tools.configuration.makefile.configureOnEdit.description": "Automatically configure Makefile project directories when any relevant makefiles and/or settings are changed", "makefile-tools.configuration.makefile.configureAfterCommand.description": "Automatically configure Makefile project directories after relevant operations, like change build configuration or makefile target", "makefile-tools.configuration.makefile.preConfigureScript.description": "The path to the script that needs to be run at least once before configure", + "makefile-tools.configuration.makefile.preConfigureArgs.description": "Arguments to pass to the preConfigureScript", "makefile-tools.configuration.makefile.postConfigureScript.description": "The path to the script that needs to be run at least once after configure", + "makefile-tools.configuration.makefile.postConfigureArgs.description": "Arguments to pass to the postConfigureScript", "makefile-tools.configuration.makefile.alwaysPreConfigure.description": "Always run the pre-configure script before configure", "makefile-tools.configuration.makefile.alwaysPostConfigure.description": "Always run the post-configure script after configure", "makefile-tools.configuration.makefile.ignoreDirectoryCommands.description": "Don't analyze directory changing commands like cd, push, pop.", diff --git a/src/configuration.ts b/src/configuration.ts index ed5b23f..fd9e49c 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -57,6 +57,12 @@ export interface MakefileConfiguration { // instead of the dry-run output of the make tool buildLog?: string; + // arguments for the pre configure script + preConfigureArgs?: string[]; + + // arguments for the post configure script + postConfigureArgs?: string[] + // TODO: investigate how flexible this is to integrate with other build systems than the MAKE family // (basically anything that can produce a dry-run output is sufficient) // Implement set-able dry-run, verbose, change-directory and always-make switches @@ -360,10 +366,18 @@ let preConfigureScript: string | undefined; export function getPreConfigureScript(): string | undefined { return preConfigureScript; } export function setPreConfigureScript(path: string): void { preConfigureScript = path; } +let preConfigureArgs: string[] = []; +export function getPreConfigureArgs(): string[] { return preConfigureArgs; } +export function setPreConfigureArgs(args: string[]): void { preConfigureArgs = args; } + let postConfigureScript: string | undefined; export function getPostConfigureScript(): string | undefined { return postConfigureScript; } export function setPostConfigureScript(path: string): void { postConfigureScript = path; } +let postConfigureArgs: string[] = []; +export function getPostConfigureArgs(): string[] { return postConfigureArgs; } +export function setPostConfigureArgs(args: string[]): void { postConfigureArgs = args; } + // Read from settings the path to a script file that needs to have been run at least once // before a sucessful configure of this project. export async function readPreConfigureScript(): Promise { @@ -377,6 +391,13 @@ export async function readPreConfigureScript(): Promise { } } +export async function readPreConfigureArgs(): Promise { + preConfigureArgs = await util.getExpandedSetting("preConfigureArgs") ?? []; + if (preConfigureArgs && preConfigureArgs.length > 0) { + logger.message(`Pre-configure arguments: '${preConfigureArgs.join("', '")}'`); + } +} + export async function readPostConfigureScript(): Promise { postConfigureScript = await util.getExpandedSetting("postConfigureScript"); if (postConfigureScript) { @@ -388,6 +409,13 @@ export async function readPostConfigureScript(): Promise { } } +export async function readPostConfigureArgs(): Promise { + postConfigureArgs = await util.getExpandedSetting("postConfigureArgs") ?? []; + if (postConfigureArgs && postConfigureArgs.length > 0) { + logger.message(`Post-configure arguments: '${postConfigureArgs.join("', '")}'`); + } +} + let alwaysPreConfigure: boolean | undefined; export function getAlwaysPreConfigure(): boolean | undefined { return alwaysPreConfigure; } export function setAlwaysPreConfigure(path: boolean): void { alwaysPreConfigure = path; } @@ -650,6 +678,14 @@ let configurationBuildLog: string | undefined; export function getConfigurationBuildLog(): string | undefined { return configurationBuildLog; } export function setConfigurationBuildLog(name: string): void { configurationBuildLog = name; } +let configurationPreConfigureArgs: string[] = []; +export function getConfigurationPreConfigureArgs(): string[] { return configurationPreConfigureArgs; } +export function setConfigurationPreConfigureArgs(args: string[]): void { configurationPreConfigureArgs = args; } + +let configurationPostConfigureArgs: string[] = []; +export function getConfigurationPostConfigureArgs(): string[] { return configurationPostConfigureArgs; } +export function setConfigurationPostConfigureArgs(args: string[]): void { configurationPostConfigureArgs = args; } + // Analyze the settings of the current makefile configuration and the global workspace settings, // according to various merging rules and decide what make command and build log // apply to the current makefile configuration. @@ -657,9 +693,11 @@ async function analyzeConfigureParams(): Promise { getBuildLogForConfiguration(currentMakefileConfiguration); await getCommandForConfiguration(currentMakefileConfiguration); getProblemMatchersForConfiguration(currentMakefileConfiguration); + getPreConfigureArgsForConfiguration(currentMakefileConfiguration); + getPostConfigureArgsForConfiguration(currentMakefileConfiguration); } -function getMakefileConfiguration(configuration: string | undefined): MakefileConfiguration | undefined { +export function getMakefileConfiguration(configuration: string | undefined): MakefileConfiguration | undefined { return makefileConfigurations.find(k => { if (k.name === configuration) { return k; @@ -866,6 +904,28 @@ export function getBuildLogForConfiguration(configuration: string | undefined): } } +export function getPreConfigureArgsForConfiguration(configuration: string | undefined): void { + let makefileConfiguration: MakefileConfiguration | undefined = getMakefileConfiguration(configuration); + const localPreConfigArgs = makefileConfiguration?.preConfigureArgs; + + if (localPreConfigArgs) { + configurationPreConfigureArgs = localPreConfigArgs; + } else { + configurationPreConfigureArgs = preConfigureArgs; + } +} + +export function getPostConfigureArgsForConfiguration(configuration: string | undefined): void { + let makefileConfiguration: MakefileConfiguration | undefined = getMakefileConfiguration(configuration); + const localPostConfigArgs = makefileConfiguration?.postConfigureArgs; + + if (localPostConfigArgs) { + configurationPostConfigureArgs = localPostConfigArgs; + } else { + configurationPostConfigureArgs = postConfigureArgs; + } +} + let makefileConfigurations: MakefileConfiguration[] = []; export function getMakefileConfigurations(): MakefileConfiguration[] { return makefileConfigurations; } export function setMakefileConfigurations(configurations: MakefileConfiguration[]): void { makefileConfigurations = configurations; } @@ -1065,8 +1125,10 @@ export async function initFromSettings(activation: boolean = false): Promise(subKey); + if (updatedPreConfigureArgs && !util.areEqual(updatedPreConfigureArgs, preConfigureArgs)) { + await readPreConfigureArgs(); + updatedSettingsSubkeys.push(subKey); + } + subKey = "postConfigureScript"; let updatedPostConfigureScript: string | undefined = await util.getExpandedSetting(subKey); if (updatedPostConfigureScript) { @@ -1267,6 +1336,13 @@ export async function initFromSettings(activation: boolean = false): Promise(subKey); + if (updatedPostConfigureArgs && !util.areEqual(updatedPostConfigureArgs, postConfigureArgs)) { + await readPostConfigureArgs(); + updatedSettingsSubkeys.push(subKey); + } + subKey = "alwaysPreConfigure"; let updatedAlwaysPreConfigure : boolean | undefined = await util.getExpandedSetting(subKey); if (updatedAlwaysPreConfigure !== alwaysPreConfigure) { diff --git a/src/make.ts b/src/make.ts index 21e5a40..ba26b46 100644 --- a/src/make.ts +++ b/src/make.ts @@ -704,7 +704,7 @@ export async function preConfigure(triggeredBy: TriggeredBy): Promise { }); } -export async function postConfigure(triggeredBy: TriggeredBy, ): Promise { +export async function postConfigure(triggeredBy: TriggeredBy): Promise { let scriptFile: string | undefined = configuration.getPostConfigureScript(); if (!scriptFile) { vscode.window.showErrorMessage("Post-configure failed: no script provided."); @@ -752,14 +752,15 @@ async function applyEnvironment(content: string | undefined) : Promise { }); } -export async function runPrePostConfigureScript(progress: vscode.Progress<{}>, scriptFile: string, loggingMessages: { success: string, successWithSomeError: string, failure: string}): Promise { +export async function runPrePostConfigureScript(progress: vscode.Progress<{}>, scriptFile: string, scriptArgs: string[], loggingMessages: { success: string, successWithSomeError: string, failure: string}): Promise { // Create a temporary wrapper for the user pre-configure script so that we collect // in another temporary output file the environrment variables that were produced. let wrapScriptFile: string = path.join(util.tmpDir(), "wrapConfigureScript"); let wrapScriptOutFile: string = wrapScriptFile + ".out"; let wrapScriptContent: string; if (process.platform === "win32") { - wrapScriptContent = `call "${scriptFile}"\r\n`; + wrapScriptContent = `call "${scriptFile}"`; + wrapScriptContent += scriptArgs.length > 0 ? `${scriptArgs.join(" ").toString()}\r\n` : "\r\n"; wrapScriptContent += `set > "${wrapScriptOutFile}"`; wrapScriptFile += ".bat"; } else { @@ -770,16 +771,16 @@ export async function runPrePostConfigureScript(progress: vscode.Progress<{}>, s util.writeFile(wrapScriptFile, wrapScriptContent); - let scriptArgs: string[] = []; + let concreteScriptArgs: string[] = []; let runCommand: string; if (process.platform === 'win32') { runCommand = "cmd"; - scriptArgs.push("/c"); - scriptArgs.push(`"${wrapScriptFile}"`); + concreteScriptArgs.push("/c"); + concreteScriptArgs.push(`"${wrapScriptFile}"`); } else { runCommand = "/bin/bash"; - scriptArgs.push("-c"); - scriptArgs.push(`"source '${wrapScriptFile}'"`); + concreteScriptArgs.push("-c"); + concreteScriptArgs.push(`"source '${wrapScriptFile}'"`); } try { @@ -795,7 +796,7 @@ export async function runPrePostConfigureScript(progress: vscode.Progress<{}>, s }; // The preconfigure invocation should use the system locale. - const result: util.SpawnProcessResult = await util.spawnChildProcess(runCommand, scriptArgs, util.getWorkspaceRoot(), false, false, stdout, stderr); + const result: util.SpawnProcessResult = await util.spawnChildProcess(runCommand, concreteScriptArgs, util.getWorkspaceRoot(), false, false, stdout, stderr); if (result.returnCode === ConfigureBuildReturnCodeTypes.success) { if (someErr) { // Depending how the preconfigure scripts (and any inner called sub-scripts) are written, @@ -826,7 +827,8 @@ export async function runPrePostConfigureScript(progress: vscode.Progress<{}>, s export async function runPreConfigureScript(progress: vscode.Progress<{}>, scriptFile: string): Promise { logger.message(`Pre-configuring...\nScript: "${configuration.getPreConfigureScript()}"`); - return await runPrePostConfigureScript(progress, scriptFile, { + const currentConfigPreConfigureArgs = configuration.getConfigurationPreConfigureArgs(); + return await runPrePostConfigureScript(progress, scriptFile, currentConfigPreConfigureArgs.length > 0 ? currentConfigPreConfigureArgs : configuration.getPreConfigureArgs(), { success: "The pre-configure succeeded.", successWithSomeError: "The pre-configure script returned success code " + "but somewhere during the preconfigure process there were errors reported. " + @@ -838,7 +840,8 @@ export async function runPreConfigureScript(progress: vscode.Progress<{}>, scrip export async function runPostConfigureScript(progress: vscode.Progress<{}>, scriptFile: string): Promise { logger.message(`Post-configuring...\nScript: "${configuration.getPostConfigureScript()}"`); - return await runPrePostConfigureScript(progress, scriptFile, { + const currentConfigPostConfigureArgs = configuration.getConfigurationPostConfigureArgs(); + return await runPrePostConfigureScript(progress, scriptFile, currentConfigPostConfigureArgs.length > 0 ? currentConfigPostConfigureArgs : configuration.getPostConfigureArgs(), { success: "The post-configure succeeded.", successWithSomeError: "The post-configure script returned success code " +