mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-28 12:33:35 +01:00
Make changes to tasks to allow tasks from User Settings and workspace file (#81469)
Still need to make configuration changes. Part of #1435
This commit is contained in:
@@ -44,7 +44,7 @@ import Constants from 'vs/workbench/contrib/markers/browser/constants';
|
||||
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { IOutputService, IOutputChannel } from 'vs/workbench/contrib/output/common/output';
|
||||
@@ -178,6 +178,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
private _schemaVersion: JsonSchemaVersion | undefined;
|
||||
private _executionEngine: ExecutionEngine | undefined;
|
||||
private _workspaceFolders: IWorkspaceFolder[] | undefined;
|
||||
private _workspace: IWorkspace | undefined;
|
||||
private _ignoredWorkspaceFolders: IWorkspaceFolder[] | undefined;
|
||||
private _showIgnoreMessage?: boolean;
|
||||
private _providers: Map<number, ITaskProvider>;
|
||||
@@ -425,7 +426,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
return this._showIgnoreMessage;
|
||||
}
|
||||
|
||||
private updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion]): void {
|
||||
private updateSetup(setup?: [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined]): void {
|
||||
if (!setup) {
|
||||
setup = this.computeWorkspaceFolderSetup();
|
||||
}
|
||||
@@ -447,6 +448,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
this._ignoredWorkspaceFolders = setup[1];
|
||||
this._executionEngine = setup[2];
|
||||
this._schemaVersion = setup[3];
|
||||
this._workspace = setup[4];
|
||||
}
|
||||
|
||||
protected showOutput(runSource: TaskRunSource = TaskRunSource.User): void {
|
||||
@@ -1402,13 +1404,21 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
for (let folder of this.workspaceFolders) {
|
||||
promises.push(this.computeWorkspaceFolderTasks(folder, runSource).then((value) => value, () => undefined));
|
||||
}
|
||||
return Promise.all(promises).then((values) => {
|
||||
return Promise.all(promises).then(async (values) => {
|
||||
let result = new Map<string, WorkspaceFolderTaskResult>();
|
||||
for (let value of values) {
|
||||
if (value) {
|
||||
result.set(value.workspaceFolder.uri.toString(), value);
|
||||
}
|
||||
}
|
||||
const userTasks = await this.computeUserTasks(this.workspaceFolders[0], runSource).then((value) => value, () => undefined);
|
||||
if (userTasks) {
|
||||
result.set('settings', userTasks);
|
||||
}
|
||||
const workspaceFileTasks = await this.computeWorkspaceFileTasks(this.workspaceFolders[0], runSource).then((value) => value, () => undefined);
|
||||
if (workspaceFileTasks && this._workspace && this._workspace.configuration) {
|
||||
result.set(this._workspace.configuration.toString(), workspaceFileTasks);
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
@@ -1429,7 +1439,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
return ProblemMatcherRegistry.onReady().then(async (): Promise<WorkspaceFolderTaskResult> => {
|
||||
let taskSystemInfo: TaskSystemInfo | undefined = this._taskSystemInfos.get(workspaceFolder.uri.scheme);
|
||||
let problemReporter = new ProblemReporter(this._outputChannel);
|
||||
let parseResult = TaskConfig.parse(workspaceFolder, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, workspaceFolderConfiguration.config!, problemReporter);
|
||||
let parseResult = TaskConfig.parse(workspaceFolder, this._workspace, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, workspaceFolderConfiguration.config!, problemReporter, TaskConfig.TaskConfigSource.TasksJson);
|
||||
let hasErrors = false;
|
||||
if (!parseResult.validationStatus.isOK()) {
|
||||
hasErrors = true;
|
||||
@@ -1456,6 +1466,101 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
});
|
||||
}
|
||||
|
||||
private testParseExternalConfig(config: TaskConfig.ExternalTaskRunnerConfiguration | undefined, location: string): { config: TaskConfig.ExternalTaskRunnerConfiguration | undefined, hasParseErrors: boolean } {
|
||||
if (!config) {
|
||||
return { config: undefined, hasParseErrors: false };
|
||||
}
|
||||
let parseErrors: string[] = (config as any).$parseErrors;
|
||||
if (parseErrors) {
|
||||
let isAffected = false;
|
||||
for (const parseError of parseErrors) {
|
||||
if (/tasks\.json$/.test(parseError)) {
|
||||
isAffected = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isAffected) {
|
||||
this._outputChannel.append(nls.localize('TaskSystem.invalidTaskJsonOther', 'Error: The content of the tasks json in {0} has syntax errors. Please correct them before executing a task.\n', location));
|
||||
this.showOutput();
|
||||
return { config, hasParseErrors: true };
|
||||
}
|
||||
}
|
||||
return { config, hasParseErrors: false };
|
||||
}
|
||||
|
||||
private async computeWorkspaceFileTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise<WorkspaceFolderTaskResult> {
|
||||
if (this.executionEngine === ExecutionEngine.Process) {
|
||||
return this.emptyWorkspaceTaskResults(workspaceFolder);
|
||||
}
|
||||
const configuration = this.testParseExternalConfig(this.configurationService.inspect<TaskConfig.ExternalTaskRunnerConfiguration>('tasks').workspace, nls.localize('TasksSystem.locationWorkspaceConfig', 'workspace file'));
|
||||
let customizedTasks: { byIdentifier: IStringDictionary<ConfiguringTask>; } = {
|
||||
byIdentifier: Object.create(null)
|
||||
};
|
||||
|
||||
const custom: CustomTask[] = [];
|
||||
await this.computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.WorkspaceFile);
|
||||
const engine = configuration.config ? TaskConfig.ExecutionEngine.from(configuration.config) : ExecutionEngine.Terminal;
|
||||
if (engine === ExecutionEngine.Process) {
|
||||
this.notificationService.warn(nls.localize('TaskSystem.versionWorkspaceFile', 'Only tasks version 2.0.0 permitted in .codeworkspace.'));
|
||||
return this.emptyWorkspaceTaskResults(workspaceFolder);
|
||||
}
|
||||
return { workspaceFolder, set: { tasks: custom }, configurations: customizedTasks, hasErrors: configuration.hasParseErrors };
|
||||
}
|
||||
|
||||
private async computeUserTasks(workspaceFolder: IWorkspaceFolder, runSource: TaskRunSource = TaskRunSource.User): Promise<WorkspaceFolderTaskResult> {
|
||||
if (this.executionEngine === ExecutionEngine.Process) {
|
||||
return this.emptyWorkspaceTaskResults(workspaceFolder);
|
||||
}
|
||||
const configuration = this.testParseExternalConfig(this.configurationService.inspect<TaskConfig.ExternalTaskRunnerConfiguration>('tasks').user, nls.localize('TasksSystem.locationUserConfig', 'user settings'));
|
||||
let customizedTasks: { byIdentifier: IStringDictionary<ConfiguringTask>; } = {
|
||||
byIdentifier: Object.create(null)
|
||||
};
|
||||
|
||||
const custom: CustomTask[] = [];
|
||||
await this.computeTasksForSingleConfig(workspaceFolder, configuration.config, runSource, custom, customizedTasks.byIdentifier, TaskConfig.TaskConfigSource.User);
|
||||
const engine = configuration.config ? TaskConfig.ExecutionEngine.from(configuration.config) : ExecutionEngine.Terminal;
|
||||
if (engine === ExecutionEngine.Process) {
|
||||
this.notificationService.warn(nls.localize('TaskSystem.versionSettings', 'Only tasks version 2.0.0 permitted in user settings.'));
|
||||
return this.emptyWorkspaceTaskResults(workspaceFolder);
|
||||
}
|
||||
return { workspaceFolder, set: { tasks: custom }, configurations: customizedTasks, hasErrors: configuration.hasParseErrors };
|
||||
}
|
||||
|
||||
private emptyWorkspaceTaskResults(workspaceFolder: IWorkspaceFolder): WorkspaceFolderTaskResult {
|
||||
return { workspaceFolder, set: undefined, configurations: undefined, hasErrors: false };
|
||||
}
|
||||
|
||||
private async computeTasksForSingleConfig(workspaceFolder: IWorkspaceFolder, config: TaskConfig.ExternalTaskRunnerConfiguration | undefined, runSource: TaskRunSource, custom: CustomTask[], customized: IStringDictionary<ConfiguringTask>, source: TaskConfig.TaskConfigSource): Promise<boolean> {
|
||||
if (!config) {
|
||||
return false;
|
||||
}
|
||||
let taskSystemInfo: TaskSystemInfo | undefined = workspaceFolder ? this._taskSystemInfos.get(workspaceFolder.uri.scheme) : undefined;
|
||||
let problemReporter = new ProblemReporter(this._outputChannel);
|
||||
let parseResult = TaskConfig.parse(workspaceFolder, this._workspace, taskSystemInfo ? taskSystemInfo.platform : Platform.platform, config, problemReporter, source);
|
||||
let hasErrors = false;
|
||||
if (!parseResult.validationStatus.isOK()) {
|
||||
this.showOutput(runSource);
|
||||
hasErrors = true;
|
||||
}
|
||||
if (problemReporter.status.isFatal()) {
|
||||
problemReporter.fatal(nls.localize('TaskSystem.configurationErrors', 'Error: the provided task configuration has validation errors and can\'t not be used. Please correct the errors first.'));
|
||||
return hasErrors;
|
||||
}
|
||||
if (parseResult.configured && parseResult.configured.length > 0) {
|
||||
for (let task of parseResult.configured) {
|
||||
customized[task.configures._key] = task;
|
||||
}
|
||||
}
|
||||
if (!(await this._areJsonTasksSupportedPromise) && (parseResult.custom.length > 0)) {
|
||||
console.warn('Custom workspace tasks are not supported.');
|
||||
} else {
|
||||
for (let task of parseResult.custom) {
|
||||
custom.push(task);
|
||||
}
|
||||
}
|
||||
return hasErrors;
|
||||
}
|
||||
|
||||
private computeConfiguration(workspaceFolder: IWorkspaceFolder): Promise<WorkspaceFolderConfigurationResult> {
|
||||
let { config, hasParseErrors } = this.getConfiguration(workspaceFolder);
|
||||
return Promise.resolve<WorkspaceFolderConfigurationResult>({ workspaceFolder, config, hasErrors: hasParseErrors });
|
||||
@@ -1463,18 +1568,19 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
|
||||
protected abstract computeLegacyConfiguration(workspaceFolder: IWorkspaceFolder): Promise<WorkspaceFolderConfigurationResult>;
|
||||
|
||||
private computeWorkspaceFolderSetup(): [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion] {
|
||||
private computeWorkspaceFolderSetup(): [IWorkspaceFolder[], IWorkspaceFolder[], ExecutionEngine, JsonSchemaVersion, IWorkspace | undefined] {
|
||||
let workspaceFolders: IWorkspaceFolder[] = [];
|
||||
let ignoredWorkspaceFolders: IWorkspaceFolder[] = [];
|
||||
let executionEngine = ExecutionEngine.Terminal;
|
||||
let schemaVersion = JsonSchemaVersion.V2_0_0;
|
||||
|
||||
let workspace: IWorkspace | undefined;
|
||||
if (this.contextService.getWorkbenchState() === WorkbenchState.FOLDER) {
|
||||
let workspaceFolder: IWorkspaceFolder = this.contextService.getWorkspace().folders[0];
|
||||
workspaceFolders.push(workspaceFolder);
|
||||
executionEngine = this.computeExecutionEngine(workspaceFolder);
|
||||
schemaVersion = this.computeJsonSchemaVersion(workspaceFolder);
|
||||
} else if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
|
||||
workspace = this.contextService.getWorkspace();
|
||||
for (let workspaceFolder of this.contextService.getWorkspace().folders) {
|
||||
if (schemaVersion === this.computeJsonSchemaVersion(workspaceFolder)) {
|
||||
workspaceFolders.push(workspaceFolder);
|
||||
@@ -1487,7 +1593,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
}
|
||||
}
|
||||
}
|
||||
return [workspaceFolders, ignoredWorkspaceFolders, executionEngine, schemaVersion];
|
||||
return [workspaceFolders, ignoredWorkspaceFolders, executionEngine, schemaVersion, workspace];
|
||||
}
|
||||
|
||||
private computeExecutionEngine(workspaceFolder: IWorkspaceFolder): ExecutionEngine {
|
||||
@@ -1508,7 +1614,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
|
||||
protected getConfiguration(workspaceFolder: IWorkspaceFolder): { config: TaskConfig.ExternalTaskRunnerConfiguration | undefined; hasParseErrors: boolean } {
|
||||
let result = this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY
|
||||
? Objects.deepClone(this.configurationService.getValue<TaskConfig.ExternalTaskRunnerConfiguration>('tasks', { resource: workspaceFolder.uri }))
|
||||
? Objects.deepClone(this.configurationService.inspect<TaskConfig.ExternalTaskRunnerConfiguration>('tasks', { resource: workspaceFolder.uri }).workspaceFolder)
|
||||
: undefined;
|
||||
if (!result) {
|
||||
return { config: undefined, hasParseErrors: false };
|
||||
@@ -1660,7 +1766,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
|
||||
}
|
||||
const TaskQuickPickEntry = (task: Task): TaskQuickPickEntry => {
|
||||
let description: string | undefined;
|
||||
if (this.needsFolderQualification()) {
|
||||
if (task._source.kind === TaskSourceKind.User) {
|
||||
description = nls.localize('taskQuickPick.userSettings', 'User Settings');
|
||||
} else if (task._source.kind === TaskSourceKind.WorkspaceFile) {
|
||||
description = task.getWorkspaceFileName();
|
||||
} else if (this.needsFolderQualification()) {
|
||||
let workspaceFolder = task.getWorkspaceFolder();
|
||||
if (workspaceFolder) {
|
||||
description = workspaceFolder.name;
|
||||
|
||||
@@ -255,9 +255,8 @@ const actionBarRegistry = Registry.as<IActionBarRegistry>(ActionBarExtensions.Ac
|
||||
actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionContributor);
|
||||
|
||||
// tasks.json validation
|
||||
let schemaId = 'vscode://schemas/tasks';
|
||||
let schema: IJSONSchema = {
|
||||
id: schemaId,
|
||||
id: tasksSchemaId,
|
||||
description: 'Task definition file',
|
||||
type: 'object',
|
||||
allowTrailingCommas: true,
|
||||
@@ -283,6 +282,7 @@ let schema: IJSONSchema = {
|
||||
import schemaVersion1 from '../common/jsonSchema_v1';
|
||||
import schemaVersion2, { updateProblemMatchers } from '../common/jsonSchema_v2';
|
||||
import { AbstractTaskService, ConfigureTaskAction } from 'vs/workbench/contrib/tasks/browser/abstractTaskService';
|
||||
import { tasksSchemaId } from 'vs/workbench/services/configuration/common/configuration';
|
||||
schema.definitions = {
|
||||
...schemaVersion1.definitions,
|
||||
...schemaVersion2.definitions,
|
||||
@@ -290,9 +290,9 @@ schema.definitions = {
|
||||
schema.oneOf = [...(schemaVersion2.oneOf || []), ...(schemaVersion1.oneOf || [])];
|
||||
|
||||
let jsonRegistry = <jsonContributionRegistry.IJSONContributionRegistry>Registry.as(jsonContributionRegistry.Extensions.JSONContribution);
|
||||
jsonRegistry.registerSchema(schemaId, schema);
|
||||
jsonRegistry.registerSchema(tasksSchemaId, schema);
|
||||
|
||||
ProblemMatcherRegistry.onMatcherChanged(() => {
|
||||
updateProblemMatchers();
|
||||
jsonRegistry.notifySchemaChanged(schemaId);
|
||||
jsonRegistry.notifySchemaChanged(tasksSchemaId);
|
||||
});
|
||||
|
||||
@@ -18,7 +18,7 @@ import {
|
||||
isNamedProblemMatcher, ProblemMatcherRegistry
|
||||
} from 'vs/workbench/contrib/tasks/common/problemMatcher';
|
||||
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import * as Tasks from './tasks';
|
||||
import { TaskDefinitionRegistry } from './taskDefinitionRegistry';
|
||||
import { ConfiguredInput } from 'vs/workbench/services/configurationResolver/common/configurationResolver';
|
||||
@@ -683,6 +683,7 @@ export namespace RunOptions {
|
||||
|
||||
interface ParseContext {
|
||||
workspaceFolder: IWorkspaceFolder;
|
||||
workspace: IWorkspace | undefined;
|
||||
problemReporter: IProblemReporter;
|
||||
namedProblemMatchers: IStringDictionary<NamedProblemMatcher>;
|
||||
uuidMap: UUIDMap;
|
||||
@@ -1181,8 +1182,7 @@ namespace ProblemMatcherConverter {
|
||||
}
|
||||
}
|
||||
|
||||
const source: Partial<Tasks.TaskSource> = {
|
||||
kind: Tasks.TaskSourceKind.Workspace,
|
||||
const partialSource: Partial<Tasks.TaskSource> = {
|
||||
label: 'Workspace',
|
||||
config: undefined
|
||||
};
|
||||
@@ -1328,7 +1328,7 @@ namespace ConfiguringTask {
|
||||
customize: string;
|
||||
}
|
||||
|
||||
export function from(this: void, external: ConfiguringTask, context: ParseContext, index: number): Tasks.ConfiguringTask | undefined {
|
||||
export function from(this: void, external: ConfiguringTask, context: ParseContext, index: number, source: TaskConfigSource): Tasks.ConfiguringTask | undefined {
|
||||
if (!external) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1383,9 +1383,24 @@ namespace ConfiguringTask {
|
||||
index,
|
||||
element: external
|
||||
};
|
||||
let taskSource: Tasks.FileBasedTaskSource;
|
||||
switch (source) {
|
||||
case TaskConfigSource.User: {
|
||||
taskSource = Objects.assign({} as Tasks.UserTaskSource, partialSource, { kind: Tasks.TaskSourceKind.User, config: configElement });
|
||||
break;
|
||||
}
|
||||
case TaskConfigSource.WorkspaceFile: {
|
||||
taskSource = Objects.assign({} as Tasks.WorkspaceFileTaskSource, partialSource, { kind: Tasks.TaskSourceKind.WorkspaceFile, config: configElement });
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
taskSource = Objects.assign({} as Tasks.WorkspaceTaskSource, partialSource, { kind: Tasks.TaskSourceKind.Workspace, config: configElement });
|
||||
break;
|
||||
}
|
||||
}
|
||||
let result: Tasks.ConfiguringTask = new Tasks.ConfiguringTask(
|
||||
`${typeDeclaration.extensionId}.${taskIdentifier._key}`,
|
||||
Objects.assign({} as Tasks.WorkspaceTaskSource, source, { config: configElement }),
|
||||
taskSource,
|
||||
undefined,
|
||||
type,
|
||||
taskIdentifier,
|
||||
@@ -1419,7 +1434,7 @@ namespace ConfiguringTask {
|
||||
}
|
||||
|
||||
namespace CustomTask {
|
||||
export function from(this: void, external: CustomTask, context: ParseContext, index: number): Tasks.CustomTask | undefined {
|
||||
export function from(this: void, external: CustomTask, context: ParseContext, index: number, source: TaskConfigSource): Tasks.CustomTask | undefined {
|
||||
if (!external) {
|
||||
return undefined;
|
||||
}
|
||||
@@ -1440,9 +1455,25 @@ namespace CustomTask {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let taskSource: Tasks.FileBasedTaskSource;
|
||||
switch (source) {
|
||||
case TaskConfigSource.User: {
|
||||
taskSource = Objects.assign({} as Tasks.UserTaskSource, partialSource, { kind: Tasks.TaskSourceKind.User, config: { index, element: external, file: '.vscode/tasks.json', workspaceFolder: context.workspaceFolder } });
|
||||
break;
|
||||
}
|
||||
case TaskConfigSource.WorkspaceFile: {
|
||||
taskSource = Objects.assign({} as Tasks.WorkspaceFileTaskSource, partialSource, { kind: Tasks.TaskSourceKind.WorkspaceFile, config: { index, element: external, file: '.vscode/tasks.json', workspaceFolder: context.workspaceFolder, workspace: context.workspace } });
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
taskSource = Objects.assign({} as Tasks.WorkspaceTaskSource, partialSource, { kind: Tasks.TaskSourceKind.Workspace, config: { index, element: external, file: '.vscode/tasks.json', workspaceFolder: context.workspaceFolder } });
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let result: Tasks.CustomTask = new Tasks.CustomTask(
|
||||
context.uuidMap.getUUID(taskName),
|
||||
Objects.assign({} as Tasks.WorkspaceTaskSource, source, { config: { index, element: external, file: '.vscode/tasks.json', workspaceFolder: context.workspaceFolder } }),
|
||||
taskSource,
|
||||
taskName,
|
||||
Tasks.CUSTOMIZED_TASK_TYPE,
|
||||
undefined,
|
||||
@@ -1574,7 +1605,7 @@ namespace TaskParser {
|
||||
return customize === undefined && (type === undefined || type === null || type === Tasks.CUSTOMIZED_TASK_TYPE || type === 'shell' || type === 'process');
|
||||
}
|
||||
|
||||
export function from(this: void, externals: Array<CustomTask | ConfiguringTask> | undefined, globals: Globals, context: ParseContext): TaskParseResult {
|
||||
export function from(this: void, externals: Array<CustomTask | ConfiguringTask> | undefined, globals: Globals, context: ParseContext, source: TaskConfigSource): TaskParseResult {
|
||||
let result: TaskParseResult = { custom: [], configured: [] };
|
||||
if (!externals) {
|
||||
return result;
|
||||
@@ -1586,7 +1617,7 @@ namespace TaskParser {
|
||||
for (let index = 0; index < externals.length; index++) {
|
||||
let external = externals[index];
|
||||
if (isCustomTask(external)) {
|
||||
let customTask = CustomTask.from(external, context, index);
|
||||
let customTask = CustomTask.from(external, context, index, source);
|
||||
if (customTask) {
|
||||
CustomTask.fillGlobals(customTask, globals);
|
||||
CustomTask.fillDefaults(customTask, context);
|
||||
@@ -1624,7 +1655,7 @@ namespace TaskParser {
|
||||
result.custom.push(customTask);
|
||||
}
|
||||
} else {
|
||||
let configuredTask = ConfiguringTask.from(external, context, index);
|
||||
let configuredTask = ConfiguringTask.from(external, context, index, source);
|
||||
if (configuredTask) {
|
||||
configuredTask.addTaskLoadMessages(context.taskLoadIssues);
|
||||
result.configured.push(configuredTask);
|
||||
@@ -1872,25 +1903,34 @@ class UUIDMap {
|
||||
}
|
||||
}
|
||||
|
||||
export enum TaskConfigSource {
|
||||
TasksJson,
|
||||
WorkspaceFile,
|
||||
User
|
||||
}
|
||||
|
||||
class ConfigurationParser {
|
||||
|
||||
private workspaceFolder: IWorkspaceFolder;
|
||||
private workspace: IWorkspace | undefined;
|
||||
private problemReporter: IProblemReporter;
|
||||
private uuidMap: UUIDMap;
|
||||
private platform: Platform;
|
||||
|
||||
constructor(workspaceFolder: IWorkspaceFolder, platform: Platform, problemReporter: IProblemReporter, uuidMap: UUIDMap) {
|
||||
constructor(workspaceFolder: IWorkspaceFolder, workspace: IWorkspace | undefined, platform: Platform, problemReporter: IProblemReporter, uuidMap: UUIDMap) {
|
||||
this.workspaceFolder = workspaceFolder;
|
||||
this.workspace = workspace;
|
||||
this.platform = platform;
|
||||
this.problemReporter = problemReporter;
|
||||
this.uuidMap = uuidMap;
|
||||
}
|
||||
|
||||
public run(fileConfig: ExternalTaskRunnerConfiguration): ParseResult {
|
||||
public run(fileConfig: ExternalTaskRunnerConfiguration, source: TaskConfigSource): ParseResult {
|
||||
let engine = ExecutionEngine.from(fileConfig);
|
||||
let schemaVersion = JsonSchemaVersion.from(fileConfig);
|
||||
let context: ParseContext = {
|
||||
workspaceFolder: this.workspaceFolder,
|
||||
workspace: this.workspace,
|
||||
problemReporter: this.problemReporter,
|
||||
uuidMap: this.uuidMap,
|
||||
namedProblemMatchers: {},
|
||||
@@ -1899,7 +1939,7 @@ class ConfigurationParser {
|
||||
platform: this.platform,
|
||||
taskLoadIssues: []
|
||||
};
|
||||
let taskParseResult = this.createTaskRunnerConfiguration(fileConfig, context);
|
||||
let taskParseResult = this.createTaskRunnerConfiguration(fileConfig, context, source);
|
||||
return {
|
||||
validationStatus: this.problemReporter.status,
|
||||
custom: taskParseResult.custom,
|
||||
@@ -1908,7 +1948,7 @@ class ConfigurationParser {
|
||||
};
|
||||
}
|
||||
|
||||
private createTaskRunnerConfiguration(fileConfig: ExternalTaskRunnerConfiguration, context: ParseContext): TaskParseResult {
|
||||
private createTaskRunnerConfiguration(fileConfig: ExternalTaskRunnerConfiguration, context: ParseContext, source: TaskConfigSource): TaskParseResult {
|
||||
let globals = Globals.from(fileConfig, context);
|
||||
if (this.problemReporter.status.isFatal()) {
|
||||
return { custom: [], configured: [] };
|
||||
@@ -1917,13 +1957,13 @@ class ConfigurationParser {
|
||||
let globalTasks: Tasks.CustomTask[] | undefined = undefined;
|
||||
let externalGlobalTasks: Array<ConfiguringTask | CustomTask> | undefined = undefined;
|
||||
if (fileConfig.windows && context.platform === Platform.Windows) {
|
||||
globalTasks = TaskParser.from(fileConfig.windows.tasks, globals, context).custom;
|
||||
globalTasks = TaskParser.from(fileConfig.windows.tasks, globals, context, source).custom;
|
||||
externalGlobalTasks = fileConfig.windows.tasks;
|
||||
} else if (fileConfig.osx && context.platform === Platform.Mac) {
|
||||
globalTasks = TaskParser.from(fileConfig.osx.tasks, globals, context).custom;
|
||||
globalTasks = TaskParser.from(fileConfig.osx.tasks, globals, context, source).custom;
|
||||
externalGlobalTasks = fileConfig.osx.tasks;
|
||||
} else if (fileConfig.linux && context.platform === Platform.Linux) {
|
||||
globalTasks = TaskParser.from(fileConfig.linux.tasks, globals, context).custom;
|
||||
globalTasks = TaskParser.from(fileConfig.linux.tasks, globals, context, source).custom;
|
||||
externalGlobalTasks = fileConfig.linux.tasks;
|
||||
}
|
||||
if (context.schemaVersion === Tasks.JsonSchemaVersion.V2_0_0 && globalTasks && globalTasks.length > 0 && externalGlobalTasks && externalGlobalTasks.length > 0) {
|
||||
@@ -1940,7 +1980,7 @@ class ConfigurationParser {
|
||||
|
||||
let result: TaskParseResult = { custom: [], configured: [] };
|
||||
if (fileConfig.tasks) {
|
||||
result = TaskParser.from(fileConfig.tasks, globals, context);
|
||||
result = TaskParser.from(fileConfig.tasks, globals, context, source);
|
||||
}
|
||||
if (globalTasks) {
|
||||
result.custom = TaskParser.assignTasks(result.custom, globalTasks);
|
||||
@@ -1989,7 +2029,7 @@ class ConfigurationParser {
|
||||
}
|
||||
|
||||
let uuidMaps: Map<string, UUIDMap> = new Map();
|
||||
export function parse(workspaceFolder: IWorkspaceFolder, platform: Platform, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter): ParseResult {
|
||||
export function parse(workspaceFolder: IWorkspaceFolder, workspace: IWorkspace | undefined, platform: Platform, configuration: ExternalTaskRunnerConfiguration, logger: IProblemReporter, source: TaskConfigSource): ParseResult {
|
||||
let uuidMap = uuidMaps.get(workspaceFolder.uri.toString());
|
||||
if (!uuidMap) {
|
||||
uuidMap = new UUIDMap();
|
||||
@@ -1997,7 +2037,7 @@ export function parse(workspaceFolder: IWorkspaceFolder, platform: Platform, con
|
||||
}
|
||||
try {
|
||||
uuidMap.start();
|
||||
return (new ConfigurationParser(workspaceFolder, platform, logger, uuidMap)).run(configuration);
|
||||
return (new ConfigurationParser(workspaceFolder, workspace, platform, logger, uuidMap)).run(configuration, source);
|
||||
} finally {
|
||||
uuidMap.finish();
|
||||
}
|
||||
|
||||
@@ -5,12 +5,13 @@
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import * as Types from 'vs/base/common/types';
|
||||
import * as resources from 'vs/base/common/resources';
|
||||
import { IJSONSchemaMap } from 'vs/base/common/jsonSchema';
|
||||
import * as Objects from 'vs/base/common/objects';
|
||||
import { UriComponents } from 'vs/base/common/uri';
|
||||
|
||||
import { ProblemMatcher } from 'vs/workbench/contrib/tasks/common/problemMatcher';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { IWorkspaceFolder, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
@@ -374,10 +375,13 @@ export namespace TaskSourceKind {
|
||||
export const Workspace: 'workspace' = 'workspace';
|
||||
export const Extension: 'extension' = 'extension';
|
||||
export const InMemory: 'inMemory' = 'inMemory';
|
||||
export const WorkspaceFile: 'workspaceFile' = 'workspaceFile';
|
||||
export const User: 'user' = 'user';
|
||||
}
|
||||
|
||||
export interface TaskSourceConfigElement {
|
||||
workspaceFolder: IWorkspaceFolder;
|
||||
workspace?: IWorkspace;
|
||||
file: string;
|
||||
index: number;
|
||||
element: any;
|
||||
@@ -410,8 +414,20 @@ export interface InMemoryTaskSource extends BaseTaskSource {
|
||||
readonly kind: 'inMemory';
|
||||
}
|
||||
|
||||
export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | InMemoryTaskSource;
|
||||
export interface UserTaskSource extends BaseTaskSource {
|
||||
readonly kind: 'user';
|
||||
readonly config: TaskSourceConfigElement;
|
||||
readonly customizes?: KeyedTaskIdentifier;
|
||||
}
|
||||
|
||||
export interface WorkspaceFileTaskSource extends BaseTaskSource {
|
||||
readonly kind: 'workspaceFile';
|
||||
readonly config: TaskSourceConfigElement;
|
||||
readonly customizes?: KeyedTaskIdentifier;
|
||||
}
|
||||
|
||||
export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | InMemoryTaskSource | UserTaskSource | WorkspaceFileTaskSource;
|
||||
export type FileBasedTaskSource = WorkspaceTaskSource | UserTaskSource | WorkspaceFileTaskSource;
|
||||
export interface TaskIdentifier {
|
||||
type: string;
|
||||
[name: string]: any;
|
||||
@@ -566,6 +582,10 @@ export abstract class CommonTask {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getWorkspaceFileName(): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public getTelemetryKind(): string {
|
||||
return 'unknown';
|
||||
}
|
||||
@@ -619,7 +639,7 @@ export class CustomTask extends CommonTask {
|
||||
/**
|
||||
* Indicated the source of the task (e.g. tasks.json or extension)
|
||||
*/
|
||||
_source: WorkspaceTaskSource;
|
||||
_source: FileBasedTaskSource;
|
||||
|
||||
hasDefinedMatchers: boolean;
|
||||
|
||||
@@ -628,7 +648,7 @@ export class CustomTask extends CommonTask {
|
||||
*/
|
||||
command: CommandConfiguration = {};
|
||||
|
||||
public constructor(id: string, source: WorkspaceTaskSource, label: string, type: string, command: CommandConfiguration | undefined,
|
||||
public constructor(id: string, source: FileBasedTaskSource, label: string, type: string, command: CommandConfiguration | undefined,
|
||||
hasDefinedMatchers: boolean, runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
|
||||
super(id, label, undefined, runOptions, configurationProperties, source);
|
||||
this._source = source;
|
||||
@@ -700,7 +720,11 @@ export class CustomTask extends CommonTask {
|
||||
if (!workspaceFolder) {
|
||||
return undefined;
|
||||
}
|
||||
let key: CustomKey = { type: CUSTOMIZED_TASK_TYPE, folder: workspaceFolder.uri.toString(), id: this.configurationProperties.identifier! };
|
||||
let id: string = this.configurationProperties.identifier!;
|
||||
if (this._source.kind !== TaskSourceKind.Workspace) {
|
||||
id += this._source.kind;
|
||||
}
|
||||
let key: CustomKey = { type: CUSTOMIZED_TASK_TYPE, folder: workspaceFolder.uri.toString(), id };
|
||||
return JSON.stringify(key);
|
||||
}
|
||||
|
||||
@@ -708,6 +732,10 @@ export class CustomTask extends CommonTask {
|
||||
return this._source.config.workspaceFolder;
|
||||
}
|
||||
|
||||
public getWorkspaceFileName(): string | undefined {
|
||||
return (this._source.config.workspace && this._source.config.workspace.configuration) ? resources.basename(this._source.config.workspace.configuration) : undefined;
|
||||
}
|
||||
|
||||
public getTelemetryKind(): string {
|
||||
if (this._source.customizes) {
|
||||
return 'workspace>extension';
|
||||
@@ -726,11 +754,11 @@ export class ConfiguringTask extends CommonTask {
|
||||
/**
|
||||
* Indicated the source of the task (e.g. tasks.json or extension)
|
||||
*/
|
||||
_source: WorkspaceTaskSource;
|
||||
_source: FileBasedTaskSource;
|
||||
|
||||
configures: KeyedTaskIdentifier;
|
||||
|
||||
public constructor(id: string, source: WorkspaceTaskSource, label: string | undefined, type: string | undefined,
|
||||
public constructor(id: string, source: FileBasedTaskSource, label: string | undefined, type: string | undefined,
|
||||
configures: KeyedTaskIdentifier, runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
|
||||
super(id, label, type, runOptions, configurationProperties, source);
|
||||
this._source = source;
|
||||
@@ -748,6 +776,10 @@ export class ConfiguringTask extends CommonTask {
|
||||
public getDefinition(): KeyedTaskIdentifier {
|
||||
return this.configures;
|
||||
}
|
||||
|
||||
public getWorkspaceFileName(): string | undefined {
|
||||
return (this._source.config.workspace && this._source.config.workspace.configuration) ? resources.basename(this._source.config.workspace.configuration) : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class ContributedTask extends CommonTask {
|
||||
|
||||
@@ -10,17 +10,19 @@ import * as UUID from 'vs/base/common/uuid';
|
||||
import * as Platform from 'vs/base/common/platform';
|
||||
import { ValidationStatus } from 'vs/base/common/parsers';
|
||||
import { ProblemMatcher, FileLocationKind, ProblemPattern, ApplyToKind } from 'vs/workbench/contrib/tasks/common/problemMatcher';
|
||||
import { IWorkspaceFolder, WorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { WorkspaceFolder, Workspace, IWorkspace } from 'vs/platform/workspace/common/workspace';
|
||||
|
||||
import * as Tasks from 'vs/workbench/contrib/tasks/common/tasks';
|
||||
import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask } from 'vs/workbench/contrib/tasks/common/taskConfiguration';
|
||||
import { parse, ParseResult, IProblemReporter, ExternalTaskRunnerConfiguration, CustomTask, TaskConfigSource } from 'vs/workbench/contrib/tasks/common/taskConfiguration';
|
||||
|
||||
const workspaceFolder: IWorkspaceFolder = new WorkspaceFolder({
|
||||
const workspaceFolder: WorkspaceFolder = new WorkspaceFolder({
|
||||
uri: URI.file('/workspace/folderOne'),
|
||||
name: 'folderOne',
|
||||
index: 0
|
||||
});
|
||||
|
||||
const workspace: IWorkspace = new Workspace('id', [workspaceFolder]);
|
||||
|
||||
class ProblemReporter implements IProblemReporter {
|
||||
|
||||
private _validationStatus: ValidationStatus = new ValidationStatus();
|
||||
@@ -357,7 +359,7 @@ class PatternBuilder {
|
||||
|
||||
function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, resolved: number) {
|
||||
let reporter = new ProblemReporter();
|
||||
let result = parse(workspaceFolder, Platform.platform, external, reporter);
|
||||
let result = parse(workspaceFolder, workspace, Platform.platform, external, reporter, TaskConfigSource.TasksJson);
|
||||
assert.ok(!reporter.receivedMessage);
|
||||
assert.strictEqual(result.custom.length, 1);
|
||||
let task = result.custom[0];
|
||||
@@ -368,7 +370,7 @@ function testDefaultProblemMatcher(external: ExternalTaskRunnerConfiguration, re
|
||||
function testConfiguration(external: ExternalTaskRunnerConfiguration, builder: ConfiguationBuilder): void {
|
||||
builder.done();
|
||||
let reporter = new ProblemReporter();
|
||||
let result = parse(workspaceFolder, Platform.platform, external, reporter);
|
||||
let result = parse(workspaceFolder, workspace, Platform.platform, external, reporter, TaskConfigSource.TasksJson);
|
||||
if (reporter.receivedMessage) {
|
||||
assert.ok(false, reporter.lastMessage);
|
||||
}
|
||||
@@ -1730,4 +1732,4 @@ suite('Bugs / regression tests', () => {
|
||||
runtime(Tasks.RuntimeType.Shell);
|
||||
testConfiguration(external, builder);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ export const machineSettingsSchemaId = 'vscode://schemas/settings/machine';
|
||||
export const workspaceSettingsSchemaId = 'vscode://schemas/settings/workspace';
|
||||
export const folderSettingsSchemaId = 'vscode://schemas/settings/folder';
|
||||
export const launchSchemaId = 'vscode://schemas/launch';
|
||||
export const tasksSchemaId = 'vscode://schemas/tasks';
|
||||
|
||||
export const LOCAL_MACHINE_SCOPES = [ConfigurationScope.APPLICATION, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE];
|
||||
export const REMOTE_MACHINE_SCOPES = [ConfigurationScope.MACHINE, ConfigurationScope.WINDOW, ConfigurationScope.RESOURCE, ConfigurationScope.MACHINE_OVERRIDABLE];
|
||||
|
||||
Reference in New Issue
Block a user