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:
Alex Ross
2019-09-26 11:59:20 +02:00
committed by GitHub
parent 3f38682210
commit 328869d618
6 changed files with 231 additions and 46 deletions

View File

@@ -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;

View File

@@ -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);
});

View File

@@ -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();
}

View File

@@ -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 {

View File

@@ -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);
});
});
});

View File

@@ -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];