extHostTask.ts 8.0 KB
Newer Older
1 2 3 4 5
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

6
import * as path from 'vs/base/common/path';
7

8
import { URI, UriComponents } from 'vs/base/common/uri';
9
import { win32 } from 'vs/base/node/processes';
J
Johannes Rieken 已提交
10
import * as types from 'vs/workbench/api/common/extHostTypes';
A
Alex Ross 已提交
11
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
12
import type * as vscode from 'vscode';
A
Alex Ross 已提交
13
import * as tasks from '../common/shared/tasks';
A
Andre Weinand 已提交
14
import { ExtHostVariableResolverService } from 'vs/workbench/api/common/extHostDebugService';
15 16
import { IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { IExtHostConfiguration } from 'vs/workbench/api/common/extHostConfiguration';
17
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
18
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
19
import { IExtHostTerminalService } from 'vs/workbench/api/common/extHostTerminalService';
20
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
21
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
22
import { ExtHostTaskBase, TaskHandleDTO, TaskDTO, CustomExecutionDTO, HandlerData } from 'vs/workbench/api/common/extHostTask';
23
import { Schemas } from 'vs/base/common/network';
24
import { ILogService } from 'vs/platform/log/common/log';
A
Andre Weinand 已提交
25
import { IProcessEnvironment } from 'vs/base/common/platform';
26
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
27

A
Alex Ross 已提交
28
export class ExtHostTask extends ExtHostTaskBase {
29
	private _variableResolver: ExtHostVariableResolverService | undefined;
D
Dirk Baeumer 已提交
30

31
	constructor(
32
		@IExtHostRpcService extHostRpc: IExtHostRpcService,
33
		@IExtHostInitDataService initData: IExtHostInitDataService,
34
		@IExtHostWorkspace private readonly workspaceService: IExtHostWorkspace,
35 36
		@IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors,
		@IExtHostConfiguration configurationService: IExtHostConfiguration,
37
		@IExtHostTerminalService extHostTerminalService: IExtHostTerminalService,
38 39
		@ILogService logService: ILogService,
		@IExtHostApiDeprecationService deprecationService: IExtHostApiDeprecationService
40
	) {
41
		super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService, deprecationService);
42 43 44 45 46 47 48
		if (initData.remote.isRemote && initData.remote.authority) {
			this.registerTaskSystem(Schemas.vscodeRemote, {
				scheme: Schemas.vscodeRemote,
				authority: initData.remote.authority,
				platform: process.platform
			});
		}
49
		this._proxy.$registerSupportedExecutions(true, true, true);
50
	}
51

52
	public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution> {
53
		const tTask = (task as types.Task);
54
		// We have a preserved ID. So the task didn't change.
R
Rob Lourens 已提交
55
		if (tTask._id !== undefined) {
56
			// Always get the task execution first to prevent timing issues when retrieving it later
57
			const handleDto = TaskHandleDTO.from(tTask, this.workspaceService);
58
			const executionDTO = await this._proxy.$getTaskExecution(handleDto);
59 60 61 62
			if (executionDTO.task === undefined) {
				throw new Error('Task from execution DTO is undefined');
			}
			const execution = await this.getTaskExecution(executionDTO, task);
63
			this._proxy.$executeTask(handleDto).catch(() => { /* The error here isn't actionable. */ });
64
			return execution;
65
		} else {
66
			const dto = TaskDTO.from(task, extension);
R
Rob Lourens 已提交
67
			if (dto === undefined) {
D
Dirk Baeumer 已提交
68 69
				return Promise.reject(new Error('Task is not valid'));
			}
70 71 72 73

			// If this task is a custom execution, then we need to save it away
			// in the provided custom execution map that is cleaned up after the
			// task is executed.
74
			if (CustomExecutionDTO.is(dto.execution)) {
A
Alex Ross 已提交
75
				await this.addCustomExecution(dto, task, false);
76
			}
77 78
			// Always get the task execution first to prevent timing issues when retrieving it later
			const execution = await this.getTaskExecution(await this._proxy.$getTaskExecution(dto), task);
79
			this._proxy.$executeTask(dto).catch(() => { /* The error here isn't actionable. */ });
80
			return execution;
81 82 83
		}
	}

A
Alex Ross 已提交
84 85 86 87
	protected provideTasksInternal(validTypes: { [key: string]: boolean; }, taskIdPromises: Promise<void>[], handler: HandlerData, value: vscode.Task[] | null | undefined): { tasks: tasks.TaskDTO[], extension: IExtensionDescription } {
		const taskDTOs: tasks.TaskDTO[] = [];
		if (value) {
			for (let task of value) {
88 89
				this.checkDeprecation(task, handler);

A
Alex Ross 已提交
90
				if (!task.definition || !validTypes[task.definition.type]) {
91
					this._logService.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`);
A
Alex Ross 已提交
92
				}
A
Alex Ross 已提交
93

A
Alex Ross 已提交
94 95 96
				const taskDTO: tasks.TaskDTO | undefined = TaskDTO.from(task, handler.extension);
				if (taskDTO) {
					taskDTOs.push(taskDTO);
A
Alex Ross 已提交
97

98
					if (CustomExecutionDTO.is(taskDTO.execution)) {
A
Alex Ross 已提交
99 100 101
						// 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
						// is invoked, we have to be able to map it back to our data.
A
Alex Ross 已提交
102
						taskIdPromises.push(this.addCustomExecution(taskDTO, task, true));
A
Alex Ross 已提交
103
					}
104
				}
105
			}
106
		}
A
Alex Ross 已提交
107 108 109 110 111
		return {
			tasks: taskDTOs,
			extension: handler.extension
		};
	}
112

A
Alex Ross 已提交
113
	protected async resolveTaskInternal(resolvedTaskDTO: tasks.TaskDTO): Promise<tasks.TaskDTO | undefined> {
114 115 116
		return resolvedTaskDTO;
	}

117 118 119
	private async getVariableResolver(workspaceFolders: vscode.WorkspaceFolder[]): Promise<ExtHostVariableResolverService> {
		if (this._variableResolver === undefined) {
			const configProvider = await this._configurationService.getConfigProvider();
A
Andre Weinand 已提交
120
			this._variableResolver = new ExtHostVariableResolverService(workspaceFolders, this._editorService, configProvider, process.env as IProcessEnvironment);
121 122 123 124
		}
		return this._variableResolver;
	}

125
	public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }> {
126 127
		const uri: URI = URI.revive(uriComponents);
		const result = {
A
Alex Ross 已提交
128
			process: <unknown>undefined as string,
129 130
			variables: Object.create(null)
		};
131
		const workspaceFolder = await this._workspaceProvider.resolveWorkspaceFolder(uri);
132
		const workspaceFolders = await this._workspaceProvider.getWorkspaceFolders2();
A
Alex Ross 已提交
133 134 135
		if (!workspaceFolders || !workspaceFolder) {
			throw new Error('Unexpected: Tasks can only be run in a workspace folder');
		}
136
		const resolver = await this.getVariableResolver(workspaceFolders);
137
		const ws: IWorkspaceFolder = {
138 139 140 141 142 143 144
			uri: workspaceFolder.uri,
			name: workspaceFolder.name,
			index: workspaceFolder.index,
			toResource: () => {
				throw new Error('Not implemented');
			}
		};
145 146 147
		for (let variable of toResolve.variables) {
			result.variables[variable] = resolver.resolve(ws, variable);
		}
R
Rob Lourens 已提交
148
		if (toResolve.process !== undefined) {
149
			let paths: string[] | undefined = undefined;
R
Rob Lourens 已提交
150
			if (toResolve.process.path !== undefined) {
151 152 153 154 155
				paths = toResolve.process.path.split(path.delimiter);
				for (let i = 0; i < paths.length; i++) {
					paths[i] = resolver.resolve(ws, paths[i]);
				}
			}
A
Alex Ross 已提交
156
			result.process = await win32.findExecutable(
157
				resolver.resolve(ws, toResolve.process.name),
R
Rob Lourens 已提交
158
				toResolve.process.cwd !== undefined ? resolver.resolve(ws, toResolve.process.cwd) : undefined,
159 160
				paths
			);
161
		}
162
		return result;
163 164
	}

165
	public $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }> {
166
		return this._terminalService.$getDefaultShellAndArgs(true);
167 168
	}

A
Alex Ross 已提交
169 170
	public async $jsonTasksSupported(): Promise<boolean> {
		return true;
171
	}
172 173 174 175

	public async $findExecutable(command: string, cwd?: string, paths?: string[]): Promise<string> {
		return win32.findExecutable(command, cwd, paths);
	}
176
}