in patched-vscode/src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts [2004:2224]
private async _getGroupedTasks(filter?: ITaskFilter): Promise<TaskMap> {
await this._waitForAllSupportedExecutions;
const type = filter?.type;
const needsRecentTasksMigration = this._needsRecentTasksMigration();
await this._activateTaskProviders(filter?.type);
const validTypes: IStringDictionary<boolean> = Object.create(null);
TaskDefinitionRegistry.all().forEach(definition => validTypes[definition.taskType] = true);
validTypes['shell'] = true;
validTypes['process'] = true;
const contributedTaskSets = await new Promise<ITaskSet[]>(resolve => {
const result: ITaskSet[] = [];
let counter: number = 0;
const done = (value: ITaskSet | undefined) => {
if (value) {
result.push(value);
}
if (--counter === 0) {
resolve(result);
}
};
const error = (error: any) => {
try {
if (error && Types.isString(error.message)) {
this._log(`Error: ${error.message}\n`);
this._showOutput();
} else {
this._log('Unknown error received while collecting tasks from providers.');
this._showOutput();
}
} finally {
if (--counter === 0) {
resolve(result);
}
}
};
if (this._isProvideTasksEnabled() && (this.schemaVersion === JsonSchemaVersion.V2_0_0) && (this._providers.size > 0)) {
let foundAnyProviders = false;
for (const [handle, provider] of this._providers) {
const providerType = this._providerTypes.get(handle);
if ((type === undefined) || (type === providerType)) {
if (providerType && !this._isTaskProviderEnabled(providerType)) {
continue;
}
foundAnyProviders = true;
counter++;
raceTimeout(provider.provideTasks(validTypes).then((taskSet: ITaskSet) => {
// Check that the tasks provided are of the correct type
for (const task of taskSet.tasks) {
if (task.type !== this._providerTypes.get(handle)) {
this._log(nls.localize('unexpectedTaskType', "The task provider for \"{0}\" tasks unexpectedly provided a task of type \"{1}\".\n", this._providerTypes.get(handle), task.type));
if ((task.type !== 'shell') && (task.type !== 'process')) {
this._showOutput();
}
break;
}
}
return done(taskSet);
}, error), 5000, () => {
// onTimeout
console.error('Timed out getting tasks from ', providerType);
done(undefined);
});
}
}
if (!foundAnyProviders) {
resolve(result);
}
} else {
resolve(result);
}
});
const result: TaskMap = new TaskMap();
const contributedTasks: TaskMap = new TaskMap();
for (const set of contributedTaskSets) {
for (const task of set.tasks) {
const workspaceFolder = task.getWorkspaceFolder();
if (workspaceFolder) {
contributedTasks.add(workspaceFolder, task);
}
}
}
try {
const customTasks = await this.getWorkspaceTasks();
const customTasksKeyValuePairs = Array.from(customTasks);
const customTasksPromises = customTasksKeyValuePairs.map(async ([key, folderTasks]) => {
const contributed = contributedTasks.get(key);
if (!folderTasks.set) {
if (contributed) {
result.add(key, ...contributed);
}
return;
}
if (this._contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
result.add(key, ...folderTasks.set.tasks);
} else {
const configurations = folderTasks.configurations;
const legacyTaskConfigurations = folderTasks.set ? this._getLegacyTaskConfigurations(folderTasks.set) : undefined;
const customTasksToDelete: Task[] = [];
if (configurations || legacyTaskConfigurations) {
const unUsedConfigurations: Set<string> = new Set<string>();
if (configurations) {
Object.keys(configurations.byIdentifier).forEach(key => unUsedConfigurations.add(key));
}
for (const task of contributed) {
if (!ContributedTask.is(task)) {
continue;
}
if (configurations) {
const configuringTask = configurations.byIdentifier[task.defines._key];
if (configuringTask) {
unUsedConfigurations.delete(task.defines._key);
result.add(key, TaskConfig.createCustomTask(task, configuringTask));
} else {
result.add(key, task);
}
} else if (legacyTaskConfigurations) {
const configuringTask = legacyTaskConfigurations[task.defines._key];
if (configuringTask) {
result.add(key, TaskConfig.createCustomTask(task, configuringTask));
customTasksToDelete.push(configuringTask);
} else {
result.add(key, task);
}
} else {
result.add(key, task);
}
}
if (customTasksToDelete.length > 0) {
const toDelete = customTasksToDelete.reduce<IStringDictionary<boolean>>((map, task) => {
map[task._id] = true;
return map;
}, Object.create(null));
for (const task of folderTasks.set.tasks) {
if (toDelete[task._id]) {
continue;
}
result.add(key, task);
}
} else {
result.add(key, ...folderTasks.set.tasks);
}
const unUsedConfigurationsAsArray = Array.from(unUsedConfigurations);
const unUsedConfigurationPromises = unUsedConfigurationsAsArray.map(async (value) => {
const configuringTask = configurations!.byIdentifier[value];
if (type && (type !== configuringTask.configures.type)) {
return;
}
let requiredTaskProviderUnavailable: boolean = false;
for (const [handle, provider] of this._providers) {
const providerType = this._providerTypes.get(handle);
if (configuringTask.type === providerType) {
if (providerType && !this._isTaskProviderEnabled(providerType)) {
requiredTaskProviderUnavailable = true;
continue;
}
try {
const resolvedTask = await provider.resolveTask(configuringTask);
if (resolvedTask && (resolvedTask._id === configuringTask._id)) {
result.add(key, TaskConfig.createCustomTask(resolvedTask, configuringTask));
return;
}
} catch (error) {
// Ignore errors. The task could not be provided by any of the providers.
}
}
}
if (requiredTaskProviderUnavailable) {
this._log(nls.localize(
'TaskService.providerUnavailable',
'Warning: {0} tasks are unavailable in the current environment.',
configuringTask.configures.type
));
} else {
this._log(nls.localize(
'TaskService.noConfiguration',
'Error: The {0} task detection didn\'t contribute a task for the following configuration:\n{1}\nThe task will be ignored.',
configuringTask.configures.type,
JSON.stringify(configuringTask._source.config.element, undefined, 4)
));
this._showOutput();
}
});
await Promise.all(unUsedConfigurationPromises);
} else {
result.add(key, ...folderTasks.set.tasks);
result.add(key, ...contributed);
}
}
});
await Promise.all(customTasksPromises);
if (needsRecentTasksMigration) {
// At this point we have all the tasks and can migrate the recently used tasks.
await this._migrateRecentTasks(result.all());
}
return result;
} catch {
// If we can't read the tasks.json file provide at least the contributed tasks
const result: TaskMap = new TaskMap();
for (const set of contributedTaskSets) {
for (const task of set.tasks) {
const folder = task.getWorkspaceFolder();
if (folder) {
result.add(folder, task);
}
}
}
return result;
}
}