mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
add handlers for promise rejections (#8735)
This change adds to handlers to unexpected promise rejection scenarios. This PR fixes #8640 * add handlers for promise rejections * Displaying all tools load errors * Update toolBase.ts - setting errorMessage to be displayed in the additional information field * disable the select button when tools not discovered * PR fixes
This commit is contained in:
@@ -254,7 +254,7 @@ export interface ITool {
|
||||
readonly autoInstallNeeded: boolean;
|
||||
readonly isNotInstalled: boolean;
|
||||
readonly isInstalled: boolean;
|
||||
readonly installationPath?: string;
|
||||
readonly installationPathOrAdditionalInformation?: string;
|
||||
readonly outputChannelName: string;
|
||||
readonly fullVersion?: string;
|
||||
readonly onDidUpdateData: vscode.Event<ITool>;
|
||||
|
||||
@@ -43,6 +43,7 @@ export class DockerTool extends ToolBase {
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
protected get versionCommand(): Command {
|
||||
return { command: 'docker version --format "{{json .}}"' };
|
||||
}
|
||||
|
||||
@@ -139,8 +139,8 @@ export abstract class ToolBase implements ITool {
|
||||
return this._statusDescription;
|
||||
}
|
||||
|
||||
public get installationPath(): string | undefined {
|
||||
return this._installationPath;
|
||||
public get installationPathOrAdditionalInformation(): string | undefined {
|
||||
return this._installationPathOrAdditionalInformation;
|
||||
}
|
||||
|
||||
protected get installationCommands(): Command[] | undefined {
|
||||
@@ -186,6 +186,7 @@ export abstract class ToolBase implements ITool {
|
||||
const errorMessage = getErrorMessage(error);
|
||||
this._statusDescription = localize('toolBase.InstallError', "Error installing tool '{0}' [ {1} ].{2}Error: {3}{2}See output channel '{4}' for more details", this.displayName, this.homePage, EOL, errorMessage, this.outputChannelName);
|
||||
this.status = ToolStatus.Error;
|
||||
this._installationPathOrAdditionalInformation = errorMessage;
|
||||
throw error;
|
||||
}
|
||||
|
||||
@@ -234,14 +235,33 @@ export abstract class ToolBase implements ITool {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the tool with discovered state and version information.
|
||||
* Upon error the this.status field is set to ToolStatus.Error and this.statusDescription && this.installationPathOrAdditionalInformation is set to the corresponding error message
|
||||
* and original error encountered is re-thrown so that it gets bubbled up to the caller.
|
||||
*/
|
||||
public async loadInformation(): Promise<void> {
|
||||
try {
|
||||
await this._pendingVersionAndStatusUpdate;
|
||||
} catch (error) {
|
||||
this.status = ToolStatus.Error;
|
||||
this._statusDescription = getErrorMessage(error);
|
||||
this._installationPathOrAdditionalInformation = this._statusDescription;
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
private startVersionAndStatusUpdate() {
|
||||
/**
|
||||
* Invokes the async method to update version and status for the tool.
|
||||
*/
|
||||
private startVersionAndStatusUpdate(): void {
|
||||
this._statusDescription = '';
|
||||
this._pendingVersionAndStatusUpdate = this.updateVersionAndStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* updates the version and status for the tool.
|
||||
*/
|
||||
private async updateVersionAndStatus(): Promise<void> {
|
||||
this._statusDescription = '';
|
||||
await this.addInstallationSearchPathsToSystemPath();
|
||||
@@ -292,7 +312,7 @@ export abstract class ToolBase implements ITool {
|
||||
if (!commandOutput) {
|
||||
throw new Error(`Install location of tool:'${this.displayName}' could not be discovered`);
|
||||
} else {
|
||||
this._installationPath = path.resolve(commandOutput.split(EOL)[0]);
|
||||
this._installationPathOrAdditionalInformation = path.resolve(commandOutput.split(EOL)[0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,5 +324,5 @@ export abstract class ToolBase implements ITool {
|
||||
private _status: ToolStatus = ToolStatus.NotInstalled;
|
||||
private _version?: SemVer;
|
||||
private _statusDescription?: string;
|
||||
private _installationPath?: string;
|
||||
private _installationPathOrAdditionalInformation?: string;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ export class ResourceTypePickerDialog extends DialogBase {
|
||||
this._selectedResourceType = resourceType;
|
||||
this._installToolButton = azdata.window.createButton(localize('deploymentDialog.InstallToolsButton', "Install tools"));
|
||||
this._toDispose.push(this._installToolButton.onClick(() => {
|
||||
this.installTools();
|
||||
this.installTools().catch(error => console.log(error));
|
||||
}));
|
||||
this._dialogObject.customButtons = [this._installToolButton];
|
||||
this._installToolButton.hidden = true;
|
||||
@@ -106,10 +106,10 @@ export class ResourceTypePickerDialog extends DialogBase {
|
||||
};
|
||||
const minVersionColumn: azdata.TableColumn = {
|
||||
value: localize('deploymentDialog.toolMinimumVersionColumnHeader', "Required Version"),
|
||||
width: 90
|
||||
width: 95
|
||||
};
|
||||
const installedPathColumn: azdata.TableColumn = {
|
||||
value: localize('deploymentDialog.toolDiscoveredPathColumnHeader', "Discovered Path"),
|
||||
value: localize('deploymentDialog.toolDiscoveredPathColumnHeader', "Discovered Path or Additional Information"),
|
||||
width: 570
|
||||
};
|
||||
this._toolsTable = view.modelBuilder.table().withProperties<azdata.TableComponentProperties>({
|
||||
@@ -197,34 +197,40 @@ export class ResourceTypePickerDialog extends DialogBase {
|
||||
private updateToolsDisplayTable(): void {
|
||||
this.toolRefreshTimestamp = new Date().getTime();
|
||||
const currentRefreshTimestamp = this.toolRefreshTimestamp;
|
||||
const toolRequirements = this.getCurrentProvider().requiredTools;
|
||||
const headerRowHeight = 28;
|
||||
this._toolsTable.height = 25 * Math.max(toolRequirements.length, 1) + headerRowHeight;
|
||||
this._toolsTable.height = 25 * Math.max(this.toolRequirements.length, 1) + headerRowHeight;
|
||||
this._dialogObject.message = {
|
||||
text: ''
|
||||
};
|
||||
this._installToolButton.hidden = true;
|
||||
if (toolRequirements.length === 0) {
|
||||
if (this.toolRequirements.length === 0) {
|
||||
this._dialogObject.okButton.enabled = true;
|
||||
this._toolsTable.data = [[localize('deploymentDialog.NoRequiredTool', "No tools required"), '']];
|
||||
this._tools = [];
|
||||
} else {
|
||||
this._tools = toolRequirements.map(toolReq => {
|
||||
return this.toolsService.getToolByName(toolReq.name)!;
|
||||
});
|
||||
this._tools = this.toolRequirements.map(toolReq => this.toolsService.getToolByName(toolReq.name)!);
|
||||
this._toolsLoadingComponent.loading = true;
|
||||
this._dialogObject.okButton.enabled = false;
|
||||
let toolsLoadingErrors: string[] = [];
|
||||
Promise.all(
|
||||
this._tools.map(tool => tool.loadInformation())
|
||||
).then(async () => {
|
||||
this._tools.map(
|
||||
tool => tool.loadInformation().catch(() => toolsLoadingErrors.push(`${tool.displayName}:${tool.statusDescription!}`))
|
||||
)
|
||||
)
|
||||
.then(() => this.executeToolsTableWorkflow(currentRefreshTimestamp, toolsLoadingErrors))
|
||||
.catch(error => console.log(error));
|
||||
}
|
||||
}
|
||||
|
||||
private executeToolsTableWorkflow(currentRefreshTimestamp: number, toolsLoadingErrors: string[]): void {
|
||||
// If the local timestamp does not match the class level timestamp, it means user has changed options, ignore the results
|
||||
if (this.toolRefreshTimestamp !== currentRefreshTimestamp) {
|
||||
return;
|
||||
}
|
||||
let minVersionCheckFailed = false;
|
||||
const toolsToAutoInstall: ITool[] = [];
|
||||
let messages: string[] = [];
|
||||
this._toolsTable.data = toolRequirements.map(toolRequirement => {
|
||||
let messages: string[] = toolsLoadingErrors!;
|
||||
this._toolsTable.data = this.toolRequirements.map(toolRequirement => {
|
||||
const tool = this.toolsService.getToolByName(toolRequirement.name)!;
|
||||
// subscribe to onUpdateData event of the tool.
|
||||
this._toDispose.push(tool.onDidUpdateData((t: ITool) => {
|
||||
@@ -233,17 +239,17 @@ export class ResourceTypePickerDialog extends DialogBase {
|
||||
if (tool.isNotInstalled) {
|
||||
if (tool.autoInstallSupported) {
|
||||
toolsToAutoInstall.push(tool);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
messages.push(localize('deploymentDialog.ToolInformation', "'{0}' was not discovered and automated installation is not currently supported. Install '{0}' manually or ensure it is started and discoverable. Once done please restart Azure Data Studio. See [{1}] .", tool.displayName, tool.homePage));
|
||||
}
|
||||
} else if (tool.isInstalled && toolRequirement.version && !tool.isSameOrNewerThan(toolRequirement.version)) {
|
||||
}
|
||||
else if (tool.isInstalled && toolRequirement.version && !tool.isSameOrNewerThan(toolRequirement.version)) {
|
||||
minVersionCheckFailed = true;
|
||||
messages.push(localize('deploymentDialog.ToolDoesNotMeetVersionRequirement', "'{0}' [ {1} ] does not meet the minimum version requirement, please uninstall it and restart Azure Data Studio.", tool.displayName, tool.homePage));
|
||||
}
|
||||
|
||||
return [tool.displayName, tool.description, tool.displayStatus, tool.fullVersion || '', toolRequirement.version || '', tool.installationPath || ''];
|
||||
return [tool.displayName, tool.description, tool.displayStatus, tool.fullVersion || '', toolRequirement.version || '', tool.installationPathOrAdditionalInformation || ''];
|
||||
});
|
||||
|
||||
this._installToolButton.hidden = minVersionCheckFailed || (toolsToAutoInstall.length === 0);
|
||||
this._dialogObject.okButton.enabled = messages.length === 0 && !minVersionCheckFailed && (toolsToAutoInstall.length === 0);
|
||||
if (messages.length !== 0) {
|
||||
@@ -255,7 +261,8 @@ export class ResourceTypePickerDialog extends DialogBase {
|
||||
level: azdata.window.MessageLevel.Error,
|
||||
text: messages.join(EOL)
|
||||
};
|
||||
} else if ((toolsToAutoInstall.length !== 0) && !this._installationInProgress) {
|
||||
}
|
||||
else if ((toolsToAutoInstall.length !== 0) && !this._installationInProgress) {
|
||||
const installationNeededHeader = toolsToAutoInstall.length === 1
|
||||
? localize('deploymentDialog.InstallToolsHintOne', "Tool: {0} is not installed, you can click the \"{1}\" button to install it.", toolsToAutoInstall[0].displayName, this._installToolButton.label)
|
||||
: localize('deploymentDialog.InstallToolsHintMany', "Tools: {0} are not installed, you can click the \"{1}\" button to install them.", toolsToAutoInstall.map(t => t.displayName).join(', '), this._installToolButton.label);
|
||||
@@ -277,8 +284,10 @@ export class ResourceTypePickerDialog extends DialogBase {
|
||||
};
|
||||
}
|
||||
this._toolsLoadingComponent.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
private get toolRequirements() {
|
||||
return this.getCurrentProvider().requiredTools;
|
||||
}
|
||||
|
||||
private createAgreementCheckbox(agreementInfo: AgreementInfo): azdata.FlexContainer {
|
||||
@@ -326,7 +335,7 @@ export class ResourceTypePickerDialog extends DialogBase {
|
||||
protected updateToolsDisplayTableData(tool: ITool) {
|
||||
this._toolsTable.data = this._toolsTable.data.map(rowData => {
|
||||
if (rowData[0] === tool.displayName) {
|
||||
return [tool.displayName, tool.description, tool.displayStatus, tool.fullVersion || '', rowData[4]/* required version*/, tool.installationPath || ''];
|
||||
return [tool.displayName, tool.description, tool.displayStatus, tool.fullVersion || '', rowData[4]/* required version*/, tool.installationPathOrAdditionalInformation || ''];
|
||||
} else {
|
||||
return rowData;
|
||||
}
|
||||
@@ -347,7 +356,7 @@ export class ResourceTypePickerDialog extends DialogBase {
|
||||
this._installationInProgress = true;
|
||||
let tool: ITool;
|
||||
try {
|
||||
const toolRequirements = this.getCurrentProvider().requiredTools;
|
||||
const toolRequirements = this.toolRequirements;
|
||||
let toolsNotInstalled: ITool[] = [];
|
||||
for (let i: number = 0; i < toolRequirements.length; i++) {
|
||||
const toolReq = toolRequirements[i];
|
||||
|
||||
@@ -25,13 +25,13 @@ export function setEnvironmentVariablesForInstallPaths(tools: ITool[]): void {
|
||||
// Use Set class to make sure the collection only contains unique values.
|
||||
let installationPaths: Set<string> = new Set<string>();
|
||||
tools.forEach(t => {
|
||||
if (t.installationPath) {
|
||||
if (t.installationPathOrAdditionalInformation) {
|
||||
|
||||
// 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 = getRuntimeBinaryPathEnvironmentVariableName(t.name);
|
||||
process.env[envVarName] = t.installationPath;
|
||||
installationPaths.add(path.dirname(t.installationPath));
|
||||
process.env[envVarName] = t.installationPathOrAdditionalInformation;
|
||||
installationPaths.add(path.dirname(t.installationPathOrAdditionalInformation));
|
||||
}
|
||||
});
|
||||
if (installationPaths.size > 0) {
|
||||
|
||||
Reference in New Issue
Block a user