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
This commit is contained in:
Arvind Ranasaria
2019-10-25 12:06:55 -07:00
committed by Alan Ren
parent 3b1c9e910d
commit af9984f73b
15 changed files with 195 additions and 44 deletions

View File

@@ -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) => {

View File

@@ -42,12 +42,12 @@ export class AzCliTool extends ToolBase {
return true;
}
protected async getInstallationPath(): Promise<string | undefined> {
protected async getSearchPaths(): Promise<string[]> {
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 = [

View File

@@ -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<string | undefined> {
protected async getSearchPaths(): Promise<string[]> {
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[] {

View File

@@ -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);
}

View File

@@ -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<string[]> {
switch (this.osType) {
case OsType.win32:
return [this.storagePath];
default:
return [defaultInstallationRoot];
}
}
protected readonly allInstallationCommands: Map<OsType, Command[]> = new Map<OsType, Command[]>([
[OsType.linux, linuxInstallationCommands],
[OsType.win32, win32InstallationCommands],

View File

@@ -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<string | undefined> {
return undefined;
}
protected abstract readonly discoveryCommand: Command;
protected get installationSearchPaths(): (string | undefined)[] {
return [this.storagePath];
protected async getSearchPaths(): Promise<string[]> {
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<void> {
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<void> {
if (this.status === ToolStatus.NotInstalled) {
await this.addInstallationSearchPathsToSystemPath();
this.status = await this.updateVersionAndGetStatus();
}
}
private async updateVersionAndGetStatus(): Promise<ToolStatus> {
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;
}