From af9984f73bbe88ffc755dd5292c71a1eb0687bdb Mon Sep 17 00:00:00 2001 From: Arvind Ranasaria Date: Fri, 25 Oct 2019 12:06:55 -0700 Subject: [PATCH] pass install paths to notebooks (#8008) * pass install paths to notebooks * onComplete * discover and publish actual installation Path * pass the path to notebook * minor fixes needed post merge of code from remote * fix some errors * remove unused variable --- .../notebooks/bdc/2019/deploy-bdc-aks.ipynb | 33 ++++++++-- .../bdc/2019/deploy-bdc-existing-aks.ipynb | 31 ++++++++-- .../2019/deploy-bdc-existing-kubeadm.ipynb | 26 +++++++- .../resource-deployment/src/interfaces.ts | 3 +- .../src/services/platformService.ts | 4 +- .../src/services/tools/azCliTool.ts | 13 +++- .../src/services/tools/azdataTool.ts | 23 ++++--- .../src/services/tools/dockerTool.ts | 1 + .../src/services/tools/kubeCtlTool.ts | 16 +++++ .../src/services/tools/toolBase.ts | 62 ++++++++++++++----- .../src/ui/deployClusterWizard/constants.ts | 1 + .../deployClusterWizardModel.ts | 2 + .../resource-deployment/src/ui/dialogBase.ts | 3 +- .../src/ui/resourceTypePickerDialog.ts | 3 +- extensions/resource-deployment/src/utils.ts | 18 ++++++ 15 files changed, 195 insertions(+), 44 deletions(-) diff --git a/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-aks.ipynb b/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-aks.ipynb index 2b30472ff6..9c52dff8df 100644 --- a/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-aks.ipynb +++ b/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-aks.ipynb @@ -57,7 +57,7 @@ { "cell_type": "markdown", "source": [ - "### **Check dependencies**" + "### **Setup**" ], "metadata": { "azdata_cell_guid": "a56d3413-a730-4997-b5c2-c8abd972757e" @@ -78,11 +78,7 @@ " !{command}\n", " if _exit_code != 0:\n", " sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n\\t{command}\\n')\n", - " print(f'Successfully executed: {command}')\n", - "\n", - "run_command('kubectl version --client=true')\n", - "run_command('azdata --version')\n", - "run_command('az --version')" + " print(f'Successfully executed: {command}')" ], "metadata": { "azdata_cell_guid": "326645cf-022a-47f2-8aff-37de71da8955", @@ -103,6 +99,31 @@ "azdata_cell_guid": "8716915b-1439-431b-ab0a-0221ef94cb7f" } }, + { + "cell_type": "markdown", + "source": [ + "### **Check dependencies**" + ], + "metadata": { + "azdata_cell_guid": "db8b1e21-eb2c-4c35-b973-bc4ef38bb1d0" + } + }, + { + "cell_type": "code", + "source": [ + "run_command('kubectl version --client=true')\n", + "run_command('azdata --version')\n", + "run_command('az --version')" + ], + "metadata": { + "azdata_cell_guid": "9361deaf-28b1-4d02-912d-2011cae97e8a", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": 0 + }, { "cell_type": "markdown", "source": [ diff --git a/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-existing-aks.ipynb b/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-existing-aks.ipynb index 650d1b2f16..b315356551 100644 --- a/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-existing-aks.ipynb +++ b/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-existing-aks.ipynb @@ -56,7 +56,7 @@ { "cell_type": "markdown", "source": [ - "### **Check dependencies**" + "### **Setup**" ], "metadata": { "azdata_cell_guid": "e3dd8e75-e15f-44b4-81fc-1f54d6f0b1e2" @@ -77,10 +77,7 @@ " !{command}\n", " if _exit_code != 0:\n", " sys.exit(f'Command execution failed with exit code: {str(_exit_code)}.\\n\\t{command}\\n')\n", - " print(f'Successfully executed: {command}')\n", - "\n", - "run_command('kubectl version --client=true')\n", - "run_command('azdata --version')" + " print(f'Successfully executed: {command}')" ], "metadata": { "azdata_cell_guid": "d973d5b4-7f0a-4a9d-b204-a16480f3940d", @@ -101,6 +98,30 @@ "azdata_cell_guid": "4b266b2d-bd1b-4565-92c9-3fc146cdce6d" } }, + { + "cell_type": "markdown", + "source": [ + "### **Check dependencies**" + ], + "metadata": { + "azdata_cell_guid": "2544648b-59c9-4ce5-a3b6-87086e214d4c" + } + }, + { + "cell_type": "code", + "source": [ + "run_command('kubectl version --client=true')\n", + "run_command('azdata --version')" + ], + "metadata": { + "azdata_cell_guid": "691671d7-3f05-406c-a183-4cff7d17f83d", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": 0 + }, { "cell_type": "markdown", "source": [ diff --git a/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-existing-kubeadm.ipynb b/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-existing-kubeadm.ipynb index d88c982998..d44b006402 100644 --- a/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-existing-kubeadm.ipynb +++ b/extensions/resource-deployment/notebooks/bdc/2019/deploy-bdc-existing-kubeadm.ipynb @@ -56,7 +56,7 @@ { "cell_type": "markdown", "source": [ - "### **Check dependencies**" + "### **Setup**" ], "metadata": { "azdata_cell_guid": "a31f9894-903f-4e19-a5a8-6fd888ff013b" @@ -101,6 +101,30 @@ "azdata_cell_guid": "e70640d0-6059-4cab-939e-e985a978c0da" } }, + { + "cell_type": "markdown", + "source": [ + "### **Check dependencies**" + ], + "metadata": { + "azdata_cell_guid": "869d0397-a280-4dc4-be76-d652189b5131" + } + }, + { + "cell_type": "code", + "source": [ + "run_command('kubectl version --client=true')\n", + "run_command('azdata --version')" + ], + "metadata": { + "azdata_cell_guid": "c38afb67-1132-495e-9af1-35bf067acbeb", + "tags": [ + "hide_input" + ] + }, + "outputs": [], + "execution_count": 0 + }, { "cell_type": "markdown", "source": [ diff --git a/extensions/resource-deployment/src/interfaces.ts b/extensions/resource-deployment/src/interfaces.ts index 4b6ffb127e..20804b6db2 100644 --- a/extensions/resource-deployment/src/interfaces.ts +++ b/extensions/resource-deployment/src/interfaces.ts @@ -226,7 +226,7 @@ export const enum ToolStatus { } export interface ITool { - isInstalling: any; + readonly isInstalling: boolean; readonly name: string; readonly displayName: string; readonly description: string; @@ -237,6 +237,7 @@ export interface ITool { readonly autoInstallSupported: boolean; readonly autoInstallRequired: boolean; readonly isNotInstalled: boolean; + readonly installationPath: string; readonly needsInstallation: boolean; readonly outputChannelName: string; readonly fullVersion: string | undefined; diff --git a/extensions/resource-deployment/src/services/platformService.ts b/extensions/resource-deployment/src/services/platformService.ts index 5a31f38790..db0efb577c 100644 --- a/extensions/resource-deployment/src/services/platformService.ts +++ b/extensions/resource-deployment/src/services/platformService.ts @@ -232,9 +232,9 @@ export class PlatformService implements IPlatformService { // Add listeners to print stdout and stderr and exit code child.on('exit', (code: number | null, signal: string | null) => { if (code !== null) { - outputChannel.appendLine(localize('platformService.RunStreamedCommand.ExitedWithCode', " >>> ${0} ... exited with code: ${1}", command, code)); + outputChannel.appendLine(localize('platformService.RunStreamedCommand.ExitedWithCode', " >>> {0} ... exited with code: {1}", command, code)); } else { - outputChannel.appendLine(localize('platformService.RunStreamedCommand.ExitedWithSignal', " >>> ${0} ... exited with signal: ${1}", command, signal)); + outputChannel.appendLine(localize('platformService.RunStreamedCommand.ExitedWithSignal', " >>> {0} ... exited with signal: {1}", command, signal)); } }); child.stdout.on('data', (data: string | Buffer) => { diff --git a/extensions/resource-deployment/src/services/tools/azCliTool.ts b/extensions/resource-deployment/src/services/tools/azCliTool.ts index 6d3c6f4469..f7e0d950cb 100644 --- a/extensions/resource-deployment/src/services/tools/azCliTool.ts +++ b/extensions/resource-deployment/src/services/tools/azCliTool.ts @@ -42,12 +42,12 @@ export class AzCliTool extends ToolBase { return true; } - protected async getInstallationPath(): Promise { + protected async getSearchPaths(): Promise { switch (this.osType) { case OsType.win32: - return win32InstallationRoot; + return [win32InstallationRoot]; default: - return defaultInstallationRoot; + return [defaultInstallationRoot]; } } @@ -65,11 +65,18 @@ export class AzCliTool extends ToolBase { return undefined; } } + protected get versionCommand(): Command { return { command: 'az --version' }; } + + protected get discoveryCommand(): Command { + return { + command: this.discoveryCommandString('az') + }; + } } const win32InstallationCommands = [ diff --git a/extensions/resource-deployment/src/services/tools/azdataTool.ts b/extensions/resource-deployment/src/services/tools/azdataTool.ts index 556b4430b7..f2d335268d 100644 --- a/extensions/resource-deployment/src/services/tools/azdataTool.ts +++ b/extensions/resource-deployment/src/services/tools/azdataTool.ts @@ -13,7 +13,6 @@ import { ToolBase } from './toolBase'; import { DeploymentConfigurationKey, AzdataPipInstallUriKey, azdataPipInstallArgsKey } from '../../constants'; const localize = nls.loadMessageBundle(); -const installationRoot = '~/.local/bin'; export class AzdataTool extends ToolBase { constructor(platformService: IPlatformService) { @@ -46,6 +45,12 @@ export class AzdataTool extends ToolBase { }; } + protected get discoveryCommand(): Command { + return { + command: this.discoveryCommandString('azdata') + }; + } + protected getVersionFromOutput(output: string): SemVer | undefined { let version: SemVer | undefined = undefined; if (output && output.split(EOL).length > 0) { @@ -58,13 +63,15 @@ export class AzdataTool extends ToolBase { return true; } - protected async getInstallationPath(): Promise { + protected async getSearchPaths(): Promise { switch (this.osType) { - case OsType.linux: - return installationRoot; default: const azdataCliInstallLocation = await this.getPip3InstallLocation('azdata-cli'); - return azdataCliInstallLocation && path.join(azdataCliInstallLocation, '..', 'Scripts'); + if (azdataCliInstallLocation) { + return [path.join(azdataCliInstallLocation, '..', 'Scripts'), path.join(azdataCliInstallLocation, '..', '..', '..', 'bin')]; + } else { + return []; + } } } @@ -78,11 +85,7 @@ export class AzdataTool extends ToolBase { } protected get uninstallCommand(): string | undefined { - if (this.osType !== OsType.linux) { - return this.defaultUninstallCommand; - } else { - return super.uninstallCommand; - } + return this.defaultUninstallCommand; } private get defaultInstallationCommands(): Command[] { diff --git a/extensions/resource-deployment/src/services/tools/dockerTool.ts b/extensions/resource-deployment/src/services/tools/dockerTool.ts index 22b421afbb..9ef811a3db 100644 --- a/extensions/resource-deployment/src/services/tools/dockerTool.ts +++ b/extensions/resource-deployment/src/services/tools/dockerTool.ts @@ -11,6 +11,7 @@ import { ToolBase } from './toolBase'; const localize = nls.loadMessageBundle(); export class DockerTool extends ToolBase { + protected discoveryCommand: Command = { command: '' }; constructor(platformService: IPlatformService) { super(platformService); } diff --git a/extensions/resource-deployment/src/services/tools/kubeCtlTool.ts b/extensions/resource-deployment/src/services/tools/kubeCtlTool.ts index 794a4155dc..01df5c4757 100644 --- a/extensions/resource-deployment/src/services/tools/kubeCtlTool.ts +++ b/extensions/resource-deployment/src/services/tools/kubeCtlTool.ts @@ -11,6 +11,8 @@ import { ToolBase } from './toolBase'; const localize = nls.loadMessageBundle(); +const defaultInstallationRoot = '/usr/local/bin'; + export class KubeCtlTool extends ToolBase { constructor(platformService: IPlatformService) { super(platformService); @@ -49,10 +51,24 @@ export class KubeCtlTool extends ToolBase { return { command: 'kubectl version -o json --client' }; } + protected get discoveryCommand(): Command { + return { + command: this.discoveryCommandString('kubectl') + }; + } + get autoInstallSupported(): boolean { return true; } + protected async getSearchPaths(): Promise { + switch (this.osType) { + case OsType.win32: + return [this.storagePath]; + default: + return [defaultInstallationRoot]; + } + } protected readonly allInstallationCommands: Map = new Map([ [OsType.linux, linuxInstallationCommands], [OsType.win32, win32InstallationCommands], diff --git a/extensions/resource-deployment/src/services/tools/toolBase.ts b/extensions/resource-deployment/src/services/tools/toolBase.ts index 85bca78ac6..99024fae08 100644 --- a/extensions/resource-deployment/src/services/tools/toolBase.ts +++ b/extensions/resource-deployment/src/services/tools/toolBase.ts @@ -14,7 +14,7 @@ import { IPlatformService } from '../platformService'; const localize = nls.loadMessageBundle(); const toolStatusNotInstalled: string = localize('deploymentDialog.ToolStatus.NotInstalled', "Not Installed"); const toolStatusInstalled: string = localize('deploymentDialog.ToolStatus.Installed', "Installed"); -const toolStatusInstalling: string = localize('deploymentDialog.ToolStatus.NotInstalling', "Installing ..."); +const toolStatusInstalling: string = localize('deploymentDialog.ToolStatus.Installing', "Installing"); const toolStatusError: string = localize('deploymentDialog.ToolStatus.Error', "Error"); const toolStatusFailed: string = localize('deploymentDialog.ToolStatus.Failed', "Failed"); @@ -45,12 +45,10 @@ export abstract class ToolBase implements ITool { protected abstract readonly versionCommand: Command; - protected async getInstallationPath(): Promise { - return undefined; - } + protected abstract readonly discoveryCommand: Command; - protected get installationSearchPaths(): (string | undefined)[] { - return [this.storagePath]; + protected async getSearchPaths(): Promise { + return []; } protected get downloadPath(): string { @@ -125,6 +123,9 @@ export abstract class ToolBase implements ITool { return this._statusDescription; } + public get installationPath(): string { + return this._installationPath; + } protected get installationCommands(): Command[] | undefined { return this.allInstallationCommands.get(this.osType); } @@ -164,6 +165,7 @@ export abstract class ToolBase implements ITool { this.status = ToolStatus.Error; throw error; } + // Since we just completed installation, the status should be ToolStatus.Installed // but if it is ToolStatus.NotInstalled then it means that installation failed with 0 exit code. if (this.status === ToolStatus.NotInstalled) { @@ -196,27 +198,28 @@ export abstract class ToolBase implements ITool { } protected async addInstallationSearchPathsToSystemPath(): Promise { - const installationPath = await this.getInstallationPath(); - const searchPaths = [installationPath, ...this.installationSearchPaths].filter(path => !!path); + const searchPaths = [...await this.getSearchPaths(), this.storagePath].filter(path => !!path); this.logToOutputChannel(localize('toolBase.addInstallationSearchPathsToSystemPath.SearchPaths', "Search Paths for tool '{0}': {1}", this.displayName, JSON.stringify(searchPaths, undefined, '\t'))); //this.displayName is localized and searchPaths are OS filesystem paths. - searchPaths.forEach(installationSearchPath => { + searchPaths.forEach(searchPath => { if (process.env.PATH) { - if (!`${delimiter}${process.env.PATH}${delimiter}`.includes(`${delimiter}${installationSearchPath}${delimiter}`)) { - process.env.PATH += `${delimiter}${installationSearchPath}`; - console.log(`Appending to Path -> ${delimiter}${installationSearchPath}`); + if (!`${delimiter}${process.env.PATH}${delimiter}`.includes(`${delimiter}${searchPath}${delimiter}`)) { + process.env.PATH += `${delimiter}${searchPath}`; + console.log(`Appending to Path -> '${delimiter}${searchPath}'`); } } else { - process.env.PATH = installationSearchPath; - console.log(`Appending to Path -> '${delimiter}${installationSearchPath}':${delimiter}${installationSearchPath}`); + process.env.PATH = searchPath; + console.log(`Setting PATH to -> '${searchPath}'`); } }); } + public async loadInformation(): Promise { if (this.status === ToolStatus.NotInstalled) { await this.addInstallationSearchPathsToSystemPath(); this.status = await this.updateVersionAndGetStatus(); } } + private async updateVersionAndGetStatus(): Promise { const commandOutput = await this._platformService.runCommand( this.versionCommand.command, @@ -229,6 +232,8 @@ export abstract class ToolBase implements ITool { ); this.version = this.getVersionFromOutput(commandOutput); if (this.version) { + // discover and set the installationPath + await this.setInstallationPath(); return ToolStatus.Installed; } else { @@ -237,10 +242,39 @@ export abstract class ToolBase implements ITool { } } + protected discoveryCommandString(toolBinary: string) { + switch (this.osType) { + case OsType.win32: + return `where.exe ${toolBinary}`; + case OsType.darwin: + return `command -v ${toolBinary}`; + default: + return `which ${toolBinary}`; + } + } + + protected async setInstallationPath() { + const commandOutput = await this._platformService.runCommand( + this.discoveryCommand.command, + { + workingDirectory: this.discoveryCommand.workingDirectory, + additionalEnvironmentVariables: this.discoveryCommand.additionalEnvironmentVariables, + sudo: false, + ignoreError: false + }, + ); + if (!commandOutput) { + throw new Error(`Install location of tool:'${this.displayName}' could not be discovered`); + } else { + this._installationPath = commandOutput.split(EOL)[0]; + } + } + private _storagePathEnsured: boolean = false; private _status: ToolStatus = ToolStatus.NotInstalled; private _osType: OsType; private _version?: SemVer; private _statusDescription?: string; + private _installationPath!: string; } diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/constants.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/constants.ts index b759766b04..b087c7aefa 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/constants.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/constants.ts @@ -69,3 +69,4 @@ export const DockerRegistry_VariableName = 'AZDATA_NB_VAR_BDC_REGISTRY'; export const DockerImageTag_VariableName = 'AZDATA_NB_VAR_BDC_DOCKER_IMAGE_TAG'; export const DockerUsername_VariableName = 'AZDATA_NB_VAR_BDC_DOCKER_USERNAME'; export const DockerPassword_VariableName = 'AZDATA_NB_VAR_BDC_DOCKER_PASSWORD'; +export const ToolsInstallPath = 'AZDATA_NB_VAR_TOOLS_INSTALLATION_PATH'; diff --git a/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizardModel.ts b/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizardModel.ts index e3d054cd3a..2d9aac2c1a 100644 --- a/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizardModel.ts +++ b/extensions/resource-deployment/src/ui/deployClusterWizard/deployClusterWizardModel.ts @@ -8,6 +8,7 @@ import * as VariableNames from './constants'; import { BigDataClusterDeploymentProfile, DataResource, SqlServerMasterResource, HdfsResource } from '../../services/bigDataClusterDeploymentProfile'; import { BdcDeploymentType } from '../../interfaces'; import { EOL } from 'os'; +import { delimiter } from 'path'; export class DeployClusterWizardModel extends Model { constructor(public deploymentTarget: BdcDeploymentType) { @@ -162,6 +163,7 @@ export class DeployClusterWizardModel extends Model { statements.push(`os.environ["DOCKER_USERNAME"] = '${this.getStringValue(VariableNames.DockerUsername_VariableName)}'`); statements.push(`os.environ["DOCKER_PASSWORD"] = os.environ["${VariableNames.DockerPassword_VariableName}"]`); } + statements.push(`os.environ["PATH"] = os.environ["PATH"] + "${delimiter}" + "${process.env[VariableNames.ToolsInstallPath]}"`); statements.push(`print('Variables have been set successfully.')`); return statements.map(line => line + EOL); } diff --git a/extensions/resource-deployment/src/ui/dialogBase.ts b/extensions/resource-deployment/src/ui/dialogBase.ts index 92beba14c9..503e1f9983 100644 --- a/extensions/resource-deployment/src/ui/dialogBase.ts +++ b/extensions/resource-deployment/src/ui/dialogBase.ts @@ -32,7 +32,8 @@ export abstract class DialogBase { this.dispose(); } - protected onComplete(): void { } + protected onComplete(): void { + } protected dispose(): void { this._toDispose.forEach(disposable => disposable.dispose()); diff --git a/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts b/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts index e9c83fd4b0..7c64f78cc5 100644 --- a/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts +++ b/extensions/resource-deployment/src/ui/resourceTypePickerDialog.ts @@ -8,7 +8,7 @@ import * as nls from 'vscode-nls'; import { AgreementInfo, DeploymentProvider, ITool, ResourceType } from '../interfaces'; import { IResourceTypeService } from '../services/resourceTypeService'; import { IToolsService } from '../services/toolsService'; -import { getErrorMessage } from '../utils'; +import { getErrorMessage, setEnvironmentVariablesForInstallPaths } from '../utils'; import { DialogBase } from './dialogBase'; import { createFlexContainer } from './modelViewUtils'; @@ -288,6 +288,7 @@ export class ResourceTypePickerDialog extends DialogBase { } protected onComplete(): void { + setEnvironmentVariablesForInstallPaths(this._tools); this.resourceTypeService.startDeployment(this.getCurrentProvider()); } diff --git a/extensions/resource-deployment/src/utils.ts b/extensions/resource-deployment/src/utils.ts index 4b83b7e9f7..8c24a7f747 100644 --- a/extensions/resource-deployment/src/utils.ts +++ b/extensions/resource-deployment/src/utils.ts @@ -2,6 +2,9 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { ITool, NoteBookEnvironmentVariablePrefix } from './interfaces'; +import * as path from 'path'; +import { ToolsInstallPath } from './ui/deployClusterWizard/constants'; export function getErrorMessage(error: any): string { return (error instanceof Error) @@ -12,3 +15,18 @@ export function getErrorMessage(error: any): string { export function getDateTimeString(): string { return new Date().toISOString().slice(0, 19).replace(/[^0-9]/g, ''); // Take the date time information and only leaving the numbers } + +export function setEnvironmentVariablesForInstallPaths(tools: ITool[]): void { + let installationPaths: Set = new Set(); + tools.forEach(t => { + // construct an env variable name with NoteBookEnvironmentVariablePrefix prefix + // and tool.name as suffix, making sure of using all uppercase characters and only _ as separator + const envVarName: string = `${NoteBookEnvironmentVariablePrefix}${t.name.toUpperCase().replace(/ |-/, '_')}`; + process.env[envVarName] = t.installationPath; + installationPaths.add(path.resolve(path.dirname(t.installationPath))); + console.log(`setting env var:'${envVarName}' to: '${t.installationPath}'`); + }); + const envVarToolsInstallationPath: string = [...installationPaths.values()].join(path.delimiter); + process.env[ToolsInstallPath] = envVarToolsInstallationPath; + console.log(`setting env var:'${ToolsInstallPath}' to: '${envVarToolsInstallationPath}'`); +}