diff --git a/packages/debug/src/browser/debug-session-manager.ts b/packages/debug/src/browser/debug-session-manager.ts index e481df8aa5fb3..042da3c3cfe6d 100644 --- a/packages/debug/src/browser/debug-session-manager.ts +++ b/packages/debug/src/browser/debug-session-manager.ts @@ -439,6 +439,7 @@ export class DebugSessionManager { return true; } + this.taskService.clearCache(); const taskInfo = await this.taskService.runWorkspaceTask(workspaceFolderUri, taskName); if (!checkErrors) { return true; diff --git a/packages/plugin-ext/src/main/browser/tasks-main.ts b/packages/plugin-ext/src/main/browser/tasks-main.ts index b2f98ccb9e3ed..ce9bd44a20d28 100644 --- a/packages/plugin-ext/src/main/browser/tasks-main.ts +++ b/packages/plugin-ext/src/main/browser/tasks-main.ts @@ -106,6 +106,7 @@ export class TasksMainImpl implements TasksMain, Disposable { } let found: TaskConfiguration[] = []; + this.taskService.clearCache(); const tasks = [...(await this.taskService.getConfiguredTasks()), ...(await this.taskService.getProvidedTasks())]; if (taskType) { found = tasks.filter(t => { diff --git a/packages/task/src/browser/provided-task-configurations.ts b/packages/task/src/browser/provided-task-configurations.ts index cdf27e1f7032c..341846fab3cc4 100644 --- a/packages/task/src/browser/provided-task-configurations.ts +++ b/packages/task/src/browser/provided-task-configurations.ts @@ -19,6 +19,7 @@ import { TaskProviderRegistry } from './task-contribution'; import { TaskDefinitionRegistry } from './task-definition-registry'; import { TaskConfiguration, TaskCustomization, TaskOutputPresentation } from '../common'; import URI from '@theia/core/lib/common/uri'; +import { Deferred } from '@theia/core/lib/common/promise-util'; @injectable() export class ProvidedTaskConfigurations { @@ -28,7 +29,7 @@ export class ProvidedTaskConfigurations { * For the second level of inner map, the key is task label. * For the third level of inner map, the key is the task scope and value TaskConfiguration. */ - protected tasksMap = new Map>>(); + protected tasksMap: Map>> | undefined; @inject(TaskProviderRegistry) protected readonly taskProviderRegistry: TaskProviderRegistry; @@ -36,8 +37,38 @@ export class ProvidedTaskConfigurations { @inject(TaskDefinitionRegistry) protected readonly taskDefinitionRegistry: TaskDefinitionRegistry; + protected loading: Deferred | undefined; + /** returns a list of provided tasks */ async getTasks(): Promise { + await this.ensureCachePopulated(); + const tasks: TaskConfiguration[] = []; + for (const taskLabelMap of this.tasksMap!.values()) { + for (const taskScopeMap of taskLabelMap.values()) { + for (const task of taskScopeMap.values()) { + tasks.push(task); + } + } + } + return tasks; + } + + clearCache(): void { + this.tasksMap = undefined; + } + + async ensureCachePopulated(): Promise { + if (!this.tasksMap) { + if (this.loading) { + await this.loading.promise; + } else { + await this.populateCache(); + } + } + } + + async populateCache(): Promise { + this.loading = new Deferred(); const providers = await this.taskProviderRegistry.getProviders(); const providedTasks: TaskConfiguration[] = (await Promise.all(providers.map(p => p.provideTasks()))) .reduce((acc, taskArray) => acc.concat(taskArray), []) @@ -52,17 +83,22 @@ export class ProvidedTaskConfigurations { }; }); this.cacheTasks(providedTasks); - return providedTasks; + this.loading.resolve(); + this.loading = undefined; } /** returns the task configuration for a given source and label or undefined if none */ async getTask(source: string, taskLabel: string, scope?: string): Promise { - const task = this.getCachedTask(source, taskLabel, scope); - if (task) { - return task; - } else { - await this.getTasks(); - return this.getCachedTask(source, taskLabel, scope); + await this.ensureCachePopulated(); + const labelConfigMap = this.tasksMap!.get(source); + if (labelConfigMap) { + const scopeConfigMap = labelConfigMap.get(taskLabel); + if (scopeConfigMap) { + if (scope) { + return scopeConfigMap.get(scope); + } + return Array.from(scopeConfigMap.values())[0]; + } } } @@ -111,20 +147,8 @@ export class ProvidedTaskConfigurations { return matchedTask; } - protected getCachedTask(source: string, taskLabel: string, scope?: string): TaskConfiguration | undefined { - const labelConfigMap = this.tasksMap.get(source); - if (labelConfigMap) { - const scopeConfigMap = labelConfigMap.get(taskLabel); - if (scopeConfigMap) { - if (scope) { - return scopeConfigMap.get(scope); - } - return Array.from(scopeConfigMap.values())[0]; - } - } - } - protected cacheTasks(tasks: TaskConfiguration[]): void { + this.tasksMap = new Map(); for (const task of tasks) { const label = task.label; const source = task._source; diff --git a/packages/task/src/browser/task-frontend-contribution.ts b/packages/task/src/browser/task-frontend-contribution.ts index a01e44d70db95..467a91837764d 100644 --- a/packages/task/src/browser/task-frontend-contribution.ts +++ b/packages/task/src/browser/task-frontend-contribution.ts @@ -212,6 +212,7 @@ export class TaskFrontendContribution implements CommandContribution, MenuContri { isEnabled: () => true, execute: async (label: string) => { + this.taskService.clearCache(); const didExecute = await this.taskService.runTaskByLabel(label); if (!didExecute) { this.quickOpenTask.open(); @@ -228,6 +229,7 @@ export class TaskFrontendContribution implements CommandContribution, MenuContri execute: (...args: any[]) => { const [source, label, scope] = args; if (source && label) { + this.taskService.clearCache(); return this.taskService.run(source, label, scope); } return this.quickOpenTask.open(); @@ -239,8 +241,10 @@ export class TaskFrontendContribution implements CommandContribution, MenuContri { isEnabled: () => this.workspaceService.opened, // eslint-disable-next-line @typescript-eslint/no-explicit-any - execute: (...args: any[]) => - this.quickOpenTask.runBuildOrTestTask('build') + execute: (...args: any[]) => { + this.taskService.clearCache(); + this.quickOpenTask.runBuildOrTestTask('build'); + } } ); registry.registerCommand( @@ -248,8 +252,10 @@ export class TaskFrontendContribution implements CommandContribution, MenuContri { isEnabled: () => this.workspaceService.opened, // eslint-disable-next-line @typescript-eslint/no-explicit-any - execute: (...args: any[]) => - this.quickOpenTask.runBuildOrTestTask('test') + execute: (...args: any[]) => { + this.taskService.clearCache(); + this.quickOpenTask.runBuildOrTestTask('test'); + } } ); registry.registerCommand( @@ -263,7 +269,10 @@ export class TaskFrontendContribution implements CommandContribution, MenuContri TaskCommands.TASK_RUN_LAST, { isEnabled: () => !!this.taskService.getLastTask(), - execute: () => this.taskService.runLastTask() + execute: () => { + this.taskService.clearCache(); + this.taskService.runLastTask(); + } } ); registry.registerCommand( @@ -278,7 +287,10 @@ export class TaskFrontendContribution implements CommandContribution, MenuContri registry.registerCommand( TaskCommands.TASK_CONFIGURE, { - execute: () => this.quickOpenTask.configure() + execute: () => { + this.taskService.clearCache(); + this.quickOpenTask.configure(); + } } ); @@ -306,7 +318,10 @@ export class TaskFrontendContribution implements CommandContribution, MenuContri registry.registerCommand( TaskCommands.TASK_RESTART_RUNNING, { - execute: () => this.taskRestartRunningQuickOpen.open() + execute: () => { + this.taskService.clearCache(); + this.taskRestartRunningQuickOpen.open(); + } } ); } diff --git a/packages/task/src/browser/task-service.ts b/packages/task/src/browser/task-service.ts index 8497ed301c67f..41c68d1a5f609 100644 --- a/packages/task/src/browser/task-service.ts +++ b/packages/task/src/browser/task-service.ts @@ -376,6 +376,10 @@ export class TaskService implements TaskConfigurationClient { return validTaskConfigs; } + clearCache(): void { + this.providedTaskConfigurations.clearCache(); + } + /** Returns an array of the task configurations which are provided by the extensions. */ getProvidedTasks(): Promise { return this.providedTaskConfigurations.getTasks();