|
|
|
@ -150,7 +150,7 @@ class TaskMap {
|
|
|
|
|
this._store.forEach(callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private getKey(workspaceFolder: IWorkspace | IWorkspaceFolder | string): string {
|
|
|
|
|
public static getKey(workspaceFolder: IWorkspace | IWorkspaceFolder | string): string {
|
|
|
|
|
let key: string | undefined;
|
|
|
|
|
if (Types.isString(workspaceFolder)) {
|
|
|
|
|
key = workspaceFolder;
|
|
|
|
@ -162,7 +162,7 @@ class TaskMap {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public get(workspaceFolder: IWorkspace | IWorkspaceFolder | string): Task[] {
|
|
|
|
|
const key = this.getKey(workspaceFolder);
|
|
|
|
|
const key = TaskMap.getKey(workspaceFolder);
|
|
|
|
|
let result: Task[] | undefined = this._store.get(key);
|
|
|
|
|
if (!result) {
|
|
|
|
|
result = [];
|
|
|
|
@ -172,7 +172,7 @@ class TaskMap {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public add(workspaceFolder: IWorkspace | IWorkspaceFolder | string, ...task: Task[]): void {
|
|
|
|
|
const key = this.getKey(workspaceFolder);
|
|
|
|
|
const key = TaskMap.getKey(workspaceFolder);
|
|
|
|
|
let values = this._store.get(key);
|
|
|
|
|
if (!values) {
|
|
|
|
|
values = [];
|
|
|
|
@ -493,6 +493,31 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
return this._showIgnoreMessage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private _getActivationEvents(type: string | undefined): string[] {
|
|
|
|
|
const result: string[] = [];
|
|
|
|
|
result.push('onCommand:workbench.action.tasks.runTask');
|
|
|
|
|
if (type) {
|
|
|
|
|
// send a specific activation event for this task type
|
|
|
|
|
result.push(`onTaskType:${type}`);
|
|
|
|
|
} else {
|
|
|
|
|
// send activation events for all task types
|
|
|
|
|
for (const definition of TaskDefinitionRegistry.all()) {
|
|
|
|
|
result.push(`onTaskType:${definition.taskType}`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async _activateTaskProviders(type: string | undefined): Promise<void> {
|
|
|
|
|
// We need to first wait for extensions to be registered because we might read
|
|
|
|
|
// the `TaskDefinitionRegistry` in case `type` is `undefined`
|
|
|
|
|
await this.extensionService.whenInstalledExtensionsRegistered();
|
|
|
|
|
|
|
|
|
|
await Promise.all(
|
|
|
|
|
this._getActivationEvents(type).map(activationEvent => this.extensionService.activateByEvent(activationEvent))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined]): void {
|
|
|
|
|
if (!setup) {
|
|
|
|
|
setup = this.computeWorkspaceFolderSetup();
|
|
|
|
@ -575,6 +600,44 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
return this._taskSystem.customExecutionComplete(task, result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get a subset of workspace tasks that match a certain predicate.
|
|
|
|
|
*/
|
|
|
|
|
private async _findWorkspaceTasks(predicate: (task: ConfiguringTask | Task, workspaceFolder: IWorkspaceFolder) => boolean): Promise<(ConfiguringTask | Task)[]> {
|
|
|
|
|
const result: (ConfiguringTask | Task)[] = [];
|
|
|
|
|
|
|
|
|
|
const tasks = await this.getWorkspaceTasks();
|
|
|
|
|
for (const [, workspaceTasks] of tasks) {
|
|
|
|
|
if (workspaceTasks.configurations) {
|
|
|
|
|
for (const taskName in workspaceTasks.configurations.byIdentifier) {
|
|
|
|
|
const task = workspaceTasks.configurations.byIdentifier[taskName];
|
|
|
|
|
if (predicate(task, workspaceTasks.workspaceFolder)) {
|
|
|
|
|
result.push(task);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (workspaceTasks.set) {
|
|
|
|
|
for (const task of workspaceTasks.set.tasks) {
|
|
|
|
|
if (predicate(task, workspaceTasks.workspaceFolder)) {
|
|
|
|
|
result.push(task);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private async _findWorkspaceTasksInGroup(group: TaskGroup): Promise<(ConfiguringTask | Task)[]> {
|
|
|
|
|
return this._findWorkspaceTasks((task) => {
|
|
|
|
|
const taskGroup = task.configurationProperties.group;
|
|
|
|
|
if (taskGroup && typeof taskGroup !== 'string') {
|
|
|
|
|
return (taskGroup._id === group._id && !!taskGroup.isDefault);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async getTask(folder: IWorkspace | IWorkspaceFolder | string, identifier: string | TaskIdentifier, compareId: boolean = false): Promise<Task | undefined> {
|
|
|
|
|
if (!(await this.trust())) {
|
|
|
|
|
return;
|
|
|
|
@ -590,6 +653,28 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
if (key === undefined) {
|
|
|
|
|
return Promise.resolve(undefined);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Try to find the task in the workspace
|
|
|
|
|
const requestedFolder = TaskMap.getKey(folder);
|
|
|
|
|
const matchedTasks = await this._findWorkspaceTasks((task, workspaceFolder) => {
|
|
|
|
|
const taskFolder = TaskMap.getKey(workspaceFolder);
|
|
|
|
|
if (taskFolder !== requestedFolder || taskFolder !== USER_TASKS_GROUP_KEY) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return task.matches(key, compareId);
|
|
|
|
|
});
|
|
|
|
|
matchedTasks.sort(task => task._source.kind === TaskSourceKind.Extension ? 1 : -1);
|
|
|
|
|
if (matchedTasks.length > 0) {
|
|
|
|
|
// Nice, we found a configured task!
|
|
|
|
|
const task = matchedTasks[0];
|
|
|
|
|
if (ConfiguringTask.is(task)) {
|
|
|
|
|
return this.tryResolveTask(task);
|
|
|
|
|
} else {
|
|
|
|
|
return task;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We didn't find the task, so we need to ask all resolvers about it
|
|
|
|
|
return this.getGroupedTasks().then((map) => {
|
|
|
|
|
let values = map.get(folder);
|
|
|
|
|
values = values.concat(map.get(USER_TASKS_GROUP_KEY));
|
|
|
|
@ -606,7 +691,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
if (!(await this.trust())) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
await Promise.all([this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask'), this.extensionService.whenInstalledExtensionsRegistered()]);
|
|
|
|
|
await this._activateTaskProviders(configuringTask.type);
|
|
|
|
|
let matchingProvider: ITaskProvider | undefined;
|
|
|
|
|
let matchingProviderUnavailable: boolean = false;
|
|
|
|
|
for (const [handle, provider] of this._providers) {
|
|
|
|
@ -690,10 +775,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
public taskTypes(): string[] {
|
|
|
|
|
const types: string[] = [];
|
|
|
|
|
if (this.isProvideTasksEnabled()) {
|
|
|
|
|
for (const [handle] of this._providers) {
|
|
|
|
|
const type = this._providerTypes.get(handle);
|
|
|
|
|
if (type && this.isTaskProviderEnabled(type)) {
|
|
|
|
|
types.push(type);
|
|
|
|
|
for (const definition of TaskDefinitionRegistry.all()) {
|
|
|
|
|
if (this.isTaskProviderEnabled(definition.taskType)) {
|
|
|
|
|
types.push(definition.taskType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -900,7 +984,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
this.openerService.open(URI.parse('https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher'));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private build(): Promise<ITaskSummary> {
|
|
|
|
|
private async build(): Promise<ITaskSummary> {
|
|
|
|
|
const buildTasks = await this._findWorkspaceTasksInGroup(TaskGroup.Build);
|
|
|
|
|
if (buildTasks.length > 0) {
|
|
|
|
|
// TODO: If a task was found, execute it and return early
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.getGroupedTasks().then((tasks) => {
|
|
|
|
|
let runnable = this.createRunnableTask(tasks, TaskGroup.Build);
|
|
|
|
|
if (!runnable || !runnable.task) {
|
|
|
|
@ -917,7 +1006,12 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private runTest(): Promise<ITaskSummary> {
|
|
|
|
|
private async runTest(): Promise<ITaskSummary> {
|
|
|
|
|
const cleanTasks = await this._findWorkspaceTasksInGroup(TaskGroup.Test);
|
|
|
|
|
if (cleanTasks.length > 0) {
|
|
|
|
|
// TODO: If a task was found, execute it and return early
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this.getGroupedTasks().then((tasks) => {
|
|
|
|
|
let runnable = this.createRunnableTask(tasks, TaskGroup.Test);
|
|
|
|
|
if (!runnable || !runnable.task) {
|
|
|
|
@ -1683,7 +1777,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
|
|
|
|
|
private getGroupedTasks(type?: string): Promise<TaskMap> {
|
|
|
|
|
const needsRecentTasksMigration = this.needsRecentTasksMigration();
|
|
|
|
|
return Promise.all([this.extensionService.activateByEvent('onCommand:workbench.action.tasks.runTask'), this.extensionService.whenInstalledExtensionsRegistered()]).then(() => {
|
|
|
|
|
return this._activateTaskProviders(type).then(() => {
|
|
|
|
|
let validTypes: IStringDictionary<boolean> = Object.create(null);
|
|
|
|
|
TaskDefinitionRegistry.all().forEach(definition => validTypes[definition.taskType] = true);
|
|
|
|
|
validTypes['shell'] = true;
|
|
|
|
@ -2647,30 +2741,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
location: ProgressLocation.Window,
|
|
|
|
|
title: nls.localize('TaskService.fetchingBuildTasks', 'Fetching build tasks...')
|
|
|
|
|
};
|
|
|
|
|
let promise = this.getWorkspaceTasks().then(tasks => {
|
|
|
|
|
const buildTasks: (ConfiguringTask | Task)[] = [];
|
|
|
|
|
for (const taskSource of tasks) {
|
|
|
|
|
for (const task in taskSource[1].configurations?.byIdentifier) {
|
|
|
|
|
if (taskSource[1].configurations) {
|
|
|
|
|
const taskGroup: TaskGroup = taskSource[1].configurations.byIdentifier[task].configurationProperties.group as TaskGroup;
|
|
|
|
|
|
|
|
|
|
if (taskGroup && taskGroup._id === TaskGroup.Build._id && taskGroup.isDefault) {
|
|
|
|
|
buildTasks.push(taskSource[1].configurations.byIdentifier[task]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (taskSource[1].set) {
|
|
|
|
|
for (const task of taskSource[1].set?.tasks) {
|
|
|
|
|
const taskGroup: TaskGroup = task.configurationProperties.group as TaskGroup;
|
|
|
|
|
if (taskGroup && taskGroup._id === TaskGroup.Build._id && taskGroup.isDefault) {
|
|
|
|
|
buildTasks.push(task);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (buildTasks.length > 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
let promise = (async () => {
|
|
|
|
|
const buildTasks = await this._findWorkspaceTasksInGroup(TaskGroup.Build);
|
|
|
|
|
|
|
|
|
|
async function runSingleBuildTask(task: Task | undefined, problemMatcherOptions: ProblemMatcherRunOptions | undefined, that: AbstractTaskService) {
|
|
|
|
|
that.run(task, problemMatcherOptions, TaskRunSource.User).then(undefined, reason => {
|
|
|
|
@ -2720,7 +2792,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
})();
|
|
|
|
|
this.progressService.withProgress(options, () => promise);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|