mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-15 02:48:30 -05:00
Merge from vscode cbeff45f80213db0ddda2183170281ed97ed3b12 (#8670)
* Merge from vscode cbeff45f80213db0ddda2183170281ed97ed3b12 * fix null strict checks
This commit is contained in:
169
src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts
Normal file
169
src/vs/workbench/contrib/debug/browser/debugTaskRunner.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import severity from 'vs/base/common/severity';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import Constants from 'vs/workbench/contrib/markers/browser/constants';
|
||||
import { ITaskService, ITaskSummary } from 'vs/workbench/contrib/tasks/common/taskService';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { TaskEvent, TaskEventKind, TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { withUndefinedAsNull } from 'vs/base/common/types';
|
||||
import { IMarkerService } from 'vs/platform/markers/common/markers';
|
||||
import { IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
||||
|
||||
function once(match: (e: TaskEvent) => boolean, event: Event<TaskEvent>): Event<TaskEvent> {
|
||||
return (listener, thisArgs = null, disposables?) => {
|
||||
const result = event(e => {
|
||||
if (match(e)) {
|
||||
result.dispose();
|
||||
return listener.call(thisArgs, e);
|
||||
}
|
||||
}, null, disposables);
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
export const enum TaskRunResult {
|
||||
Failure,
|
||||
Success
|
||||
}
|
||||
|
||||
export class DebugTaskRunner {
|
||||
|
||||
constructor(
|
||||
@ITaskService private readonly taskService: ITaskService,
|
||||
@IMarkerService private readonly markerService: IMarkerService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IPanelService private readonly panelService: IPanelService,
|
||||
@IDialogService private readonly dialogService: IDialogService,
|
||||
) { }
|
||||
|
||||
async runTaskAndCheckErrors(root: IWorkspaceFolder | IWorkspace | undefined, taskId: string | TaskIdentifier | undefined, onError: (msg: string, actions: IAction[]) => Promise<void>): Promise<TaskRunResult> {
|
||||
try {
|
||||
const taskSummary = await this.runTask(root, taskId);
|
||||
|
||||
const errorCount = taskId ? this.markerService.getStatistics().errors : 0;
|
||||
const successExitCode = taskSummary && taskSummary.exitCode === 0;
|
||||
const failureExitCode = taskSummary && taskSummary.exitCode !== 0;
|
||||
const onTaskErrors = this.configurationService.getValue<IDebugConfiguration>('debug').onTaskErrors;
|
||||
if (successExitCode || onTaskErrors === 'debugAnyway' || (errorCount === 0 && !failureExitCode)) {
|
||||
return TaskRunResult.Success;
|
||||
}
|
||||
if (onTaskErrors === 'showErrors') {
|
||||
this.panelService.openPanel(Constants.MARKERS_PANEL_ID);
|
||||
return Promise.resolve(TaskRunResult.Failure);
|
||||
}
|
||||
|
||||
const taskLabel = typeof taskId === 'string' ? taskId : taskId ? taskId.name : '';
|
||||
const message = errorCount > 1
|
||||
? nls.localize('preLaunchTaskErrors', "Errors exist after running preLaunchTask '{0}'.", taskLabel)
|
||||
: errorCount === 1
|
||||
? nls.localize('preLaunchTaskError', "Error exists after running preLaunchTask '{0}'.", taskLabel)
|
||||
: nls.localize('preLaunchTaskExitCode', "The preLaunchTask '{0}' terminated with exit code {1}.", taskLabel, taskSummary ? taskSummary.exitCode : 0);
|
||||
|
||||
const result = await this.dialogService.show(severity.Warning, message, [nls.localize('debugAnyway', "Debug Anyway"), nls.localize('showErrors', "Show Errors"), nls.localize('cancel', "Cancel")], {
|
||||
checkbox: {
|
||||
label: nls.localize('remember', "Remember my choice in user settings"),
|
||||
},
|
||||
cancelId: 2
|
||||
});
|
||||
|
||||
if (result.choice === 2) {
|
||||
return Promise.resolve(TaskRunResult.Failure);
|
||||
}
|
||||
const debugAnyway = result.choice === 0;
|
||||
if (result.checkboxChecked) {
|
||||
this.configurationService.updateValue('debug.onTaskErrors', debugAnyway ? 'debugAnyway' : 'showErrors');
|
||||
}
|
||||
if (debugAnyway) {
|
||||
return TaskRunResult.Success;
|
||||
}
|
||||
|
||||
this.panelService.openPanel(Constants.MARKERS_PANEL_ID);
|
||||
return Promise.resolve(TaskRunResult.Failure);
|
||||
} catch (err) {
|
||||
await onError(err.message, [this.taskService.configureAction()]);
|
||||
return TaskRunResult.Failure;
|
||||
}
|
||||
}
|
||||
|
||||
async runTask(root: IWorkspace | IWorkspaceFolder | undefined, taskId: string | TaskIdentifier | undefined): Promise<ITaskSummary | null> {
|
||||
if (!taskId) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
if (!root) {
|
||||
return Promise.reject(new Error(nls.localize('invalidTaskReference', "Task '{0}' can not be referenced from a launch configuration that is in a different workspace folder.", typeof taskId === 'string' ? taskId : taskId.type)));
|
||||
}
|
||||
// run a task before starting a debug session
|
||||
const task = await this.taskService.getTask(root, taskId);
|
||||
if (!task) {
|
||||
const errorMessage = typeof taskId === 'string'
|
||||
? nls.localize('DebugTaskNotFoundWithTaskId', "Could not find the task '{0}'.", taskId)
|
||||
: nls.localize('DebugTaskNotFound', "Could not find the specified task.");
|
||||
return Promise.reject(createErrorWithActions(errorMessage));
|
||||
}
|
||||
|
||||
// If a task is missing the problem matcher the promise will never complete, so we need to have a workaround #35340
|
||||
let taskStarted = false;
|
||||
const inactivePromise: Promise<ITaskSummary | null> = new Promise((c, e) => once(e => {
|
||||
// When a task isBackground it will go inactive when it is safe to launch.
|
||||
// But when a background task is terminated by the user, it will also fire an inactive event.
|
||||
// This means that we will not get to see the real exit code from running the task (undefined when terminated by the user).
|
||||
// Catch the ProcessEnded event here, which occurs before inactive, and capture the exit code to prevent this.
|
||||
return (e.kind === TaskEventKind.Inactive
|
||||
|| (e.kind === TaskEventKind.ProcessEnded && e.exitCode === undefined))
|
||||
&& e.taskId === task._id;
|
||||
}, this.taskService.onDidStateChange)(e => {
|
||||
taskStarted = true;
|
||||
c(e.kind === TaskEventKind.ProcessEnded ? { exitCode: e.exitCode } : null);
|
||||
}));
|
||||
|
||||
const promise: Promise<ITaskSummary | null> = this.taskService.getActiveTasks().then(async (tasks): Promise<ITaskSummary | null> => {
|
||||
if (tasks.filter(t => t._id === task._id).length) {
|
||||
// Check that the task isn't busy and if it is, wait for it
|
||||
const busyTasks = await this.taskService.getBusyTasks();
|
||||
if (busyTasks.filter(t => t._id === task._id).length) {
|
||||
taskStarted = true;
|
||||
return inactivePromise;
|
||||
}
|
||||
// task is already running and isn't busy - nothing to do.
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
once(e => ((e.kind === TaskEventKind.Active) || (e.kind === TaskEventKind.DependsOnStarted)) && e.taskId === task._id, this.taskService.onDidStateChange)(() => {
|
||||
// Task is active, so everything seems to be fine, no need to prompt after 10 seconds
|
||||
// Use case being a slow running task should not be prompted even though it takes more than 10 seconds
|
||||
taskStarted = true;
|
||||
});
|
||||
const taskPromise = this.taskService.run(task);
|
||||
if (task.configurationProperties.isBackground) {
|
||||
return inactivePromise;
|
||||
}
|
||||
|
||||
return taskPromise.then(withUndefinedAsNull);
|
||||
});
|
||||
|
||||
return new Promise((c, e) => {
|
||||
promise.then(result => {
|
||||
taskStarted = true;
|
||||
c(result);
|
||||
}, error => e(error));
|
||||
|
||||
setTimeout(() => {
|
||||
if (!taskStarted) {
|
||||
const errorMessage = typeof taskId === 'string'
|
||||
? nls.localize('taskNotTrackedWithTaskId', "The specified task cannot be tracked.")
|
||||
: nls.localize('taskNotTracked', "The task '{0}' cannot be tracked.", JSON.stringify(taskId));
|
||||
e({ severity: severity.Error, message: errorMessage });
|
||||
}
|
||||
}, 10000);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user