From 8410bd6fbf51490eb14c71d3abe8be794a546d50 Mon Sep 17 00:00:00 2001 From: Martin Fleck Date: Wed, 26 Jul 2023 09:13:21 +0200 Subject: [PATCH] Ensure we keep task type and properly support custom execution - Make TaskProviderAdapter more resilient against undefined - Ensure task type is not lost during conversion (used for custom exec) - Ensure task type is considered during comparison Fixes https://github.com/eclipse-theia/theia/issues/12721 --- .../plugin-ext/src/common/plugin-api-rpc.ts | 4 +-- .../plugin-ext/src/main/browser/tasks-main.ts | 8 ++--- .../src/plugin/tasks/task-provider.ts | 21 ++++++------- packages/plugin-ext/src/plugin/tasks/tasks.ts | 31 +++++++++++-------- .../src/browser/task-definition-registry.ts | 3 ++ 5 files changed, 36 insertions(+), 31 deletions(-) diff --git a/packages/plugin-ext/src/common/plugin-api-rpc.ts b/packages/plugin-ext/src/common/plugin-api-rpc.ts index 917337b1b6e81..2857dbb4d106f 100644 --- a/packages/plugin-ext/src/common/plugin-api-rpc.ts +++ b/packages/plugin-ext/src/common/plugin-api-rpc.ts @@ -2175,8 +2175,8 @@ export const MAIN_RPC_CONTEXT = { export interface TasksExt { $initLoadedTasks(executions: TaskExecutionDto[]): Promise; - $provideTasks(handle: number): Promise; - $resolveTask(handle: number, task: TaskDto, token?: CancellationToken): Promise; + $provideTasks(handle: number): Promise; + $resolveTask(handle: number, task: TaskDto, token?: CancellationToken): Promise; $onDidStartTask(execution: TaskExecutionDto, terminalId: number): void; $onDidEndTask(id: number): void; $onDidStartTaskProcess(processId: number | undefined, execution: TaskExecutionDto): void; diff --git a/packages/plugin-ext/src/main/browser/tasks-main.ts b/packages/plugin-ext/src/main/browser/tasks-main.ts index 70b009814d59d..7c674d763b06e 100644 --- a/packages/plugin-ext/src/main/browser/tasks-main.ts +++ b/packages/plugin-ext/src/main/browser/tasks-main.ts @@ -184,8 +184,8 @@ export class TasksMainImpl implements TasksMain, Disposable { protected createTaskProvider(handle: number): TaskProvider { return { provideTasks: () => - this.proxy.$provideTasks(handle).then(v => - v!.map(taskDto => + this.proxy.$provideTasks(handle).then(tasks => + tasks.map(taskDto => this.toTaskConfiguration(taskDto) ) ) @@ -195,8 +195,8 @@ export class TasksMainImpl implements TasksMain, Disposable { protected createTaskResolver(handle: number): TaskResolver { return { resolveTask: taskConfig => - this.proxy.$resolveTask(handle, this.fromTaskConfiguration(taskConfig)).then(v => - this.toTaskConfiguration(v!) + this.proxy.$resolveTask(handle, this.fromTaskConfiguration(taskConfig)).then(task => + this.toTaskConfiguration(task) ) }; } diff --git a/packages/plugin-ext/src/plugin/tasks/task-provider.ts b/packages/plugin-ext/src/plugin/tasks/task-provider.ts index 4b533549818ca..6ef22841e1c05 100644 --- a/packages/plugin-ext/src/plugin/tasks/task-provider.ts +++ b/packages/plugin-ext/src/plugin/tasks/task-provider.ts @@ -15,17 +15,17 @@ // ***************************************************************************** import * as theia from '@theia/plugin'; -import * as Converter from '../type-converters'; import { TaskDto } from '../../common'; +import * as Converter from '../type-converters'; export class TaskProviderAdapter { constructor(private readonly provider: theia.TaskProvider) { } - provideTasks(token: theia.CancellationToken): Promise { + provideTasks(token: theia.CancellationToken): Promise { return Promise.resolve(this.provider.provideTasks(token)).then(tasks => { if (!Array.isArray(tasks)) { - return undefined; + return []; } const result: TaskDto[] = []; for (const task of tasks) { @@ -40,21 +40,18 @@ export class TaskProviderAdapter { }); } - resolveTask(task: TaskDto, token: theia.CancellationToken): Promise { + async resolveTask(task: TaskDto, token: theia.CancellationToken): Promise { if (typeof this.provider.resolveTask !== 'function') { - return Promise.resolve(undefined); + return task; } const item = Converter.toTask(task); if (!item) { - return Promise.resolve(undefined); + return task; } - return Promise.resolve(this.provider.resolveTask(item, token)).then(value => { - if (value) { - return Converter.fromTask(value); - } - return undefined; - }); + const resolved = await this.provider.resolveTask(item, token); + const converted = resolved ? Converter.fromTask(resolved) : Converter.fromTask(item); + return converted ?? task; } } diff --git a/packages/plugin-ext/src/plugin/tasks/tasks.ts b/packages/plugin-ext/src/plugin/tasks/tasks.ts index ab54e5e817e70..4aecc67a3e51d 100644 --- a/packages/plugin-ext/src/plugin/tasks/tasks.ts +++ b/packages/plugin-ext/src/plugin/tasks/tasks.ts @@ -158,37 +158,42 @@ export class TasksExtImpl implements TasksExt { throw new Error('Task was not successfully transformed into a task config'); } - $provideTasks(handle: number): Promise { + async $provideTasks(handle: number): Promise { const adapter = this.adaptersMap.get(handle); if (adapter) { return adapter.provideTasks(CancellationToken.None).then(tasks => { - if (tasks) { - for (const task of tasks) { - if (task.taskType === 'customExecution') { - task.executionId = this.addCustomExecution(task.callback); - task.callback = undefined; - } + for (const task of tasks) { + if (task.taskType === 'customExecution') { + this.applyCustomExecution(task); } } return tasks; }); } else { - return Promise.reject(new Error('No adapter found to provide tasks')); + throw new Error('No adapter found to provide tasks'); } } - $resolveTask(handle: number, task: TaskDto, token: theia.CancellationToken): Promise { + async $resolveTask(handle: number, task: TaskDto, token: theia.CancellationToken): Promise { const adapter = this.adaptersMap.get(handle); if (adapter) { return adapter.resolveTask(task, token).then(resolvedTask => { - if (resolvedTask && resolvedTask.taskType === 'customExecution') { - resolvedTask.executionId = this.addCustomExecution(resolvedTask.callback); - resolvedTask.callback = undefined; + // ensure we do not lose task type and execution id during resolution as we need it for custom execution + resolvedTask.taskType = resolvedTask.taskType ?? task.taskType; + if (resolvedTask.taskType === 'customExecution') { + this.applyCustomExecution(resolvedTask); } return resolvedTask; }); } else { - return Promise.reject(new Error('No adapter found to resolve task')); + throw new Error('No adapter found to resolve task'); + } + } + + private applyCustomExecution(task: TaskDto): void { + if (task.callback) { + task.executionId = this.addCustomExecution(task.callback); + task.callback = undefined; } } diff --git a/packages/task/src/browser/task-definition-registry.ts b/packages/task/src/browser/task-definition-registry.ts index 2c80374a13a85..57ef3c539c421 100644 --- a/packages/task/src/browser/task-definition-registry.ts +++ b/packages/task/src/browser/task-definition-registry.ts @@ -113,6 +113,9 @@ export class TaskDefinitionRegistry { if (oneType !== otherType) { return false; } + if (one['taskType'] !== other['taskType']) { + return false; + } const def = this.getDefinition(one); if (def) { // scope is either a string or an enum value. Anyway...they must exactly match