Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix task reconnection issues #156699

Merged
merged 7 commits into from
Aug 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 82 additions & 13 deletions src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
// private static autoDetectTelemetryName: string = 'taskServer.autoDetect';
private static readonly RecentlyUsedTasks_Key = 'workbench.tasks.recentlyUsedTasks';
private static readonly RecentlyUsedTasks_KeyV2 = 'workbench.tasks.recentlyUsedTasks2';
private static readonly PersistentTasks_Key = 'workbench.tasks.persistentTasks';
private static readonly IgnoreTask010DonotShowAgain_key = 'workbench.tasks.ignoreTask010Shown';

public _serviceBrand: undefined;
Expand All @@ -218,6 +219,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
private _recentlyUsedTasksV1: LRUCache<string, string> | undefined;
private _recentlyUsedTasks: LRUCache<string, string> | undefined;

private _persistentTasks: LRUCache<string, string> | undefined;

protected _taskRunningState: IContextKey<boolean>;

protected _outputChannel: IOutputChannel;
Expand Down Expand Up @@ -346,11 +349,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}

private async _reconnectTasks(): Promise<void> {
const recentlyUsedTasks = await this.readRecentTasks();
if (!recentlyUsedTasks.length) {
const tasks = await this.getSavedTasks('persistent');
if (!tasks.length) {
return;
}
for (const task of recentlyUsedTasks) {
for (const task of tasks) {
if (ConfiguringTask.is(task)) {
const resolved = await this.tryResolveTask(task);
if (resolved) {
Expand Down Expand Up @@ -889,7 +892,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
return this._recentlyUsedTasksV1;
}

private _getRecentlyUsedTasks(): LRUCache<string, string> {
private _getTasksFromStorage(type: 'persistent' | 'historical'): LRUCache<string, string> {
return type === 'persistent' ? this._getPersistentTasks() : this._getRecentTasks();
}

private _getRecentTasks(): LRUCache<string, string> {
if (this._recentlyUsedTasks) {
return this._recentlyUsedTasks;
}
Expand All @@ -912,21 +919,44 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
return this._recentlyUsedTasks;
}

private _getPersistentTasks(): LRUCache<string, string> {
if (this._persistentTasks) {
return this._persistentTasks;
}
//TODO: should this # be configurable?
this._persistentTasks = new LRUCache<string, string>(10);

const storageValue = this._storageService.get(AbstractTaskService.PersistentTasks_Key, StorageScope.WORKSPACE);
if (storageValue) {
try {
const values: [string, string][] = JSON.parse(storageValue);
if (Array.isArray(values)) {
for (const value of values) {
this._persistentTasks.set(value[0], value[1]);
}
}
} catch (error) {
// Ignore. We use the empty result
}
}
return this._persistentTasks;
}

private _getFolderFromTaskKey(key: string): { folder: string | undefined; isWorkspaceFile: boolean | undefined } {
const keyValue: { folder: string | undefined; id: string | undefined } = JSON.parse(key);
return {
folder: keyValue.folder, isWorkspaceFile: keyValue.id?.endsWith(TaskSourceKind.WorkspaceFile)
};
}

public async readRecentTasks(): Promise<(Task | ConfiguringTask)[]> {
public async getSavedTasks(type: 'persistent' | 'historical'): Promise<(Task | ConfiguringTask)[]> {
const folderMap: IStringDictionary<IWorkspaceFolder> = Object.create(null);
this.workspaceFolders.forEach(folder => {
folderMap[folder.uri.toString()] = folder;
});
const folderToTasksMap: Map<string, any> = new Map();
const workspaceToTaskMap: Map<string, any> = new Map();
const recentlyUsedTasks = this._getRecentlyUsedTasks();
const storedTasks = this._getTasksFromStorage(type);
const tasks: (Task | ConfiguringTask)[] = [];

function addTaskToMap(map: Map<string, any>, folder: string | undefined, task: any) {
Expand All @@ -937,7 +967,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
map.get(folder).push(task);
}
}
for (const entry of recentlyUsedTasks.entries()) {
for (const entry of storedTasks.entries()) {
const key = entry[0];
const task = JSON.parse(entry[1]);
const folderInfo = this._getFolderFromTaskKey(key);
Expand Down Expand Up @@ -974,7 +1004,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
await readTasks(this, folderToTasksMap, false);
await readTasks(this, workspaceToTaskMap, true);
for (const key of recentlyUsedTasks.keys()) {
for (const key of storedTasks.keys()) {
if (readTasksMap.has(key)) {
tasks.push(readTasksMap.get(key)!);
}
Expand All @@ -983,8 +1013,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}

public removeRecentlyUsedTask(taskRecentlyUsedKey: string) {
if (this._getRecentlyUsedTasks().has(taskRecentlyUsedKey)) {
this._getRecentlyUsedTasks().delete(taskRecentlyUsedKey);
if (this._getTasksFromStorage('historical').has(taskRecentlyUsedKey)) {
this._getTasksFromStorage('historical').delete(taskRecentlyUsedKey);
this._saveRecentlyUsedTasks();
}
}
Expand All @@ -1011,7 +1041,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
key = customized[configuration].getRecentlyUsedKey()!;
}
}
this._getRecentlyUsedTasks().set(key, JSON.stringify(customizations));
this._getTasksFromStorage('historical').set(key, JSON.stringify(customizations));
this._saveRecentlyUsedTasks();
}
}
Expand All @@ -1036,6 +1066,41 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this._storageService.store(AbstractTaskService.RecentlyUsedTasks_KeyV2, JSON.stringify(keyValues), StorageScope.WORKSPACE, StorageTarget.USER);
}

private async _setPersistentTask(task: Task): Promise<void> {
if (!task.configurationProperties.isBackground || !this._tasksReconnected) {
return;
}
let key = task.getRecentlyUsedKey();
if (!InMemoryTask.is(task) && key) {
const customizations = this._createCustomizableTask(task);
if (ContributedTask.is(task) && customizations) {
const custom: CustomTask[] = [];
const customized: IStringDictionary<ConfiguringTask> = Object.create(null);
await this._computeTasksForSingleConfig(task._source.workspaceFolder ?? this.workspaceFolders[0], {
version: '2.0.0',
tasks: [customizations]
}, TaskRunSource.System, custom, customized, TaskConfig.TaskConfigSource.TasksJson, true);
for (const configuration in customized) {
key = customized[configuration].getRecentlyUsedKey()!;
}
}
this._getTasksFromStorage('persistent').set(key, JSON.stringify(customizations));
this._savePersistentTasks();
}
}

private _savePersistentTasks(): void {
if (!this._persistentTasks) {
return;
}
const keys = [...this._persistentTasks.keys()];
const keyValues: [string, string][] = [];
for (const key of keys) {
keyValues.push([key, this._persistentTasks.get(key, Touch.None)!]);
}
this._storageService.store(AbstractTaskService.PersistentTasks_Key, JSON.stringify(keyValues), StorageScope.WORKSPACE, StorageTarget.USER);
}

private _openDocumentation(): void {
this._openerService.open(URI.parse('https://code.visualstudio.com/docs/editor/tasks#_defining-a-problem-matcher'));
}
Expand Down Expand Up @@ -1776,6 +1841,9 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}

private async _handleExecuteResult(executeResult: ITaskExecuteResult, runSource?: TaskRunSource): Promise<ITaskSummary> {
if (this._configurationService.getValue(TaskSettingId.Reconnection) === true) {
await this._setPersistentTask(executeResult.task);
}
if (runSource === TaskRunSource.User) {
await this._setRecentlyUsedTask(executeResult.task);
}
Expand Down Expand Up @@ -1804,6 +1872,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}
}
this._setRecentlyUsedTask(executeResult.task);
this._setPersistentTask(executeResult.task);
return executeResult.promise;
}

Expand Down Expand Up @@ -2514,7 +2583,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
if (tasks.length === 1) {
entries.push(TaskQuickPickEntry(tasks[0]));
} else {
const recentlyUsedTasks = await this.readRecentTasks();
const recentlyUsedTasks = await this.getSavedTasks('historical');
const recent: Task[] = [];
const recentSet: Set<string> = new Set();
let configured: Task[] = [];
Expand Down Expand Up @@ -2647,7 +2716,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}

private _needsRecentTasksMigration(): boolean {
return (this.getRecentlyUsedTasksV1().size > 0) && (this._getRecentlyUsedTasks().size === 0);
return (this.getRecentlyUsedTasksV1().size > 0) && (this._getTasksFromStorage('historical').size === 0);
}

private async _migrateRecentTasks(tasks: Task[]) {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ export class TaskQuickPick extends Disposable {
if (this._topLevelEntries !== undefined) {
return { entries: this._topLevelEntries };
}
let recentTasks: (Task | ConfiguringTask)[] = (await this._taskService.readRecentTasks()).reverse();
let recentTasks: (Task | ConfiguringTask)[] = (await this._taskService.getSavedTasks('historical')).reverse();
const configuredTasks: (Task | ConfiguringTask)[] = this._handleFolderTaskResult(await this._taskService.getWorkspaceTasks());
const extensionTaskTypes = this._taskService.taskTypes();
this._topLevelEntries = [];
Expand Down
Loading