Skip to content
Open
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
4 changes: 2 additions & 2 deletions src/vs/workbench/api/browser/mainThreadTask.ts
Original file line number Diff line number Diff line change
Expand Up @@ -732,7 +732,7 @@ export class MainThreadTask extends Disposable implements MainThreadTaskShape {
default:
platform = Platform.platform;
}
this._taskService.registerTaskSystem(key, {
this._register(this._taskService.registerTaskSystem(key, {
platform: platform,
uriProvider: (path: string): URI => {
return URI.from({ scheme: info.scheme, authority: info.authority, path });
Expand Down Expand Up @@ -777,7 +777,7 @@ export class MainThreadTask extends Disposable implements MainThreadTaskShape {
findExecutable: (command: string, cwd?: string, paths?: string[]): Promise<string | undefined> => {
return this._proxy.$findExecutable(command, cwd, paths);
}
});
}));
}

async $registerSupportedExecutions(custom?: boolean, shell?: boolean, process?: boolean): Promise<void> {
Expand Down
38 changes: 38 additions & 0 deletions src/vs/workbench/api/test/browser/mainThreadTask.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as assert from 'assert';
import { Event } from '../../../../base/common/event.js';
import { IDisposable, toDisposable } from '../../../../base/common/lifecycle.js';
import { mock } from '../../../../base/test/common/mock.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../base/test/common/utils.js';
import { ITaskService } from '../../../contrib/tasks/common/taskService.js';
import { MainThreadTask } from '../../browser/mainThreadTask.js';
import { SingleProxyRPCProtocol } from '../common/testRPCProtocol.js';

suite('MainThreadTask', function () {

ensureNoDisposablesAreLeakedInTestSuite();

test('unregisters task systems on dispose', function () {
let registrations = 0;
let disposals = 0;
const taskService = new class extends mock<ITaskService>() {
override readonly onDidStateChange = Event.None;

override registerTaskSystem(): IDisposable {
registrations++;
return toDisposable(() => disposals++);
}
};
const mainThreadTask = new MainThreadTask(SingleProxyRPCProtocol(null), taskService, undefined!, undefined!);

mainThreadTask.$registerTaskSystem('file', { scheme: 'file', authority: '', platform: 'linux' });
assert.strictEqual(registrations, 1);

mainThreadTask.dispose();
assert.strictEqual(disposals, 1);
});
});
20 changes: 18 additions & 2 deletions src/vs/workbench/contrib/tasks/browser/abstractTaskService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -878,8 +878,8 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
return infosCount > 0;
}

public registerTaskSystem(key: string, info: ITaskSystemInfo): void {
// Ideally the Web caller of registerRegisterTaskSystem would use the correct key.
public registerTaskSystem(key: string, info: ITaskSystemInfo): IDisposable {
// Ideally the Web caller of registerTaskSystem would use the correct key.
// However, the caller doesn't know about the workspace folders at the time of the call, even though we know about them here.
if (info.platform === Platform.Platform.Web) {
key = this.workspaceFolders.length ? this.workspaceFolders[0].uri.scheme : key;
Expand All @@ -899,6 +899,22 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
if (this.hasTaskSystemInfo) {
this._onDidChangeTaskSystemInfo.fire();
}

return toDisposable(() => {
const infos = this._taskSystemInfos.get(key);
if (!infos) {
return;
}
const index = infos.indexOf(info);
if (index === -1) {
return;
}
infos.splice(index, 1);
if (infos.length === 0) {
this._taskSystemInfos.delete(key);
}
this._onDidChangeTaskSystemInfo.fire();
});
}

private _getTaskSystemInfo(key: string): ITaskSystemInfo | undefined {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/contrib/tasks/common/taskService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export interface ITaskService {

registerTaskProvider(taskProvider: ITaskProvider, type: string): IDisposable;

registerTaskSystem(scheme: string, taskSystemInfo: ITaskSystemInfo): void;
registerTaskSystem(scheme: string, taskSystemInfo: ITaskSystemInfo): IDisposable;
readonly onDidChangeTaskSystemInfo: Event<void>;
readonly onDidChangeTaskConfig: Event<void>;
readonly hasTaskSystemInfo: boolean;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as assert from 'assert';
import { Emitter } from '../../../../../base/common/event.js';
import * as Platform from '../../../../../base/common/platform.js';
import { URI } from '../../../../../base/common/uri.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
import { AbstractTaskService } from '../../browser/abstractTaskService.js';
import { ITaskSystemInfo } from '../../common/taskSystem.js';

suite('AbstractTaskService', function () {

const store = ensureNoDisposablesAreLeakedInTestSuite();

test('removes task system info and emits a change when disposed', function () {
const taskSystemInfoEmitter = store.add(new Emitter<void>());
const taskService = Object.create(AbstractTaskService.prototype) as AbstractTaskService;
Reflect.set(taskService, '_taskSystemInfos', new Map<string, ITaskSystemInfo[]>());
Reflect.set(taskService, '_environmentService', { remoteAuthority: undefined });
Reflect.set(taskService, '_onDidChangeTaskSystemInfo', taskSystemInfoEmitter);
Reflect.set(taskService, 'onDidChangeTaskSystemInfo', taskSystemInfoEmitter.event);

const states: boolean[] = [];
store.add(taskService.onDidChangeTaskSystemInfo(() => states.push(taskService.hasTaskSystemInfo)));
const registration = store.add(taskService.registerTaskSystem('file', {
platform: Platform.Platform.Linux,
context: undefined,
uriProvider: path => URI.file(path),
resolveVariables: async () => undefined,
findExecutable: async () => undefined
}));

registration.dispose();

assert.deepStrictEqual(states, [true, false]);
});
});