提交 b6089b1d 编写于 作者: J Joel Day 提交者: Alex Ross

Adding support for TaskProvider.resolveTask (#71027)

* Adding support for TaskProvider.resolveTask.

* Reorganize task grouping and resolution async code for readability.

* Made small changes and implmented resolveTask for gulp
上级 9b28638e
...@@ -67,6 +67,24 @@ function showError() { ...@@ -67,6 +67,24 @@ function showError() {
}); });
} }
async function findGulpCommand(rootPath: string): Promise<string> {
let gulpCommand: string;
let platform = process.platform;
if (platform === 'win32' && await exists(path.join(rootPath, 'node_modules', '.bin', 'gulp.cmd'))) {
const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm', 'gulp.cmd');
if (await exists(globalGulp)) {
gulpCommand = '"' + globalGulp + '"';
} else {
gulpCommand = path.join('.', 'node_modules', '.bin', 'gulp.cmd');
}
} else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(rootPath, 'node_modules', '.bin', 'gulp'))) {
gulpCommand = path.join('.', 'node_modules', '.bin', 'gulp');
} else {
gulpCommand = 'gulp';
}
return gulpCommand;
}
interface GulpTaskDefinition extends vscode.TaskDefinition { interface GulpTaskDefinition extends vscode.TaskDefinition {
task: string; task: string;
file?: string; file?: string;
...@@ -77,7 +95,9 @@ class FolderDetector { ...@@ -77,7 +95,9 @@ class FolderDetector {
private fileWatcher: vscode.FileSystemWatcher | undefined; private fileWatcher: vscode.FileSystemWatcher | undefined;
private promise: Thenable<vscode.Task[]> | undefined; private promise: Thenable<vscode.Task[]> | undefined;
constructor(private _workspaceFolder: vscode.WorkspaceFolder) { constructor(
private _workspaceFolder: vscode.WorkspaceFolder,
private _gulpCommand: Promise<string>) {
} }
public get workspaceFolder(): vscode.WorkspaceFolder { public get workspaceFolder(): vscode.WorkspaceFolder {
...@@ -97,10 +117,28 @@ class FolderDetector { ...@@ -97,10 +117,28 @@ class FolderDetector {
} }
public async getTasks(): Promise<vscode.Task[]> { public async getTasks(): Promise<vscode.Task[]> {
if (!this.promise) { if (this.isEnabled()) {
this.promise = this.computeTasks(); if (!this.promise) {
this.promise = this.computeTasks();
}
return this.promise;
} else {
return [];
}
}
public async getTask(_task: vscode.Task): Promise<vscode.Task | undefined> {
const gulpTask = (<any>_task.definition).task;
if (gulpTask) {
let kind: GulpTaskDefinition = {
type: 'gulp',
task: gulpTask
};
let options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath };
let task = new vscode.Task(kind, this.workspaceFolder, gulpTask, 'gulp', new vscode.ShellExecution(await this._gulpCommand, [gulpTask], options));
return task;
} }
return this.promise; return undefined;
} }
private async computeTasks(): Promise<vscode.Task[]> { private async computeTasks(): Promise<vscode.Task[]> {
...@@ -117,22 +155,7 @@ class FolderDetector { ...@@ -117,22 +155,7 @@ class FolderDetector {
} }
} }
let gulpCommand: string; let commandLine = `${await this._gulpCommand} --tasks-simple --no-color`;
let platform = process.platform;
if (platform === 'win32' && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp.cmd'))) {
const globalGulp = path.join(process.env.APPDATA ? process.env.APPDATA : '', 'npm', 'gulp.cmd');
if (await exists(globalGulp)) {
gulpCommand = '"' + globalGulp + '"';
} else {
gulpCommand = path.join('.', 'node_modules', '.bin', 'gulp.cmd');
}
} else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(rootPath!, 'node_modules', '.bin', 'gulp'))) {
gulpCommand = path.join('.', 'node_modules', '.bin', 'gulp');
} else {
gulpCommand = 'gulp';
}
let commandLine = `${gulpCommand} --tasks-simple --no-color`;
try { try {
let { stdout, stderr } = await exec(commandLine, { cwd: rootPath }); let { stdout, stderr } = await exec(commandLine, { cwd: rootPath });
if (stderr && stderr.length > 0) { if (stderr && stderr.length > 0) {
...@@ -151,7 +174,7 @@ class FolderDetector { ...@@ -151,7 +174,7 @@ class FolderDetector {
task: line task: line
}; };
let options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath }; let options: vscode.ShellExecutionOptions = { cwd: this.workspaceFolder.uri.fsPath };
let task = new vscode.Task(kind, this.workspaceFolder, line, 'gulp', new vscode.ShellExecution(gulpCommand, [line], options)); let task = new vscode.Task(kind, this.workspaceFolder, line, 'gulp', new vscode.ShellExecution(await this._gulpCommand, [line], options));
result.push(task); result.push(task);
let lowerCaseLine = line.toLowerCase(); let lowerCaseLine = line.toLowerCase();
if (isBuildTask(lowerCaseLine)) { if (isBuildTask(lowerCaseLine)) {
...@@ -218,9 +241,9 @@ class TaskDetector { ...@@ -218,9 +241,9 @@ class TaskDetector {
} }
} }
for (let add of added) { for (let add of added) {
let detector = new FolderDetector(add); let detector = new FolderDetector(add, findGulpCommand(add.uri.fsPath));
this.detectors.set(add.uri.toString(), detector);
if (detector.isEnabled()) { if (detector.isEnabled()) {
this.detectors.set(add.uri.toString(), detector);
detector.start(); detector.start();
} }
} }
...@@ -229,18 +252,16 @@ class TaskDetector { ...@@ -229,18 +252,16 @@ class TaskDetector {
private updateConfiguration(): void { private updateConfiguration(): void {
for (let detector of this.detectors.values()) { for (let detector of this.detectors.values()) {
if (!detector.isEnabled()) { detector.dispose();
detector.dispose(); this.detectors.delete(detector.workspaceFolder.uri.toString());
this.detectors.delete(detector.workspaceFolder.uri.toString());
}
} }
let folders = vscode.workspace.workspaceFolders; let folders = vscode.workspace.workspaceFolders;
if (folders) { if (folders) {
for (let folder of folders) { for (let folder of folders) {
if (!this.detectors.has(folder.uri.toString())) { if (!this.detectors.has(folder.uri.toString())) {
let detector = new FolderDetector(folder); let detector = new FolderDetector(folder, findGulpCommand(folder.uri.fsPath));
this.detectors.set(folder.uri.toString(), detector);
if (detector.isEnabled()) { if (detector.isEnabled()) {
this.detectors.set(folder.uri.toString(), detector);
detector.start(); detector.start();
} }
} }
...@@ -251,12 +272,13 @@ class TaskDetector { ...@@ -251,12 +272,13 @@ class TaskDetector {
private updateProvider(): void { private updateProvider(): void {
if (!this.taskProvider && this.detectors.size > 0) { if (!this.taskProvider && this.detectors.size > 0) {
const thisCapture = this;
this.taskProvider = vscode.workspace.registerTaskProvider('gulp', { this.taskProvider = vscode.workspace.registerTaskProvider('gulp', {
provideTasks: () => { provideTasks(): Promise<vscode.Task[]> {
return this.getTasks(); return thisCapture.getTasks();
}, },
resolveTask(_task: vscode.Task): vscode.Task | undefined { resolveTask(_task: vscode.Task): Promise<vscode.Task | undefined> {
return undefined; return thisCapture.getTask(_task);
} }
}); });
} }
...@@ -291,6 +313,25 @@ class TaskDetector { ...@@ -291,6 +313,25 @@ class TaskDetector {
}); });
} }
} }
public async getTask(task: vscode.Task): Promise<vscode.Task | undefined> {
if (this.detectors.size === 0) {
return undefined;
} else if (this.detectors.size === 1) {
return this.detectors.values().next().value.getTask(task);
} else {
if ((task.scope === vscode.TaskScope.Workspace) || (task.scope === vscode.TaskScope.Global)) {
// Not supported, we don't have enough info to create the task.
return undefined;
} else if (task.scope) {
const detector = this.detectors.get(task.scope.uri.toString());
if (detector) {
return detector.getTask(task);
}
}
return undefined;
}
}
} }
let detector: TaskDetector; let detector: TaskDetector;
......
...@@ -16,7 +16,7 @@ import { IDisposable } from 'vs/base/common/lifecycle'; ...@@ -16,7 +16,7 @@ import { IDisposable } from 'vs/base/common/lifecycle';
import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { import {
ContributedTask, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind, ContributedTask, ConfiguringTask, KeyedTaskIdentifier, TaskExecution, Task, TaskEvent, TaskEventKind,
PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource, PresentationOptions, CommandOptions, CommandConfiguration, RuntimeType, CustomTask, TaskScope, TaskSource,
TaskSourceKind, ExtensionTaskSource, RunOptions, TaskSet, TaskDefinition TaskSourceKind, ExtensionTaskSource, RunOptions, TaskSet, TaskDefinition
} from 'vs/workbench/contrib/tasks/common/tasks'; } from 'vs/workbench/contrib/tasks/common/tasks';
...@@ -304,8 +304,8 @@ namespace TaskHandleDTO { ...@@ -304,8 +304,8 @@ namespace TaskHandleDTO {
} }
namespace TaskDTO { namespace TaskDTO {
export function from(task: Task): TaskDTO | undefined { export function from(task: Task | ConfiguringTask): TaskDTO | undefined {
if (task === undefined || task === null || (!CustomTask.is(task) && !ContributedTask.is(task))) { if (task === undefined || task === null || (!CustomTask.is(task) && !ContributedTask.is(task) && !ConfiguringTask.is(task))) {
return undefined; return undefined;
} }
const result: TaskDTO = { const result: TaskDTO = {
...@@ -314,7 +314,7 @@ namespace TaskDTO { ...@@ -314,7 +314,7 @@ namespace TaskDTO {
definition: TaskDefinitionDTO.from(task.getDefinition()), definition: TaskDefinitionDTO.from(task.getDefinition()),
source: TaskSourceDTO.from(task._source), source: TaskSourceDTO.from(task._source),
execution: undefined, execution: undefined,
presentationOptions: task.command ? TaskPresentationOptionsDTO.from(task.command.presentation) : undefined, presentationOptions: !ConfiguringTask.is(task) && task.command ? TaskPresentationOptionsDTO.from(task.command.presentation) : undefined,
isBackground: task.configurationProperties.isBackground, isBackground: task.configurationProperties.isBackground,
problemMatchers: [], problemMatchers: [],
hasDefinedMatchers: ContributedTask.is(task) ? task.hasDefinedMatchers : false, hasDefinedMatchers: ContributedTask.is(task) ? task.hasDefinedMatchers : false,
...@@ -323,7 +323,7 @@ namespace TaskDTO { ...@@ -323,7 +323,7 @@ namespace TaskDTO {
if (task.configurationProperties.group) { if (task.configurationProperties.group) {
result.group = task.configurationProperties.group; result.group = task.configurationProperties.group;
} }
if (task.command) { if (!ConfiguringTask.is(task) && task.command) {
if (task.command.runtime === RuntimeType.Process) { if (task.command.runtime === RuntimeType.Process) {
result.execution = ProcessExecutionDTO.from(task.command); result.execution = ProcessExecutionDTO.from(task.command);
} else if (task.command.runtime === RuntimeType.Shell) { } else if (task.command.runtime === RuntimeType.Shell) {
...@@ -442,7 +442,7 @@ export class MainThreadTask implements MainThreadTaskShape { ...@@ -442,7 +442,7 @@ export class MainThreadTask implements MainThreadTaskShape {
}); });
} }
public $registerTaskProvider(handle: number): Promise<void> { public $registerTaskProvider(handle: number, type: string): Promise<void> {
const provider: ITaskProvider = { const provider: ITaskProvider = {
provideTasks: (validTypes: IStringDictionary<boolean>) => { provideTasks: (validTypes: IStringDictionary<boolean>) => {
return Promise.resolve(this._proxy.$provideTasks(handle, validTypes)).then((value) => { return Promise.resolve(this._proxy.$provideTasks(handle, validTypes)).then((value) => {
...@@ -460,9 +460,24 @@ export class MainThreadTask implements MainThreadTaskShape { ...@@ -460,9 +460,24 @@ export class MainThreadTask implements MainThreadTaskShape {
extension: value.extension extension: value.extension
} as TaskSet; } as TaskSet;
}); });
},
resolveTask: (task: ConfiguringTask) => {
const dto = TaskDTO.from(task);
if (dto) {
dto.name = ((dto.name === undefined) ? '' : dto.name); // Using an empty name causes the name to default to the one given by the provider.
return Promise.resolve(this._proxy.$resolveTask(handle, dto)).then(resolvedTask => {
if (resolvedTask) {
return TaskDTO.to(resolvedTask, this._workspaceContextServer, true);
}
return undefined;
});
}
return Promise.resolve<ContributedTask | undefined>(undefined);
} }
}; };
const disposable = this._taskService.registerTaskProvider(provider); const disposable = this._taskService.registerTaskProvider(provider, type);
this._providers.set(handle, { disposable, provider }); this._providers.set(handle, { disposable, provider });
return Promise.resolve(undefined); return Promise.resolve(undefined);
} }
......
...@@ -635,7 +635,7 @@ export interface MainThreadSearchShape extends IDisposable { ...@@ -635,7 +635,7 @@ export interface MainThreadSearchShape extends IDisposable {
export interface MainThreadTaskShape extends IDisposable { export interface MainThreadTaskShape extends IDisposable {
$createTaskId(task: tasks.TaskDTO): Promise<string>; $createTaskId(task: tasks.TaskDTO): Promise<string>;
$registerTaskProvider(handle: number): Promise<void>; $registerTaskProvider(handle: number, type: string): Promise<void>;
$unregisterTaskProvider(handle: number): Promise<void>; $unregisterTaskProvider(handle: number): Promise<void>;
$fetchTasks(filter?: tasks.TaskFilterDTO): Promise<tasks.TaskDTO[]>; $fetchTasks(filter?: tasks.TaskFilterDTO): Promise<tasks.TaskDTO[]>;
$executeTask(task: tasks.TaskHandleDTO | tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>; $executeTask(task: tasks.TaskHandleDTO | tasks.TaskDTO): Promise<tasks.TaskExecutionDTO>;
...@@ -1183,6 +1183,7 @@ export interface ExtHostSCMShape { ...@@ -1183,6 +1183,7 @@ export interface ExtHostSCMShape {
export interface ExtHostTaskShape { export interface ExtHostTaskShape {
$provideTasks(handle: number, validTypes: { [key: string]: boolean; }): Thenable<tasks.TaskSetDTO>; $provideTasks(handle: number, validTypes: { [key: string]: boolean; }): Thenable<tasks.TaskSetDTO>;
$resolveTask(handle: number, taskDTO: tasks.TaskDTO): Thenable<tasks.TaskDTO | undefined>;
$onDidStartTask(execution: tasks.TaskExecutionDTO, terminalId: number): void; $onDidStartTask(execution: tasks.TaskExecutionDTO, terminalId: number): void;
$onDidStartTaskProcess(value: tasks.TaskProcessStartedDTO): void; $onDidStartTaskProcess(value: tasks.TaskProcessStartedDTO): void;
$onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void; $onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void;
......
...@@ -675,7 +675,7 @@ export function createApiFactory( ...@@ -675,7 +675,7 @@ export function createApiFactory(
return extHostDocumentContentProviders.registerTextDocumentContentProvider(scheme, provider); return extHostDocumentContentProviders.registerTextDocumentContentProvider(scheme, provider);
}, },
registerTaskProvider: (type: string, provider: vscode.TaskProvider) => { registerTaskProvider: (type: string, provider: vscode.TaskProvider) => {
return extHostTask.registerTaskProvider(extension, provider); return extHostTask.registerTaskProvider(extension, type, provider);
}, },
registerFileSystemProvider(scheme, provider, options) { registerFileSystemProvider(scheme, provider, options) {
return extHostFileSystem.registerFileSystemProvider(scheme, provider, options); return extHostFileSystem.registerFileSystemProvider(scheme, provider, options);
...@@ -776,7 +776,7 @@ export function createApiFactory( ...@@ -776,7 +776,7 @@ export function createApiFactory(
const tasks: typeof vscode.tasks = { const tasks: typeof vscode.tasks = {
registerTaskProvider: (type: string, provider: vscode.TaskProvider) => { registerTaskProvider: (type: string, provider: vscode.TaskProvider) => {
return extHostTask.registerTaskProvider(extension, provider); return extHostTask.registerTaskProvider(extension, type, provider);
}, },
fetchTasks: (filter?: vscode.TaskFilter): Thenable<vscode.Task[]> => { fetchTasks: (filter?: vscode.TaskFilter): Thenable<vscode.Task[]> => {
return extHostTask.fetchTasks(filter); return extHostTask.fetchTasks(filter);
......
...@@ -347,6 +347,7 @@ namespace TaskExecutionDTO { ...@@ -347,6 +347,7 @@ namespace TaskExecutionDTO {
} }
interface HandlerData { interface HandlerData {
type: string;
provider: vscode.TaskProvider; provider: vscode.TaskProvider;
extension: IExtensionDescription; extension: IExtensionDescription;
} }
...@@ -492,13 +493,13 @@ export class ExtHostTask implements ExtHostTaskShape { ...@@ -492,13 +493,13 @@ export class ExtHostTask implements ExtHostTaskShape {
this._activeCustomExecutions = new Map<string, CustomExecutionData>(); this._activeCustomExecutions = new Map<string, CustomExecutionData>();
} }
public registerTaskProvider(extension: IExtensionDescription, provider: vscode.TaskProvider): vscode.Disposable { public registerTaskProvider(extension: IExtensionDescription, type: string, provider: vscode.TaskProvider): vscode.Disposable {
if (!provider) { if (!provider) {
return new types.Disposable(() => { }); return new types.Disposable(() => { });
} }
const handle = this.nextHandle(); const handle = this.nextHandle();
this._handlers.set(handle, { provider, extension }); this._handlers.set(handle, { type, provider, extension });
this._proxy.$registerTaskProvider(handle); this._proxy.$registerTaskProvider(handle, type);
return new types.Disposable(() => { return new types.Disposable(() => {
this._handlers.delete(handle); this._handlers.delete(handle);
this._proxy.$unregisterTaskProvider(handle); this._proxy.$unregisterTaskProvider(handle);
...@@ -652,15 +653,10 @@ export class ExtHostTask implements ExtHostTaskShape { ...@@ -652,15 +653,10 @@ export class ExtHostTask implements ExtHostTaskShape {
taskDTOs.push(taskDTO); taskDTOs.push(taskDTO);
if (CustomExecutionDTO.is(taskDTO.execution)) { if (CustomExecutionDTO.is(taskDTO.execution)) {
taskIdPromises.push(new Promise((resolve) => { // The ID is calculated on the main thread task side, so, let's call into it here.
// The ID is calculated on the main thread task side, so, let's call into it here. // We need the task id's pre-computed for custom task executions because when OnDidStartTask
// We need the task id's pre-computed for custom task executions because when OnDidStartTask // is invoked, we have to be able to map it back to our data.
// is invoked, we have to be able to map it back to our data. taskIdPromises.push(this.addCustomExecution(taskDTO, <vscode.Task2>task));
this._proxy.$createTaskId(taskDTO).then((taskId) => {
this._providedCustomExecutions.set(taskId, new CustomExecutionData(<vscode.CustomExecution>(<vscode.Task2>task).execution2, this._terminalService));
resolve();
});
}));
} }
} }
} }
...@@ -680,6 +676,38 @@ export class ExtHostTask implements ExtHostTaskShape { ...@@ -680,6 +676,38 @@ export class ExtHostTask implements ExtHostTaskShape {
}); });
} }
public async $resolveTask(handle: number, taskDTO: TaskDTO): Promise<TaskDTO | undefined> {
const handler = this._handlers.get(handle);
if (!handler) {
return Promise.reject(new Error('no handler found'));
}
if (taskDTO.definition.type !== handler.type) {
throw new Error(`Unexpected: Task of type [${taskDTO.definition.type}] cannot be resolved by provider of type [${handler.type}].`);
}
const task = await TaskDTO.to(taskDTO, this._workspaceProvider);
if (!task) {
throw new Error('Unexpected: Task cannot be resolved.');
}
const resolvedTask = await handler.provider.resolveTask(task, CancellationToken.None);
if (!resolvedTask) {
return;
}
const resolvedTaskDTO: TaskDTO | undefined = TaskDTO.from(resolvedTask, handler.extension);
if (!resolvedTaskDTO) {
throw new Error('Unexpected: Task cannot be resolved.');
}
if (CustomExecutionDTO.is(resolvedTaskDTO.execution)) {
await this.addCustomExecution(taskDTO, <vscode.Task2>task);
}
return resolvedTaskDTO;
}
public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }> { public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }> {
const configProvider = await this._configurationService.getConfigProvider(); const configProvider = await this._configurationService.getConfigProvider();
const uri: URI = URI.revive(uriComponents); const uri: URI = URI.revive(uriComponents);
...@@ -725,6 +753,11 @@ export class ExtHostTask implements ExtHostTaskShape { ...@@ -725,6 +753,11 @@ export class ExtHostTask implements ExtHostTaskShape {
return this._handleCounter++; return this._handleCounter++;
} }
private async addCustomExecution(taskDTO: TaskDTO, task: vscode.Task2): Promise<void> {
const taskId = await this._proxy.$createTaskId(taskDTO);
this._providedCustomExecutions.set(taskId, new CustomExecutionData(<vscode.CustomExecution>(<vscode.Task2>task).execution2, this._terminalService));
}
private async getTaskExecution(execution: TaskExecutionDTO | string, task?: vscode.Task): Promise<TaskExecutionImpl> { private async getTaskExecution(execution: TaskExecutionDTO | string, task?: vscode.Task): Promise<TaskExecutionImpl> {
if (typeof execution === 'string') { if (typeof execution === 'string') {
const taskExecution = this._taskExecutions.get(execution); const taskExecution = this._taskExecutions.get(execution);
......
...@@ -182,6 +182,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -182,6 +182,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
private _ignoredWorkspaceFolders: IWorkspaceFolder[]; private _ignoredWorkspaceFolders: IWorkspaceFolder[];
private _showIgnoreMessage?: boolean; private _showIgnoreMessage?: boolean;
private _providers: Map<number, ITaskProvider>; private _providers: Map<number, ITaskProvider>;
private _providerTypes: Map<number, string>;
protected _taskSystemInfos: Map<string, TaskSystemInfo>; protected _taskSystemInfos: Map<string, TaskSystemInfo>;
protected _workspaceTasksPromise?: Promise<Map<string, WorkspaceFolderTaskResult>>; protected _workspaceTasksPromise?: Promise<Map<string, WorkspaceFolderTaskResult>>;
...@@ -230,6 +231,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -230,6 +231,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
this._taskSystemListener = undefined; this._taskSystemListener = undefined;
this._outputChannel = this.outputService.getChannel(AbstractTaskService.OutputChannelId)!; this._outputChannel = this.outputService.getChannel(AbstractTaskService.OutputChannelId)!;
this._providers = new Map<number, ITaskProvider>(); this._providers = new Map<number, ITaskProvider>();
this._providerTypes = new Map<number, string>();
this._taskSystemInfos = new Map<string, TaskSystemInfo>(); this._taskSystemInfos = new Map<string, TaskSystemInfo>();
this._register(this.contextService.onDidChangeWorkspaceFolders(() => { this._register(this.contextService.onDidChangeWorkspaceFolders(() => {
if (!this._taskSystem && !this._workspaceTasksPromise) { if (!this._taskSystem && !this._workspaceTasksPromise) {
...@@ -443,7 +445,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -443,7 +445,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
} }
} }
public registerTaskProvider(provider: ITaskProvider): IDisposable { public registerTaskProvider(provider: ITaskProvider, type: string): IDisposable {
if (!provider) { if (!provider) {
return { return {
dispose: () => { } dispose: () => { }
...@@ -451,9 +453,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -451,9 +453,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
} }
let handle = AbstractTaskService.nextHandle++; let handle = AbstractTaskService.nextHandle++;
this._providers.set(handle, provider); this._providers.set(handle, provider);
this._providerTypes.set(handle, type);
return { return {
dispose: () => { dispose: () => {
this._providers.delete(handle); this._providers.delete(handle);
this._providerTypes.delete(handle);
} }
}; };
} }
...@@ -1154,6 +1158,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -1154,6 +1158,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
}).then((contributedTaskSets) => { }).then((contributedTaskSets) => {
let result: TaskMap = new TaskMap(); let result: TaskMap = new TaskMap();
let contributedTasks: TaskMap = new TaskMap(); let contributedTasks: TaskMap = new TaskMap();
for (let set of contributedTaskSets) { for (let set of contributedTaskSets) {
for (let task of set.tasks) { for (let task of set.tasks) {
let workspaceFolder = task.getWorkspaceFolder(); let workspaceFolder = task.getWorkspaceFolder();
...@@ -1162,8 +1167,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -1162,8 +1167,10 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
} }
} }
} }
return this.getWorkspaceTasks().then((customTasks) => {
customTasks.forEach((folderTasks, key) => { return this.getWorkspaceTasks().then(async (customTasks) => {
const customTasksKeyValuePairs = Array.from(customTasks);
const customTasksPromises = customTasksKeyValuePairs.map(async ([key, folderTasks]) => {
let contributed = contributedTasks.get(key); let contributed = contributedTasks.get(key);
if (!folderTasks.set) { if (!folderTasks.set) {
if (contributed) { if (contributed) {
...@@ -1221,8 +1228,26 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -1221,8 +1228,26 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
} else { } else {
result.add(key, ...folderTasks.set.tasks); result.add(key, ...folderTasks.set.tasks);
} }
unUsedConfigurations.forEach((value) => {
const unUsedConfigurationsAsArray = Array.from(unUsedConfigurations);
const unUsedConfigurationPromises = unUsedConfigurationsAsArray.map(async (value) => {
let configuringTask = configurations!.byIdentifier[value]; let configuringTask = configurations!.byIdentifier[value];
for (const [handle, provider] of this._providers) {
if (configuringTask.type === this._providerTypes.get(handle)) {
try {
const resolvedTask = await provider.resolveTask(configuringTask);
if (resolvedTask) {
result.add(key, TaskConfig.createCustomTask(resolvedTask, configuringTask));
return;
}
} catch (error) {
// Ignore errors. The task could not be provided by any of the providers.
}
}
}
this._outputChannel.append(nls.localize( this._outputChannel.append(nls.localize(
'TaskService.noConfiguration', 'TaskService.noConfiguration',
'Error: The {0} task detection didn\'t contribute a task for the following configuration:\n{1}\nThe task will be ignored.\n', 'Error: The {0} task detection didn\'t contribute a task for the following configuration:\n{1}\nThe task will be ignored.\n',
...@@ -1231,12 +1256,17 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer ...@@ -1231,12 +1256,17 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
)); ));
this.showOutput(); this.showOutput();
}); });
await Promise.all(unUsedConfigurationPromises);
} else { } else {
result.add(key, ...folderTasks.set.tasks); result.add(key, ...folderTasks.set.tasks);
result.add(key, ...contributed); result.add(key, ...contributed);
} }
} }
}); });
await Promise.all(customTasksPromises);
return result; return result;
}, () => { }, () => {
// If we can't read the tasks.json file provide at least the contributed tasks // If we can't read the tasks.json file provide at least the contributed tasks
......
...@@ -7,6 +7,7 @@ import * as nls from 'vs/nls'; ...@@ -7,6 +7,7 @@ import * as nls from 'vs/nls';
import * as Objects from 'vs/base/common/objects'; import * as Objects from 'vs/base/common/objects';
import { IStringDictionary } from 'vs/base/common/collections'; import { IStringDictionary } from 'vs/base/common/collections';
import { IJSONSchemaMap } from 'vs/base/common/jsonSchema';
import { Platform } from 'vs/base/common/platform'; import { Platform } from 'vs/base/common/platform';
import * as Types from 'vs/base/common/types'; import * as Types from 'vs/base/common/types';
import * as UUID from 'vs/base/common/uuid'; import * as UUID from 'vs/base/common/uuid';
...@@ -22,6 +23,7 @@ import * as Tasks from './tasks'; ...@@ -22,6 +23,7 @@ import * as Tasks from './tasks';
import { TaskDefinitionRegistry } from './taskDefinitionRegistry'; import { TaskDefinitionRegistry } from './taskDefinitionRegistry';
import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
export const enum ShellQuoting { export const enum ShellQuoting {
/** /**
* Default is character escaping. * Default is character escaping.
...@@ -1240,11 +1242,20 @@ namespace ConfigurationProperties { ...@@ -1240,11 +1242,20 @@ namespace ConfigurationProperties {
{ property: 'presentation', type: CommandConfiguration.PresentationOptions }, { property: 'problemMatchers' } { property: 'presentation', type: CommandConfiguration.PresentationOptions }, { property: 'problemMatchers' }
]; ];
export function from(this: void, external: ConfigurationProperties, context: ParseContext, includeCommandOptions: boolean): Tasks.ConfigurationProperties | undefined { export function from(this: void, external: ConfigurationProperties, context: ParseContext, includeCommandOptions: boolean, properties?: IJSONSchemaMap): Tasks.ConfigurationProperties | undefined {
if (!external) { if (!external) {
return undefined; return undefined;
} }
let result: Tasks.ConfigurationProperties = {}; let result: Tasks.ConfigurationProperties = {};
if (properties) {
for (const propertyName of Object.keys(properties)) {
if (external[propertyName] !== undefined) {
result[propertyName] = Objects.deepClone(external[propertyName]);
}
}
}
if (Types.isString(external.taskName)) { if (Types.isString(external.taskName)) {
result.name = external.taskName; result.name = external.taskName;
} }
...@@ -1380,7 +1391,7 @@ namespace ConfiguringTask { ...@@ -1380,7 +1391,7 @@ namespace ConfiguringTask {
RunOptions.fromConfiguration(external.runOptions), RunOptions.fromConfiguration(external.runOptions),
{} {}
); );
let configuration = ConfigurationProperties.from(external, context, true); let configuration = ConfigurationProperties.from(external, context, true, typeDeclaration.properties);
if (configuration) { if (configuration) {
result.configurationProperties = Objects.assign(result.configurationProperties, configuration); result.configurationProperties = Objects.assign(result.configurationProperties, configuration);
if (result.configurationProperties.name) { if (result.configurationProperties.name) {
......
...@@ -20,6 +20,7 @@ export const ITaskService = createDecorator<ITaskService>('taskService'); ...@@ -20,6 +20,7 @@ export const ITaskService = createDecorator<ITaskService>('taskService');
export interface ITaskProvider { export interface ITaskProvider {
provideTasks(validTypes: IStringDictionary<boolean>): Promise<TaskSet>; provideTasks(validTypes: IStringDictionary<boolean>): Promise<TaskSet>;
resolveTask(task: ConfiguringTask): Promise<ContributedTask | undefined>;
} }
export interface ProblemMatcherRunOptions { export interface ProblemMatcherRunOptions {
...@@ -79,7 +80,7 @@ export interface ITaskService { ...@@ -79,7 +80,7 @@ export interface ITaskService {
customize(task: ContributedTask | CustomTask, properties?: {}, openConfig?: boolean): Promise<void>; customize(task: ContributedTask | CustomTask, properties?: {}, openConfig?: boolean): Promise<void>;
openConfig(task: CustomTask | undefined): Promise<void>; openConfig(task: CustomTask | undefined): Promise<void>;
registerTaskProvider(taskProvider: ITaskProvider): IDisposable; registerTaskProvider(taskProvider: ITaskProvider, type: string): IDisposable;
registerTaskSystem(scheme: string, taskSystemInfo: TaskSystemInfo): void; registerTaskSystem(scheme: string, taskSystemInfo: TaskSystemInfo): void;
......
...@@ -745,6 +745,9 @@ export class ConfiguringTask extends CommonTask { ...@@ -745,6 +745,9 @@ export class ConfiguringTask extends CommonTask {
return object; return object;
} }
public getDefinition(): KeyedTaskIdentifier {
return this.configures;
}
} }
export class ContributedTask extends CommonTask { export class ContributedTask extends CommonTask {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册