提交 c78ebcb2 编写于 作者: D Dirk Baeumer

Fixes #27548: Annotation tasks break old 0.1.0 task behaviour

上级 b6041fbc
......@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as nls from 'vs/nls';
import { TPromise } from 'vs/base/common/winjs.base';
import * as UUID from 'vs/base/common/uuid';
import { asWinJsPromise } from 'vs/base/common/async';
......@@ -308,13 +309,16 @@ namespace Tasks {
if (command === void 0) {
return undefined;
}
let source = {
kind: TaskSystem.TaskSourceKind.Extension,
label: typeof task.source === 'string' ? task.source : extension.name,
detail: extension.id
};
let label = nls.localize('task.label', '{0}: {1}', source.label, task.name);
let result: TaskSystem.Task = {
_id: uuidMap.getUUID(task.identifier),
_source: {
kind: TaskSystem.TaskSourceKind.Extension,
label: typeof task.source === 'string' ? task.source : extension.name,
detail: extension.id
},
_source: source,
_label: label,
name: task.name,
identifier: task.identifier ? task.identifier : `${extension.id}.${task.name}`,
group: types.TaskGroup.is(task.group) ? task.group : undefined,
......
......@@ -13,21 +13,18 @@ import QuickOpen = require('vs/base/parts/quickopen/common/quickOpen');
import Model = require('vs/base/parts/quickopen/browser/quickOpenModel');
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { Task, TaskSourceKind, computeLabel } from 'vs/workbench/parts/tasks/common/tasks';
import { Task, TaskSourceKind } from 'vs/workbench/parts/tasks/common/tasks';
import { ITaskService } from 'vs/workbench/parts/tasks/common/taskService';
import { ActionBarContributor, ContributableActionProvider } from 'vs/workbench/browser/actions';
export class TaskEntry extends Model.QuickOpenEntry {
private _label: string;
constructor(protected taskService: ITaskService, protected _task: Task, highlights: Model.IHighlight[] = []) {
super(highlights);
this._label = computeLabel(_task);
}
public getLabel(): string {
return this._label;
return this.task._label;
}
public getAriaLabel(): string {
......
......@@ -301,6 +301,11 @@ export interface ExternalTaskRunnerConfiguration extends BaseTaskRunnerConfigura
_runner?: string;
/**
* Determines the runner to use
*/
runner?: string;
/**
* The config's version number
*/
......@@ -341,7 +346,8 @@ function mergeProperty<T, K extends keyof T>(target: T, source: T, key: K) {
interface ParseContext {
problemReporter: IProblemReporter;
namedProblemMatchers: IStringDictionary<NamedProblemMatcher>;
isTermnial: boolean;
engine: Tasks.ExecutionEngine;
schemaVersion: Tasks.JsonSchemaVersion;
}
namespace CommandOptions {
......@@ -587,7 +593,7 @@ namespace CommandConfiguration {
result.options = CommandOptions.from(config.options, context);
if (result.options && result.options.shell === void 0 && isShellConfiguration) {
result.options.shell = ShellConfiguration.from(config.isShellCommand as ShellConfiguration, context);
if (!context.isTermnial) {
if (context.engine !== Tasks.ExecutionEngine.Terminal) {
context.problemReporter.warn(nls.localize('ConfigurationParser.noShell', 'Warning: shell configuration is only supported when executing tasks in the terminal.'));
}
}
......@@ -776,6 +782,7 @@ namespace TaskDescription {
let annotatingTasks: Tasks.Task[] = [];
let defaultBuildTask: { task: Tasks.Task; rank: number; } = { task: undefined, rank: -1 };
let defaultTestTask: { task: Tasks.Task; rank: number; } = { task: undefined, rank: -1 };
let schema2_0_0: boolean = context.schemaVersion === Tasks.JsonSchemaVersion.V2_0_0;
tasks.forEach((externalTask) => {
let taskName = externalTask.taskName;
if (!taskName) {
......@@ -792,6 +799,7 @@ namespace TaskDescription {
let task: Tasks.Task = {
_id: UUID.generateUuid(),
_source: source,
_label: taskName,
name: taskName,
identifier: identifer,
command
......@@ -835,7 +843,7 @@ namespace TaskDescription {
if (problemMatchers) {
task.problemMatchers = problemMatchers;
}
if (context.isTermnial && isAnnotating(task)) {
if (schema2_0_0 && isAnnotating(task)) {
mergeGlobalsIntoAnnnotation(task, globals);
annotatingTasks.push(task);
return;
......@@ -843,15 +851,15 @@ namespace TaskDescription {
mergeGlobals(task, globals);
fillDefaults(task);
let addTask: boolean = true;
if (context.isTermnial && task.command && task.command.name && task.command.type === Tasks.CommandType.Shell && task.command.args && task.command.args.length > 0) {
if (context.engine === Tasks.ExecutionEngine.Terminal && task.command && task.command.name && task.command.type === Tasks.CommandType.Shell && task.command.args && task.command.args.length > 0) {
if (hasUnescapedSpaces(task.command.name) || task.command.args.some(hasUnescapedSpaces)) {
context.problemReporter.warn(nls.localize('taskConfiguration.shellArgs', 'Warning: the task \'{0}\' is a shell command and either the command name or one of its arguments has unescaped spaces. To ensure correct command line quoting please merge args into the command.', task.name));
}
}
if (context.isTermnial) {
if (schema2_0_0) {
if ((task.command === void 0 || task.command.name === void 0) && (task.dependsOn === void 0 || task.dependsOn.length === 0)) {
context.problemReporter.error(nls.localize(
'taskConfiguration.noCommandOrDependsOn', 'Error: the task \'{0}\' neither specifies a command or a dependsOn property. The task will be ignored. Its definition is:\n{1}',
'taskConfiguration.noCommandOrDependsOn', 'Error: the task \'{0}\' neither specifies a command nor a dependsOn property. The task will be ignored. Its definition is:\n{1}',
task.name, JSON.stringify(externalTask, undefined, 4)
));
addTask = false;
......@@ -1094,19 +1102,43 @@ namespace Globals {
export namespace ExecutionEngine {
export function from(config: ExternalTaskRunnerConfiguration): Tasks.ExecutionEngine {
return isTerminalConfig(config)
? Tasks.ExecutionEngine.Terminal
: isRunnerConfig(config)
? Tasks.ExecutionEngine.Process
: Tasks.ExecutionEngine.Unknown;
let runner = config.runner || config._runner;
let result: Tasks.ExecutionEngine;
if (runner) {
switch (runner) {
case 'terminal':
result = Tasks.ExecutionEngine.Terminal;
break;
case 'process':
result = Tasks.ExecutionEngine.Process;
break;
}
}
let schemaVersion = JsonSchemaVersion.from(config);
if (schemaVersion === Tasks.JsonSchemaVersion.V0_1_0) {
return result || Tasks.ExecutionEngine.Process;
} else if (schemaVersion === Tasks.JsonSchemaVersion.V2_0_0) {
return Tasks.ExecutionEngine.Terminal;
} else {
throw new Error('Shouldn\'t happen.');
}
}
function isRunnerConfig(config: ExternalTaskRunnerConfiguration): boolean {
return (!config._runner || config._runner === 'program') && (config.version === '0.1.0' || !config.version);
}
}
function isTerminalConfig(config: ExternalTaskRunnerConfiguration): boolean {
return config._runner === 'terminal' || config.version === '2.0.0';
export namespace JsonSchemaVersion {
export function from(config: ExternalTaskRunnerConfiguration): Tasks.JsonSchemaVersion {
let version = config.version;
if (!version) {
return Tasks.JsonSchemaVersion.V2_0_0;
}
switch (version) {
case '0.1.0':
return Tasks.JsonSchemaVersion.V0_1_0;
default:
return Tasks.JsonSchemaVersion.V2_0_0;
}
}
}
......@@ -1130,13 +1162,15 @@ class ConfigurationParser {
public run(fileConfig: ExternalTaskRunnerConfiguration): ParseResult {
let engine = ExecutionEngine.from(fileConfig);
let schemaVersion = JsonSchemaVersion.from(fileConfig);
if (engine === Tasks.ExecutionEngine.Terminal) {
this.problemReporter.clearOutput();
}
let context: ParseContext = {
problemReporter: this.problemReporter,
namedProblemMatchers: undefined,
isTermnial: engine === Tasks.ExecutionEngine.Terminal
engine,
schemaVersion,
};
let taskParseResult = this.createTaskRunnerConfiguration(fileConfig, context);
return {
......@@ -1177,6 +1211,7 @@ class ConfigurationParser {
let task: Tasks.Task = {
_id: UUID.generateUuid(),
_source: TaskDescription.source,
_label: globals.command.name,
name: globals.command.name,
identifier: globals.command.name,
group: Tasks.TaskGroup.Build,
......
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import nls = require('vs/nls');
import * as Types from 'vs/base/common/types';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
......@@ -183,6 +182,11 @@ export interface Task {
*/
_id: string;
/**
* The cached label.
*/
_label: string;
/**
* Indicated the source of the task (e.g tasks.json or extension)
*/
......@@ -241,20 +245,16 @@ export interface Task {
}
export enum ExecutionEngine {
Unknown = 0,
Terminal = 1,
Process = 2
Process = 1,
Terminal = 2
}
export enum JsonSchemaVersion {
V0_1_0 = 1,
V2_0_0 = 2
}
export interface TaskSet {
tasks: Task[];
extension?: IExtensionDescription;
}
export function computeLabel(task: Task): string {
if (task._source.kind === TaskSourceKind.Extension) {
return nls.localize('taskEntry.label', '{0}: {1}', task._source.label, task.name);
} else {
return task.name;
}
}
\ No newline at end of file
......@@ -13,32 +13,41 @@ import commonSchema from './jsonSchemaCommon';
const schema: IJSONSchema = {
oneOf: [
{
'allOf': [
allOf: [
{
'type': 'object',
'required': ['version'],
'properties': {
'version': {
'type': 'string',
'enum': ['0.1.0'],
'description': nls.localize('JsonSchema.version', 'The config\'s version number')
type: 'object',
required: ['version'],
properties: {
version: {
type: 'string',
enum: ['0.1.0'],
description: nls.localize('JsonSchema.version', 'The config\'s version number')
},
'windows': {
'$ref': '#/definitions/taskRunnerConfiguration',
'description': nls.localize('JsonSchema.windows', 'Windows specific command configuration')
_runner: {
deprecationMessage: nls.localize('JsonSchema._runner', 'The runner has graduated. Use the offical runner property')
},
'osx': {
'$ref': '#/definitions/taskRunnerConfiguration',
'description': nls.localize('JsonSchema.mac', 'Mac specific command configuration')
runner: {
type: 'string',
enum: ['process', 'terminal'],
default: 'process',
description: nls.localize('JsonSchema.runner', 'Defines whether the task is executed as a process and the output is shown in the output window or inside the terminal.')
},
'linux': {
'$ref': '#/definitions/taskRunnerConfiguration',
'description': nls.localize('JsonSchema.linux', 'Linux specific command configuration')
windows: {
$ref: '#/definitions/taskRunnerConfiguration',
description: nls.localize('JsonSchema.windows', 'Windows specific command configuration')
},
osx: {
$ref: '#/definitions/taskRunnerConfiguration',
description: nls.localize('JsonSchema.mac', 'Mac specific command configuration')
},
linux: {
$ref: '#/definitions/taskRunnerConfiguration',
description: nls.localize('JsonSchema.linux', 'Linux specific command configuration')
}
}
},
{
'$ref': '#/definitions/taskRunnerConfiguration'
$ref: '#/definitions/taskRunnerConfiguration'
}
]
}
......
......@@ -71,7 +71,7 @@ import { Scope, IActionBarRegistry, Extensions as ActionBarExtensions } from 'vs
import { ITerminalService } from 'vs/workbench/parts/terminal/common/terminal';
import { ITaskSystem, ITaskResolver, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, TaskSystemEvents } from 'vs/workbench/parts/tasks/common/taskSystem';
import { Task, TaskSet, TaskGroup, ExecutionEngine, TaskSourceKind, computeLabel as computeTaskLabel } from 'vs/workbench/parts/tasks/common/tasks';
import { Task, TaskSet, TaskGroup, ExecutionEngine, TaskSourceKind } from 'vs/workbench/parts/tasks/common/tasks';
import { ITaskService, TaskServiceEvents, ITaskProvider } from 'vs/workbench/parts/tasks/common/taskService';
import { templates as taskTemplates } from 'vs/workbench/parts/tasks/common/taskTemplates';
......@@ -455,7 +455,7 @@ interface WorkspaceTaskResult {
set: TaskSet;
annotatingTasks: {
byIdentifier: IStringDictionary<Task>;
byName: IStringDictionary<Task>;
byLabel: IStringDictionary<Task>;
};
hasErrors: boolean;
}
......@@ -547,7 +547,7 @@ class TaskService extends EventEmitter implements ITaskService {
? ExecutionEngine.Terminal
: this._taskSystem instanceof ProcessTaskSystem
? ExecutionEngine.Process
: ExecutionEngine.Unknown;
: undefined;
if (currentExecutionEngine !== this.getExecutionEngine()) {
this.messageService.show(Severity.Info, nls.localize('TaskSystem.noHotSwap', 'Changing the task execution engine requires restarting VS Code. The change is ignored.'));
}
......@@ -709,7 +709,7 @@ class TaskService extends EventEmitter implements ITaskService {
return TPromise.as<void>(undefined);
}
let fileConfig = configuration.config;
let customize = { taskName: computeTaskLabel(task), identifier: task.identifier };
let customize = { taskName: task._label, identifier: task.identifier };
if (!fileConfig) {
fileConfig = {
version: '2.0.0',
......@@ -746,7 +746,7 @@ class TaskService extends EventEmitter implements ITaskService {
sets.forEach((set) => {
set.tasks.forEach((task) => {
uuidMap[task._id] = task;
labelMap[computeTaskLabel(task)] = task;
labelMap[task._label] = task;
identifierMap[task.identifier] = task;
if (group && task.group === group) {
if (task._source.kind === TaskSourceKind.Workspace) {
......@@ -779,6 +779,7 @@ class TaskService extends EventEmitter implements ITaskService {
let task: Task = {
_id: id,
_source: { kind: TaskSourceKind.Generic, label: 'generic' },
_label: id,
name: id,
identifier: id,
dependsOn: extensionTasks.map(task => task._id),
......@@ -794,7 +795,7 @@ class TaskService extends EventEmitter implements ITaskService {
sets.forEach((set) => {
set.tasks.forEach((task) => {
labelMap[computeTaskLabel(task)] = task;
labelMap[task._label] = task;
identifierMap[task.identifier] = task;
});
});
......@@ -922,10 +923,11 @@ class TaskService extends EventEmitter implements ITaskService {
for (let set of result) {
for (let task of set.tasks) {
if (annotatingTasks) {
let annotatingTask = annotatingTasks.byIdentifier[task.identifier] || annotatingTasks.byName[task.name];
let annotatingTask = annotatingTasks.byIdentifier[task.identifier] || annotatingTasks.byLabel[task._label];
if (annotatingTask) {
TaskConfig.mergeTasks(task, annotatingTask);
task.name = annotatingTask.name;
task._label = annotatingTask._label;
task._source.kind = TaskSourceKind.Workspace;
continue;
}
......@@ -936,6 +938,7 @@ class TaskService extends EventEmitter implements ITaskService {
TaskConfig.mergeTasks(task, legacyAnnotatingTask);
task._source.kind = TaskSourceKind.Workspace;
task.name = legacyAnnotatingTask.name;
task._label = legacyAnnotatingTask._label;
workspaceTasksToDelete.push(legacyAnnotatingTask);
continue;
}
......@@ -1015,29 +1018,36 @@ class TaskService extends EventEmitter implements ITaskService {
}
if (config) {
let engine = TaskConfig.ExecutionEngine.from(config);
if (engine === ExecutionEngine.Process && this.hasDetectorSupport(config)) {
configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService, config).detect(true).then((value): WorkspaceConfigurationResult => {
let hasErrors = this.printStderr(value.stderr);
let detectedConfig = value.config;
if (!detectedConfig) {
return { config, hasErrors };
}
let result: TaskConfig.ExternalTaskRunnerConfiguration = Objects.clone(config);
let configuredTasks: IStringDictionary<TaskConfig.TaskDescription> = Object.create(null);
if (!result.tasks) {
if (detectedConfig.tasks) {
result.tasks = detectedConfig.tasks;
if (engine === ExecutionEngine.Process) {
if (this.hasDetectorSupport(config)) {
configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService, config).detect(true).then((value): WorkspaceConfigurationResult => {
let hasErrors = this.printStderr(value.stderr);
let detectedConfig = value.config;
if (!detectedConfig) {
return { config, hasErrors };
}
} else {
result.tasks.forEach(task => configuredTasks[task.taskName] = task);
detectedConfig.tasks.forEach((task) => {
if (!configuredTasks[task.taskName]) {
result.tasks.push(task);
let result: TaskConfig.ExternalTaskRunnerConfiguration = Objects.clone(config);
let configuredTasks: IStringDictionary<TaskConfig.TaskDescription> = Object.create(null);
if (!result.tasks) {
if (detectedConfig.tasks) {
result.tasks = detectedConfig.tasks;
}
});
}
return { config: result, hasErrors };
});
} else {
result.tasks.forEach(task => configuredTasks[task.taskName] = task);
detectedConfig.tasks.forEach((task) => {
if (!configuredTasks[task.taskName]) {
result.tasks.push(task);
}
});
}
return { config: result, hasErrors };
});
} else {
configPromise = new ProcessRunnerDetector(this.fileService, this.contextService, this.configurationResolverService).detect(true).then((value) => {
let hasErrors = this.printStderr(value.stderr);
return { config: value.config, hasErrors };
});
}
} else {
configPromise = TPromise.as({ config, hasErrors: false });
}
......@@ -1061,16 +1071,16 @@ class TaskService extends EventEmitter implements ITaskService {
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 { set: undefined, annotatingTasks: undefined, hasErrors };
}
let annotatingTasks: { byIdentifier: IStringDictionary<Task>; byName: IStringDictionary<Task>; };
let annotatingTasks: { byIdentifier: IStringDictionary<Task>; byLabel: IStringDictionary<Task>; };
if (parseResult.annotatingTasks && parseResult.annotatingTasks.length > 0) {
annotatingTasks = {
byIdentifier: Object.create(null),
byName: Object.create(null)
byLabel: Object.create(null)
};
for (let task of parseResult.annotatingTasks) {
annotatingTasks.byIdentifier[task.identifier] = task;
if (task.name) {
annotatingTasks.byName[task.name] = task;
if (task._label) {
annotatingTasks.byLabel[task._label] = task;
}
}
}
......@@ -1087,6 +1097,16 @@ class TaskService extends EventEmitter implements ITaskService {
return TaskConfig.ExecutionEngine.from(config);
}
/*
private getJsonSchemaVersion(): JsonSchemaVersion {
let { config } = this.getConfiguration();
if (!config) {
return JsonSchemaVersion.V2_0_0;
}
return TaskConfig.JsonSchemaVersion.from(config);
}
*/
private getConfiguration(): { config: TaskConfig.ExternalTaskRunnerConfiguration; hasParseErrors: boolean } {
let result = this.configurationService.getConfiguration<TaskConfig.ExternalTaskRunnerConfiguration>('tasks');
if (!result) {
......
......@@ -145,6 +145,7 @@ class TaskBuilder {
this.result = {
_id: name,
_source: { kind: Tasks.TaskSourceKind.Workspace, label: 'workspace' },
_label: name,
identifier: name,
name: name,
command: this.commandBuilder.result,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册