Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/workbench/api/node/extHostTask.ts
3296 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import * as path from '../../../base/common/path.js';
7
8
import { URI, UriComponents } from '../../../base/common/uri.js';
9
import { findExecutable } from '../../../base/node/processes.js';
10
import * as types from '../common/extHostTypes.js';
11
import { IExtHostWorkspace } from '../common/extHostWorkspace.js';
12
import type * as vscode from 'vscode';
13
import * as tasks from '../common/shared/tasks.js';
14
import { IExtHostDocumentsAndEditors } from '../common/extHostDocumentsAndEditors.js';
15
import { IExtHostConfiguration } from '../common/extHostConfiguration.js';
16
import { IWorkspaceFolder, WorkspaceFolder } from '../../../platform/workspace/common/workspace.js';
17
import { IExtensionDescription } from '../../../platform/extensions/common/extensions.js';
18
import { IExtHostTerminalService } from '../common/extHostTerminalService.js';
19
import { IExtHostRpcService } from '../common/extHostRpcService.js';
20
import { IExtHostInitDataService } from '../common/extHostInitDataService.js';
21
import { ExtHostTaskBase, TaskHandleDTO, TaskDTO, CustomExecutionDTO, HandlerData } from '../common/extHostTask.js';
22
import { Schemas } from '../../../base/common/network.js';
23
import { ILogService } from '../../../platform/log/common/log.js';
24
import { IExtHostApiDeprecationService } from '../common/extHostApiDeprecationService.js';
25
import * as resources from '../../../base/common/resources.js';
26
import { homedir } from 'os';
27
import { IExtHostVariableResolverProvider } from '../common/extHostVariableResolverService.js';
28
29
export class ExtHostTask extends ExtHostTaskBase {
30
constructor(
31
@IExtHostRpcService extHostRpc: IExtHostRpcService,
32
@IExtHostInitDataService initData: IExtHostInitDataService,
33
@IExtHostWorkspace private readonly workspaceService: IExtHostWorkspace,
34
@IExtHostDocumentsAndEditors editorService: IExtHostDocumentsAndEditors,
35
@IExtHostConfiguration configurationService: IExtHostConfiguration,
36
@IExtHostTerminalService extHostTerminalService: IExtHostTerminalService,
37
@ILogService logService: ILogService,
38
@IExtHostApiDeprecationService deprecationService: IExtHostApiDeprecationService,
39
@IExtHostVariableResolverProvider private readonly variableResolver: IExtHostVariableResolverProvider,
40
) {
41
super(extHostRpc, initData, workspaceService, editorService, configurationService, extHostTerminalService, logService, deprecationService);
42
if (initData.remote.isRemote && initData.remote.authority) {
43
this.registerTaskSystem(Schemas.vscodeRemote, {
44
scheme: Schemas.vscodeRemote,
45
authority: initData.remote.authority,
46
platform: process.platform
47
});
48
} else {
49
this.registerTaskSystem(Schemas.file, {
50
scheme: Schemas.file,
51
authority: '',
52
platform: process.platform
53
});
54
}
55
this._proxy.$registerSupportedExecutions(true, true, true);
56
}
57
58
public async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution> {
59
const tTask = (task as types.Task);
60
61
if (!task.execution && (tTask._id === undefined)) {
62
throw new Error('Tasks to execute must include an execution');
63
}
64
65
// We have a preserved ID. So the task didn't change.
66
if (tTask._id !== undefined) {
67
// Always get the task execution first to prevent timing issues when retrieving it later
68
const handleDto = TaskHandleDTO.from(tTask, this.workspaceService);
69
const executionDTO = await this._proxy.$getTaskExecution(handleDto);
70
if (executionDTO.task === undefined) {
71
throw new Error('Task from execution DTO is undefined');
72
}
73
const execution = await this.getTaskExecution(executionDTO, task);
74
this._proxy.$executeTask(handleDto).catch(() => { /* The error here isn't actionable. */ });
75
return execution;
76
} else {
77
const dto = TaskDTO.from(task, extension);
78
if (dto === undefined) {
79
return Promise.reject(new Error('Task is not valid'));
80
}
81
82
// If this task is a custom execution, then we need to save it away
83
// in the provided custom execution map that is cleaned up after the
84
// task is executed.
85
if (CustomExecutionDTO.is(dto.execution)) {
86
await this.addCustomExecution(dto, task, false);
87
}
88
// Always get the task execution first to prevent timing issues when retrieving it later
89
const execution = await this.getTaskExecution(await this._proxy.$getTaskExecution(dto), task);
90
this._proxy.$executeTask(dto).catch(() => { /* The error here isn't actionable. */ });
91
return execution;
92
}
93
}
94
95
protected provideTasksInternal(validTypes: { [key: string]: boolean }, taskIdPromises: Promise<void>[], handler: HandlerData, value: vscode.Task[] | null | undefined): { tasks: tasks.ITaskDTO[]; extension: IExtensionDescription } {
96
const taskDTOs: tasks.ITaskDTO[] = [];
97
if (value) {
98
for (const task of value) {
99
this.checkDeprecation(task, handler);
100
101
if (!task.definition || !validTypes[task.definition.type]) {
102
this._logService.warn(`The task [${task.source}, ${task.name}] uses an undefined task type. The task will be ignored in the future.`);
103
}
104
105
const taskDTO: tasks.ITaskDTO | undefined = TaskDTO.from(task, handler.extension);
106
if (taskDTO) {
107
taskDTOs.push(taskDTO);
108
109
if (CustomExecutionDTO.is(taskDTO.execution)) {
110
// The ID is calculated on the main thread task side, so, let's call into it here.
111
// We need the task id's pre-computed for custom task executions because when OnDidStartTask
112
// is invoked, we have to be able to map it back to our data.
113
taskIdPromises.push(this.addCustomExecution(taskDTO, task, true));
114
}
115
}
116
}
117
}
118
return {
119
tasks: taskDTOs,
120
extension: handler.extension
121
};
122
}
123
124
protected async resolveTaskInternal(resolvedTaskDTO: tasks.ITaskDTO): Promise<tasks.ITaskDTO | undefined> {
125
return resolvedTaskDTO;
126
}
127
128
private async getAFolder(workspaceFolders: vscode.WorkspaceFolder[] | undefined): Promise<IWorkspaceFolder> {
129
let folder = (workspaceFolders && workspaceFolders.length > 0) ? workspaceFolders[0] : undefined;
130
if (!folder) {
131
const userhome = URI.file(homedir());
132
folder = new WorkspaceFolder({ uri: userhome, name: resources.basename(userhome), index: 0 });
133
}
134
return {
135
uri: folder.uri,
136
name: folder.name,
137
index: folder.index,
138
toResource: () => {
139
throw new Error('Not implemented');
140
}
141
};
142
}
143
144
public async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }; variables: string[] }): Promise<{ process?: string; variables: { [key: string]: string } }> {
145
const uri: URI = URI.revive(uriComponents);
146
const result = {
147
process: undefined as string | undefined,
148
variables: Object.create(null)
149
};
150
const workspaceFolder = await this._workspaceProvider.resolveWorkspaceFolder(uri);
151
const workspaceFolders = (await this._workspaceProvider.getWorkspaceFolders2()) ?? [];
152
153
const resolver = await this.variableResolver.getResolver();
154
const ws: IWorkspaceFolder = workspaceFolder ? {
155
uri: workspaceFolder.uri,
156
name: workspaceFolder.name,
157
index: workspaceFolder.index,
158
toResource: () => {
159
throw new Error('Not implemented');
160
}
161
} : await this.getAFolder(workspaceFolders);
162
163
for (const variable of toResolve.variables) {
164
result.variables[variable] = await resolver.resolveAsync(ws, variable);
165
}
166
if (toResolve.process !== undefined) {
167
let paths: string[] | undefined = undefined;
168
if (toResolve.process.path !== undefined) {
169
paths = toResolve.process.path.split(path.delimiter);
170
for (let i = 0; i < paths.length; i++) {
171
paths[i] = await resolver.resolveAsync(ws, paths[i]);
172
}
173
}
174
const processName = await resolver.resolveAsync(ws, toResolve.process.name);
175
const cwd = toResolve.process.cwd !== undefined ? await resolver.resolveAsync(ws, toResolve.process.cwd) : undefined;
176
const foundExecutable = await findExecutable(processName, cwd, paths);
177
if (foundExecutable) {
178
result.process = foundExecutable;
179
} else if (path.isAbsolute(processName)) {
180
result.process = processName;
181
} else {
182
result.process = path.join(cwd ?? '', processName);
183
}
184
}
185
return result;
186
}
187
188
public async $jsonTasksSupported(): Promise<boolean> {
189
return true;
190
}
191
192
public async $findExecutable(command: string, cwd?: string, paths?: string[]): Promise<string | undefined> {
193
return findExecutable(command, cwd, paths);
194
}
195
}
196
197