mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-16 17:22:29 -05:00
Vscode merge (#4582)
* Merge from vscode 37cb23d3dd4f9433d56d4ba5ea3203580719a0bd * fix issues with merges * bump node version in azpipe * replace license headers * remove duplicate launch task * fix build errors * fix build errors * fix tslint issues * working through package and linux build issues * more work * wip * fix packaged builds * working through linux build errors * wip * wip * wip * fix mac and linux file limits * iterate linux pipeline * disable editor typing * revert series to parallel * remove optimize vscode from linux * fix linting issues * revert testing change * add work round for new node * readd packaging for extensions * fix issue with angular not resolving decorator dependencies
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as path from 'path';
|
||||
import * as path from 'vs/base/common/path';
|
||||
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as Objects from 'vs/base/common/objects';
|
||||
@@ -11,16 +11,18 @@ import { asPromise } from 'vs/base/common/async';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { win32 } from 'vs/base/node/processes';
|
||||
|
||||
import { IExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
||||
import { MainContext, MainThreadTaskShape, ExtHostTaskShape, IMainContext } from 'vs/workbench/api/node/extHost.protocol';
|
||||
|
||||
import * as types from 'vs/workbench/api/node/extHostTypes';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import { ExtHostWorkspace, IExtHostWorkspaceProvider } from 'vs/workbench/api/node/extHostWorkspace';
|
||||
import * as vscode from 'vscode';
|
||||
import {
|
||||
TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO, ProcessExecutionOptionsDTO, ProcessExecutionDTO,
|
||||
ShellExecutionOptionsDTO, ShellExecutionDTO, TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO, TaskSetDTO
|
||||
TaskDefinitionDTO, TaskExecutionDTO, TaskPresentationOptionsDTO,
|
||||
ProcessExecutionOptionsDTO, ProcessExecutionDTO,
|
||||
ShellExecutionOptionsDTO, ShellExecutionDTO,
|
||||
CustomExecutionDTO,
|
||||
TaskDTO, TaskHandleDTO, TaskFilterDTO, TaskProcessStartedDTO, TaskProcessEndedDTO, TaskSystemInfoDTO, TaskSetDTO
|
||||
} from '../shared/tasks';
|
||||
|
||||
// {{SQL CARBON EDIT}}
|
||||
@@ -28,17 +30,20 @@ import {
|
||||
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/node/extHostDocumentsAndEditors';
|
||||
import { ExtHostConfiguration } from 'vs/workbench/api/node/extHostConfiguration';
|
||||
import { ExtHostTerminalService, ExtHostTerminal } from 'vs/workbench/api/node/extHostTerminalService';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
namespace TaskDefinitionDTO {
|
||||
export function from(value: vscode.TaskDefinition): TaskDefinitionDTO {
|
||||
export function from(value: vscode.TaskDefinition): TaskDefinitionDTO | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
export function to(value: TaskDefinitionDTO): vscode.TaskDefinition {
|
||||
export function to(value: TaskDefinitionDTO): vscode.TaskDefinition | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -47,13 +52,13 @@ namespace TaskDefinitionDTO {
|
||||
}
|
||||
|
||||
namespace TaskPresentationOptionsDTO {
|
||||
export function from(value: vscode.TaskPresentationOptions): TaskPresentationOptionsDTO {
|
||||
export function from(value: vscode.TaskPresentationOptions): TaskPresentationOptionsDTO | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
export function to(value: TaskPresentationOptionsDTO): vscode.TaskPresentationOptions {
|
||||
export function to(value: TaskPresentationOptionsDTO): vscode.TaskPresentationOptions | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -62,13 +67,13 @@ namespace TaskPresentationOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ProcessExecutionOptionsDTO {
|
||||
export function from(value: vscode.ProcessExecutionOptions): ProcessExecutionOptionsDTO {
|
||||
export function from(value: vscode.ProcessExecutionOptions): ProcessExecutionOptionsDTO | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
export function to(value: ProcessExecutionOptionsDTO): vscode.ProcessExecutionOptions {
|
||||
export function to(value: ProcessExecutionOptionsDTO): vscode.ProcessExecutionOptions | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -77,15 +82,19 @@ namespace ProcessExecutionOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ProcessExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO): value is ProcessExecutionDTO {
|
||||
let candidate = value as ProcessExecutionDTO;
|
||||
return candidate && !!candidate.process;
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined): value is ProcessExecutionDTO {
|
||||
if (value) {
|
||||
const candidate = value as ProcessExecutionDTO;
|
||||
return candidate && !!candidate.process;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function from(value: vscode.ProcessExecution): ProcessExecutionDTO {
|
||||
export function from(value: vscode.ProcessExecution): ProcessExecutionDTO | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
let result: ProcessExecutionDTO = {
|
||||
const result: ProcessExecutionDTO = {
|
||||
process: value.process,
|
||||
args: value.args
|
||||
};
|
||||
@@ -94,7 +103,7 @@ namespace ProcessExecutionDTO {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export function to(value: ProcessExecutionDTO): types.ProcessExecution {
|
||||
export function to(value: ProcessExecutionDTO): types.ProcessExecution | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -103,13 +112,13 @@ namespace ProcessExecutionDTO {
|
||||
}
|
||||
|
||||
namespace ShellExecutionOptionsDTO {
|
||||
export function from(value: vscode.ShellExecutionOptions): ShellExecutionOptionsDTO {
|
||||
export function from(value: vscode.ShellExecutionOptions): ShellExecutionOptionsDTO | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
export function to(value: ShellExecutionOptionsDTO): vscode.ShellExecutionOptions {
|
||||
export function to(value: ShellExecutionOptionsDTO): vscode.ShellExecutionOptions | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -118,15 +127,19 @@ namespace ShellExecutionOptionsDTO {
|
||||
}
|
||||
|
||||
namespace ShellExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO): value is ShellExecutionDTO {
|
||||
let candidate = value as ShellExecutionDTO;
|
||||
return candidate && (!!candidate.commandLine || !!candidate.command);
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined): value is ShellExecutionDTO {
|
||||
if (value) {
|
||||
const candidate = value as ShellExecutionDTO;
|
||||
return candidate && (!!candidate.commandLine || !!candidate.command);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
export function from(value: vscode.ShellExecution): ShellExecutionDTO {
|
||||
export function from(value: vscode.ShellExecution): ShellExecutionDTO | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
let result: ShellExecutionDTO = {
|
||||
const result: ShellExecutionDTO = {
|
||||
};
|
||||
if (value.commandLine !== undefined) {
|
||||
result.commandLine = value.commandLine;
|
||||
@@ -139,27 +152,44 @@ namespace ShellExecutionDTO {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
export function to(value: ShellExecutionDTO): types.ShellExecution {
|
||||
if (value === undefined || value === null) {
|
||||
export function to(value: ShellExecutionDTO): types.ShellExecution | undefined {
|
||||
if (value === undefined || value === null || (value.command === undefined && value.commandLine === undefined)) {
|
||||
return undefined;
|
||||
}
|
||||
if (value.commandLine) {
|
||||
return new types.ShellExecution(value.commandLine, value.options);
|
||||
} else {
|
||||
return new types.ShellExecution(value.command, value.args ? value.args : [], value.options);
|
||||
return new types.ShellExecution(value.command!, value.args ? value.args : [], value.options);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace CustomExecutionDTO {
|
||||
export function is(value: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined): value is CustomExecutionDTO {
|
||||
if (value) {
|
||||
let candidate = value as CustomExecutionDTO;
|
||||
return candidate && candidate.customExecution === 'customExecution';
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function from(value: vscode.CustomExecution): CustomExecutionDTO {
|
||||
return {
|
||||
customExecution: 'customExecution'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace TaskHandleDTO {
|
||||
export function from(value: types.Task): TaskHandleDTO {
|
||||
let folder: UriComponents;
|
||||
let folder: UriComponents | undefined;
|
||||
if (value.scope !== undefined && typeof value.scope !== 'number') {
|
||||
folder = value.scope.uri;
|
||||
}
|
||||
return {
|
||||
id: value._id,
|
||||
workspaceFolder: folder
|
||||
id: value._id!,
|
||||
workspaceFolder: folder!
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -170,9 +200,9 @@ namespace TaskDTO {
|
||||
if (tasks === undefined || tasks === null) {
|
||||
return [];
|
||||
}
|
||||
let result: TaskDTO[] = [];
|
||||
const result: TaskDTO[] = [];
|
||||
for (let task of tasks) {
|
||||
let converted = from(task, extension);
|
||||
const converted = from(task, extension);
|
||||
if (converted) {
|
||||
result.push(converted);
|
||||
}
|
||||
@@ -180,17 +210,19 @@ namespace TaskDTO {
|
||||
return result;
|
||||
}
|
||||
|
||||
export function from(value: vscode.Task, extension: IExtensionDescription): TaskDTO {
|
||||
export function from(value: vscode.Task, extension: IExtensionDescription): TaskDTO | undefined {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
let execution: ShellExecutionDTO | ProcessExecutionDTO;
|
||||
let execution: ShellExecutionDTO | ProcessExecutionDTO | CustomExecutionDTO | undefined;
|
||||
if (value.execution instanceof types.ProcessExecution) {
|
||||
execution = ProcessExecutionDTO.from(value.execution);
|
||||
} else if (value.execution instanceof types.ShellExecution) {
|
||||
execution = ShellExecutionDTO.from(value.execution);
|
||||
} else if ((<vscode.Task2>value).execution2 && (<vscode.Task2>value).execution2 instanceof types.CustomExecution) {
|
||||
execution = CustomExecutionDTO.from(<types.CustomExecution>(<vscode.Task2>value).execution2);
|
||||
}
|
||||
let definition: TaskDefinitionDTO = TaskDefinitionDTO.from(value.definition);
|
||||
const definition: TaskDefinitionDTO | undefined = TaskDefinitionDTO.from(value.definition);
|
||||
let scope: number | UriComponents;
|
||||
if (value.scope) {
|
||||
if (typeof value.scope === 'number') {
|
||||
@@ -205,9 +237,9 @@ namespace TaskDTO {
|
||||
if (!definition || !scope) {
|
||||
return undefined;
|
||||
}
|
||||
let group = (value.group as types.TaskGroup) ? (value.group as types.TaskGroup).id : undefined;
|
||||
let result: TaskDTO = {
|
||||
_id: (value as types.Task)._id,
|
||||
const group = (value.group as types.TaskGroup) ? (value.group as types.TaskGroup).id : undefined;
|
||||
const result: TaskDTO = {
|
||||
_id: (value as types.Task)._id!,
|
||||
definition,
|
||||
name: value.name,
|
||||
source: {
|
||||
@@ -215,7 +247,7 @@ namespace TaskDTO {
|
||||
label: value.source,
|
||||
scope: scope
|
||||
},
|
||||
execution,
|
||||
execution: execution!,
|
||||
isBackground: value.isBackground,
|
||||
group: group,
|
||||
presentationOptions: TaskPresentationOptionsDTO.from(value.presentationOptions),
|
||||
@@ -225,24 +257,24 @@ namespace TaskDTO {
|
||||
};
|
||||
return result;
|
||||
}
|
||||
export function to(value: TaskDTO, workspace: ExtHostWorkspace): types.Task {
|
||||
export async function to(value: TaskDTO | undefined, workspace: IExtHostWorkspaceProvider): Promise<types.Task | undefined> {
|
||||
if (value === undefined || value === null) {
|
||||
return undefined;
|
||||
}
|
||||
let execution: types.ShellExecution | types.ProcessExecution;
|
||||
let execution: types.ShellExecution | types.ProcessExecution | undefined;
|
||||
if (ProcessExecutionDTO.is(value.execution)) {
|
||||
execution = ProcessExecutionDTO.to(value.execution);
|
||||
} else if (ShellExecutionDTO.is(value.execution)) {
|
||||
execution = ShellExecutionDTO.to(value.execution);
|
||||
}
|
||||
let definition: vscode.TaskDefinition = TaskDefinitionDTO.to(value.definition);
|
||||
let scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder;
|
||||
const definition: vscode.TaskDefinition | undefined = TaskDefinitionDTO.to(value.definition);
|
||||
let scope: vscode.TaskScope.Global | vscode.TaskScope.Workspace | vscode.WorkspaceFolder | undefined;
|
||||
if (value.source) {
|
||||
if (value.source.scope !== undefined) {
|
||||
if (typeof value.source.scope === 'number') {
|
||||
scope = value.source.scope;
|
||||
} else {
|
||||
scope = workspace.resolveWorkspaceFolder(URI.revive(value.source.scope));
|
||||
scope = await workspace.resolveWorkspaceFolder(URI.revive(value.source.scope));
|
||||
}
|
||||
} else {
|
||||
scope = types.TaskScope.Workspace;
|
||||
@@ -251,7 +283,7 @@ namespace TaskDTO {
|
||||
if (!definition || !scope) {
|
||||
return undefined;
|
||||
}
|
||||
let result = new types.Task(definition, scope, value.name, value.source.label, execution, value.problemMatchers);
|
||||
const result = new types.Task(definition, scope, value.name!, value.source.label, execution, value.problemMatchers);
|
||||
if (value.isBackground !== undefined) {
|
||||
result.isBackground = value.isBackground;
|
||||
}
|
||||
@@ -259,7 +291,7 @@ namespace TaskDTO {
|
||||
result.group = types.TaskGroup.from(value.group);
|
||||
}
|
||||
if (value.presentationOptions) {
|
||||
result.presentationOptions = TaskPresentationOptionsDTO.to(value.presentationOptions);
|
||||
result.presentationOptions = TaskPresentationOptionsDTO.to(value.presentationOptions)!;
|
||||
}
|
||||
if (value._id) {
|
||||
result._id = value._id;
|
||||
@@ -269,11 +301,11 @@ namespace TaskDTO {
|
||||
}
|
||||
|
||||
namespace TaskFilterDTO {
|
||||
export function from(value: vscode.TaskFilter): TaskFilterDTO {
|
||||
export function from(value: vscode.TaskFilter | undefined): TaskFilterDTO | undefined {
|
||||
return value;
|
||||
}
|
||||
|
||||
export function to(value: TaskFilterDTO): vscode.TaskFilter {
|
||||
export function to(value: TaskFilterDTO): vscode.TaskFilter | undefined {
|
||||
if (!value) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -302,8 +334,12 @@ class TaskExecutionImpl implements vscode.TaskExecution {
|
||||
}
|
||||
|
||||
namespace TaskExecutionDTO {
|
||||
export function to(value: TaskExecutionDTO, tasks: ExtHostTask): vscode.TaskExecution {
|
||||
return new TaskExecutionImpl(tasks, value.id, TaskDTO.to(value.task, tasks.extHostWorkspace));
|
||||
export async function to(value: TaskExecutionDTO, tasks: ExtHostTask, workspaceProvider: IExtHostWorkspaceProvider): Promise<vscode.TaskExecution> {
|
||||
const task = await TaskDTO.to(value.task, workspaceProvider);
|
||||
if (!task) {
|
||||
throw new Error('Unexpected: Task cannot be created.');
|
||||
}
|
||||
return new TaskExecutionImpl(tasks, value.id, task);
|
||||
}
|
||||
export function from(value: vscode.TaskExecution): TaskExecutionDTO {
|
||||
return {
|
||||
@@ -318,15 +354,121 @@ interface HandlerData {
|
||||
extension: IExtensionDescription;
|
||||
}
|
||||
|
||||
class CustomExecutionData implements IDisposable {
|
||||
private static waitForDimensionsTimeoutInMs: number = 5000;
|
||||
private _cancellationSource?: CancellationTokenSource;
|
||||
private readonly _onTaskExecutionComplete: Emitter<CustomExecutionData> = new Emitter<CustomExecutionData>();
|
||||
private readonly _disposables: IDisposable[] = [];
|
||||
private terminal?: vscode.Terminal;
|
||||
private terminalId?: number;
|
||||
public result: number | undefined;
|
||||
|
||||
constructor(
|
||||
private readonly customExecution: vscode.CustomExecution,
|
||||
private readonly terminalService: ExtHostTerminalService) {
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
dispose(this._disposables);
|
||||
}
|
||||
|
||||
public get onTaskExecutionComplete(): Event<CustomExecutionData> {
|
||||
return this._onTaskExecutionComplete.event;
|
||||
}
|
||||
|
||||
private onDidCloseTerminal(terminal: vscode.Terminal): void {
|
||||
if ((this.terminal === terminal) && this._cancellationSource) {
|
||||
this._cancellationSource.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
private onDidOpenTerminal(terminal: vscode.Terminal): void {
|
||||
if (!(terminal instanceof ExtHostTerminal)) {
|
||||
throw new Error('How could this not be a extension host terminal?');
|
||||
}
|
||||
|
||||
if (this.terminalId && terminal._id === this.terminalId) {
|
||||
this.startCallback(this.terminalId);
|
||||
}
|
||||
}
|
||||
|
||||
public async startCallback(terminalId: number): Promise<void> {
|
||||
this.terminalId = terminalId;
|
||||
|
||||
// If we have already started the extension task callback, then
|
||||
// do not start it again.
|
||||
// It is completely valid for multiple terminals to be opened
|
||||
// before the one for our task.
|
||||
if (this._cancellationSource) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const callbackTerminals: vscode.Terminal[] = this.terminalService.terminals.filter((terminal) => terminal._id === terminalId);
|
||||
|
||||
if (!callbackTerminals || callbackTerminals.length === 0) {
|
||||
this._disposables.push(this.terminalService.onDidOpenTerminal(this.onDidOpenTerminal.bind(this)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (callbackTerminals.length !== 1) {
|
||||
throw new Error(`Expected to only have one terminal at this point`);
|
||||
}
|
||||
|
||||
this.terminal = callbackTerminals[0];
|
||||
const terminalRenderer: vscode.TerminalRenderer = await this.terminalService.resolveTerminalRenderer(terminalId);
|
||||
|
||||
// If we don't have the maximum dimensions yet, then we need to wait for them (but not indefinitely).
|
||||
// Custom executions will expect the dimensions to be set properly before they are launched.
|
||||
// BUT, due to the API contract VSCode has for terminals and dimensions, they are still responsible for
|
||||
// handling cases where they are not set.
|
||||
if (!terminalRenderer.maximumDimensions) {
|
||||
const dimensionTimeout: Promise<void> = new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, CustomExecutionData.waitForDimensionsTimeoutInMs);
|
||||
});
|
||||
|
||||
let dimensionsRegistration: IDisposable | undefined;
|
||||
const dimensionsPromise: Promise<void> = new Promise((resolve) => {
|
||||
dimensionsRegistration = terminalRenderer.onDidChangeMaximumDimensions((newDimensions) => {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
await Promise.race([dimensionTimeout, dimensionsPromise]);
|
||||
if (dimensionsRegistration) {
|
||||
dimensionsRegistration.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
this._cancellationSource = new CancellationTokenSource();
|
||||
this._disposables.push(this._cancellationSource);
|
||||
|
||||
this._disposables.push(this.terminalService.onDidCloseTerminal(this.onDidCloseTerminal.bind(this)));
|
||||
|
||||
// Regardless of how the task completes, we are done with this custom execution task.
|
||||
this.customExecution.callback(terminalRenderer, this._cancellationSource.token).then(
|
||||
(success) => {
|
||||
this.result = success;
|
||||
this._onTaskExecutionComplete.fire(this);
|
||||
}, (rejected) => {
|
||||
this._onTaskExecutionComplete.fire(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostTask implements ExtHostTaskShape {
|
||||
|
||||
private _proxy: MainThreadTaskShape;
|
||||
private _workspaceService: ExtHostWorkspace;
|
||||
private _workspaceProvider: IExtHostWorkspaceProvider;
|
||||
private _editorService: ExtHostDocumentsAndEditors;
|
||||
private _configurationService: ExtHostConfiguration;
|
||||
private _terminalService: ExtHostTerminalService;
|
||||
private _handleCounter: number;
|
||||
private _handlers: Map<number, HandlerData>;
|
||||
private _taskExecutions: Map<string, TaskExecutionImpl>;
|
||||
private _providedCustomExecutions: Map<string, CustomExecutionData>;
|
||||
private _activeCustomExecutions: Map<string, CustomExecutionData>;
|
||||
|
||||
private readonly _onDidExecuteTask: Emitter<vscode.TaskStartEvent> = new Emitter<vscode.TaskStartEvent>();
|
||||
private readonly _onDidTerminateTask: Emitter<vscode.TaskEndEvent> = new Emitter<vscode.TaskEndEvent>();
|
||||
@@ -334,25 +476,29 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
private readonly _onDidTaskProcessStarted: Emitter<vscode.TaskProcessStartEvent> = new Emitter<vscode.TaskProcessStartEvent>();
|
||||
private readonly _onDidTaskProcessEnded: Emitter<vscode.TaskProcessEndEvent> = new Emitter<vscode.TaskProcessEndEvent>();
|
||||
|
||||
constructor(mainContext: IMainContext, workspaceService: ExtHostWorkspace, editorService: ExtHostDocumentsAndEditors, configurationService: ExtHostConfiguration) {
|
||||
constructor(
|
||||
mainContext: IMainContext,
|
||||
workspaceService: ExtHostWorkspace,
|
||||
editorService: ExtHostDocumentsAndEditors,
|
||||
configurationService: ExtHostConfiguration,
|
||||
extHostTerminalService: ExtHostTerminalService) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadTask);
|
||||
this._workspaceService = workspaceService;
|
||||
this._workspaceProvider = workspaceService;
|
||||
this._editorService = editorService;
|
||||
this._configurationService = configurationService;
|
||||
this._terminalService = extHostTerminalService;
|
||||
this._handleCounter = 0;
|
||||
this._handlers = new Map<number, HandlerData>();
|
||||
this._taskExecutions = new Map<string, TaskExecutionImpl>();
|
||||
}
|
||||
|
||||
public get extHostWorkspace(): ExtHostWorkspace {
|
||||
return this._workspaceService;
|
||||
this._providedCustomExecutions = new Map<string, CustomExecutionData>();
|
||||
this._activeCustomExecutions = new Map<string, CustomExecutionData>();
|
||||
}
|
||||
|
||||
public registerTaskProvider(extension: IExtensionDescription, provider: vscode.TaskProvider): vscode.Disposable {
|
||||
if (!provider) {
|
||||
return new types.Disposable(() => { });
|
||||
}
|
||||
let handle = this.nextHandle();
|
||||
const handle = this.nextHandle();
|
||||
this._handlers.set(handle, { provider, extension });
|
||||
this._proxy.$registerTaskProvider(handle);
|
||||
return new types.Disposable(() => {
|
||||
@@ -366,10 +512,10 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
}
|
||||
|
||||
public fetchTasks(filter?: vscode.TaskFilter): Promise<vscode.Task[]> {
|
||||
return this._proxy.$fetchTasks(TaskFilterDTO.from(filter)).then((values) => {
|
||||
let result: vscode.Task[] = [];
|
||||
return this._proxy.$fetchTasks(TaskFilterDTO.from(filter)).then(async (values) => {
|
||||
const result: vscode.Task[] = [];
|
||||
for (let value of values) {
|
||||
let task = TaskDTO.to(value, this._workspaceService);
|
||||
const task = await TaskDTO.to(value, this._workspaceProvider);
|
||||
if (task) {
|
||||
result.push(task);
|
||||
}
|
||||
@@ -378,13 +524,13 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
});
|
||||
}
|
||||
|
||||
public executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution> {
|
||||
let tTask = (task as types.Task);
|
||||
public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution> {
|
||||
const tTask = (task as types.Task);
|
||||
// We have a preserved ID. So the task didn't change.
|
||||
if (tTask._id !== undefined) {
|
||||
return this._proxy.$executeTask(TaskHandleDTO.from(tTask)).then(value => this.getTaskExecution(value, task));
|
||||
} else {
|
||||
let dto = TaskDTO.from(task, extension);
|
||||
const dto = TaskDTO.from(task, extension);
|
||||
if (dto === undefined) {
|
||||
return Promise.reject(new Error('Task is not valid'));
|
||||
}
|
||||
@@ -393,7 +539,7 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
}
|
||||
|
||||
public get taskExecutions(): vscode.TaskExecution[] {
|
||||
let result: vscode.TaskExecution[] = [];
|
||||
const result: vscode.TaskExecution[] = [];
|
||||
this._taskExecutions.forEach(value => result.push(value));
|
||||
return result;
|
||||
}
|
||||
@@ -409,9 +555,28 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return this._onDidExecuteTask.event;
|
||||
}
|
||||
|
||||
public $onDidStartTask(execution: TaskExecutionDTO): void {
|
||||
public async $onDidStartTask(execution: TaskExecutionDTO, terminalId: number): Promise<void> {
|
||||
// Once a terminal is spun up for the custom execution task this event will be fired.
|
||||
// At that point, we need to actually start the callback, but
|
||||
// only if it hasn't already begun.
|
||||
const extensionCallback: CustomExecutionData | undefined = this._providedCustomExecutions.get(execution.id);
|
||||
if (extensionCallback) {
|
||||
if (this._activeCustomExecutions.get(execution.id) !== undefined) {
|
||||
throw new Error('We should not be trying to start the same custom task executions twice.');
|
||||
}
|
||||
|
||||
this._activeCustomExecutions.set(execution.id, extensionCallback);
|
||||
|
||||
const taskExecutionComplete: IDisposable = extensionCallback.onTaskExecutionComplete(() => {
|
||||
this.customExecutionComplete(execution);
|
||||
taskExecutionComplete.dispose();
|
||||
});
|
||||
|
||||
extensionCallback.startCallback(terminalId);
|
||||
}
|
||||
|
||||
this._onDidExecuteTask.fire({
|
||||
execution: this.getTaskExecution(execution)
|
||||
execution: await this.getTaskExecution(execution)
|
||||
});
|
||||
}
|
||||
|
||||
@@ -419,9 +584,10 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return this._onDidTerminateTask.event;
|
||||
}
|
||||
|
||||
public $OnDidEndTask(execution: TaskExecutionDTO): void {
|
||||
const _execution = this.getTaskExecution(execution);
|
||||
public async $OnDidEndTask(execution: TaskExecutionDTO): Promise<void> {
|
||||
const _execution = await this.getTaskExecution(execution);
|
||||
this._taskExecutions.delete(execution.id);
|
||||
this.customExecutionComplete(execution);
|
||||
this._onDidTerminateTask.fire({
|
||||
execution: _execution
|
||||
});
|
||||
@@ -431,8 +597,8 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return this._onDidTaskProcessStarted.event;
|
||||
}
|
||||
|
||||
public $onDidStartTaskProcess(value: TaskProcessStartedDTO): void {
|
||||
const execution = this.getTaskExecution(value.id);
|
||||
public async $onDidStartTaskProcess(value: TaskProcessStartedDTO): Promise<void> {
|
||||
const execution = await this.getTaskExecution(value.id);
|
||||
if (execution) {
|
||||
this._onDidTaskProcessStarted.fire({
|
||||
execution: execution,
|
||||
@@ -445,8 +611,8 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return this._onDidTaskProcessEnded.event;
|
||||
}
|
||||
|
||||
public $onDidEndTaskProcess(value: TaskProcessEndedDTO): void {
|
||||
const execution = this.getTaskExecution(value.id);
|
||||
public async $onDidEndTaskProcess(value: TaskProcessEndedDTO): Promise<void> {
|
||||
const execution = await this.getTaskExecution(value.id);
|
||||
if (execution) {
|
||||
this._onDidTaskProcessEnded.fire({
|
||||
execution: execution,
|
||||
@@ -456,63 +622,106 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
}
|
||||
|
||||
public $provideTasks(handle: number, validTypes: { [key: string]: boolean; }): Thenable<TaskSetDTO> {
|
||||
let handler = this._handlers.get(handle);
|
||||
const handler = this._handlers.get(handle);
|
||||
if (!handler) {
|
||||
return Promise.reject(new Error('no handler found'));
|
||||
}
|
||||
return asPromise(() => handler.provider.provideTasks(CancellationToken.None)).then(value => {
|
||||
let sanitized: vscode.Task[] = [];
|
||||
for (let task of value) {
|
||||
if (task.definition && validTypes[task.definition.type] === true) {
|
||||
sanitized.push(task);
|
||||
} else {
|
||||
sanitized.push(task);
|
||||
console.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`);
|
||||
|
||||
// For custom execution tasks, we need to store the execution objects locally
|
||||
// since we obviously cannot send callback functions through the proxy.
|
||||
// So, clear out any existing ones.
|
||||
this._providedCustomExecutions.clear();
|
||||
|
||||
// Set up a list of task ID promises that we can wait on
|
||||
// before returning the provided tasks. The ensures that
|
||||
// our task IDs are calculated for any custom execution tasks.
|
||||
// Knowing this ID ahead of time is needed because when a task
|
||||
// start event is fired this is when the custom execution is called.
|
||||
// The task start event is also the first time we see the ID from the main
|
||||
// thread, which is too late for us because we need to save an map
|
||||
// from an ID to the custom execution function. (Kind of a cart before the horse problem).
|
||||
const taskIdPromises: Promise<void>[] = [];
|
||||
const fetchPromise = asPromise(() => handler.provider.provideTasks(CancellationToken.None)).then(value => {
|
||||
const taskDTOs: TaskDTO[] = [];
|
||||
if (value) {
|
||||
for (let task of value) {
|
||||
if (!task.definition || !validTypes[task.definition.type]) {
|
||||
console.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`);
|
||||
}
|
||||
|
||||
const taskDTO: TaskDTO | undefined = TaskDTO.from(task, handler.extension);
|
||||
if (taskDTO) {
|
||||
taskDTOs.push(taskDTO);
|
||||
|
||||
if (CustomExecutionDTO.is(taskDTO.execution)) {
|
||||
taskIdPromises.push(new Promise((resolve) => {
|
||||
// The ID is calculated on the main thread task side, so, let's call into it here.
|
||||
// We need the task id's pre-computed for custom task executions because when OnDidStartTask
|
||||
// is invoked, we have to be able to map it back to our data.
|
||||
this._proxy.$createTaskId(taskDTO).then((taskId) => {
|
||||
this._providedCustomExecutions.set(taskId, new CustomExecutionData(<vscode.CustomExecution>(<vscode.Task2>task).execution2, this._terminalService));
|
||||
resolve();
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
tasks: TaskDTO.fromMany(sanitized, handler.extension),
|
||||
tasks: taskDTOs,
|
||||
extension: handler.extension
|
||||
};
|
||||
});
|
||||
|
||||
return new Promise((resolve) => {
|
||||
fetchPromise.then((result) => {
|
||||
Promise.all(taskIdPromises).then(() => {
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// {{SQL CARBON EDIT}} disable debug related method
|
||||
public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }> {
|
||||
// const configProvider = await this._configurationService.getConfigProvider();
|
||||
// let uri: URI = URI.revive(uriComponents);
|
||||
// let result = {
|
||||
// process: undefined as string,
|
||||
// variables: Object.create(null)
|
||||
// };
|
||||
// let workspaceFolder = this._workspaceService.resolveWorkspaceFolder(uri);
|
||||
// let resolver = new ExtHostVariableResolverService(this._workspaceService, this._editorService, configProvider);
|
||||
// let ws: IWorkspaceFolder = {
|
||||
// uri: workspaceFolder.uri,
|
||||
// name: workspaceFolder.name,
|
||||
// index: workspaceFolder.index,
|
||||
// toResource: () => {
|
||||
// throw new Error('Not implemented');
|
||||
// }
|
||||
// };
|
||||
// for (let variable of toResolve.variables) {
|
||||
// result.variables[variable] = resolver.resolve(ws, variable);
|
||||
// }
|
||||
// if (toResolve.process !== undefined) {
|
||||
// let paths: string[] | undefined = undefined;
|
||||
// if (toResolve.process.path !== undefined) {
|
||||
// paths = toResolve.process.path.split(path.delimiter);
|
||||
// for (let i = 0; i < paths.length; i++) {
|
||||
// paths[i] = resolver.resolve(ws, paths[i]);
|
||||
// }
|
||||
// }
|
||||
// result.process = win32.findExecutable(
|
||||
// resolver.resolve(ws, toResolve.process.name),
|
||||
// toResolve.process.cwd !== undefined ? resolver.resolve(ws, toResolve.process.cwd) : undefined,
|
||||
// paths
|
||||
// );
|
||||
// }
|
||||
// return result;
|
||||
/*const configProvider = await this._configurationService.getConfigProvider();
|
||||
const uri: URI = URI.revive(uriComponents);
|
||||
const result = {
|
||||
process: <unknown>undefined as string,
|
||||
variables: Object.create(null)
|
||||
};
|
||||
const workspaceFolder = await this._workspaceProvider.resolveWorkspaceFolder(uri);
|
||||
const workspaceFolders = await this._workspaceProvider.getWorkspaceFolders2();
|
||||
if (!workspaceFolders || !workspaceFolder) {
|
||||
throw new Error('Unexpected: Tasks can only be run in a workspace folder');
|
||||
}
|
||||
const resolver = new ExtHostVariableResolverService(workspaceFolders, this._editorService, configProvider);
|
||||
const ws: IWorkspaceFolder = {
|
||||
uri: workspaceFolder.uri,
|
||||
name: workspaceFolder.name,
|
||||
index: workspaceFolder.index,
|
||||
toResource: () => {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
};
|
||||
for (let variable of toResolve.variables) {
|
||||
result.variables[variable] = resolver.resolve(ws, variable);
|
||||
}
|
||||
if (toResolve.process !== undefined) {
|
||||
let paths: string[] | undefined = undefined;
|
||||
if (toResolve.process.path !== undefined) {
|
||||
paths = toResolve.process.path.split(path.delimiter);
|
||||
for (let i = 0; i < paths.length; i++) {
|
||||
paths[i] = resolver.resolve(ws, paths[i]);
|
||||
}
|
||||
}
|
||||
result.process = win32.findExecutable(
|
||||
resolver.resolve(ws, toResolve.process.name),
|
||||
toResolve.process.cwd !== undefined ? resolver.resolve(ws, toResolve.process.cwd) : undefined,
|
||||
paths
|
||||
);
|
||||
}
|
||||
return result;*/
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -520,17 +729,34 @@ export class ExtHostTask implements ExtHostTaskShape {
|
||||
return this._handleCounter++;
|
||||
}
|
||||
|
||||
private getTaskExecution(execution: TaskExecutionDTO | string, task?: vscode.Task): TaskExecutionImpl {
|
||||
private async getTaskExecution(execution: TaskExecutionDTO | string, task?: vscode.Task): Promise<TaskExecutionImpl> {
|
||||
if (typeof execution === 'string') {
|
||||
return this._taskExecutions.get(execution);
|
||||
const taskExecution = this._taskExecutions.get(execution);
|
||||
if (!taskExecution) {
|
||||
throw new Error('Unexpected: The specified task is missing an execution');
|
||||
}
|
||||
return taskExecution;
|
||||
}
|
||||
|
||||
let result: TaskExecutionImpl = this._taskExecutions.get(execution.id);
|
||||
let result: TaskExecutionImpl | undefined = this._taskExecutions.get(execution.id);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
result = new TaskExecutionImpl(this, execution.id, task ? task : TaskDTO.to(execution.task, this._workspaceService));
|
||||
this._taskExecutions.set(execution.id, result);
|
||||
return result;
|
||||
const taskToCreate = task ? task : await TaskDTO.to(execution.task, this._workspaceProvider);
|
||||
if (!taskToCreate) {
|
||||
throw new Error('Unexpected: Task does not exist.');
|
||||
}
|
||||
const createdResult: TaskExecutionImpl = new TaskExecutionImpl(this, execution.id, taskToCreate);
|
||||
this._taskExecutions.set(execution.id, createdResult);
|
||||
return createdResult;
|
||||
}
|
||||
|
||||
private customExecutionComplete(execution: TaskExecutionDTO): void {
|
||||
const extensionCallback: CustomExecutionData | undefined = this._activeCustomExecutions.get(execution.id);
|
||||
if (extensionCallback) {
|
||||
this._activeCustomExecutions.delete(execution.id);
|
||||
this._proxy.$customExecutionComplete(execution.id, extensionCallback.result);
|
||||
extensionCallback.dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user