mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-27 15:20:30 -04:00
999 lines
24 KiB
TypeScript
999 lines
24 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import * as nls from 'vs/nls';
|
|
import * as Types from 'vs/base/common/types';
|
|
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 { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
|
|
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
|
import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry';
|
|
|
|
export const TASK_RUNNING_STATE = new RawContextKey<boolean>('taskRunning', false);
|
|
|
|
export enum ShellQuoting {
|
|
/**
|
|
* Use character escaping.
|
|
*/
|
|
Escape = 1,
|
|
|
|
/**
|
|
* Use strong quoting
|
|
*/
|
|
Strong = 2,
|
|
|
|
/**
|
|
* Use weak quoting.
|
|
*/
|
|
Weak = 3,
|
|
}
|
|
|
|
export const CUSTOMIZED_TASK_TYPE = '$customized';
|
|
|
|
export namespace ShellQuoting {
|
|
export function from(this: void, value: string): ShellQuoting {
|
|
if (!value) {
|
|
return ShellQuoting.Strong;
|
|
}
|
|
switch (value.toLowerCase()) {
|
|
case 'escape':
|
|
return ShellQuoting.Escape;
|
|
case 'strong':
|
|
return ShellQuoting.Strong;
|
|
case 'weak':
|
|
return ShellQuoting.Weak;
|
|
default:
|
|
return ShellQuoting.Strong;
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface ShellQuotingOptions {
|
|
/**
|
|
* The character used to do character escaping.
|
|
*/
|
|
escape?: string | {
|
|
escapeChar: string;
|
|
charsToEscape: string;
|
|
};
|
|
|
|
/**
|
|
* The character used for string quoting.
|
|
*/
|
|
strong?: string;
|
|
|
|
/**
|
|
* The character used for weak quoting.
|
|
*/
|
|
weak?: string;
|
|
}
|
|
|
|
export interface ShellConfiguration {
|
|
/**
|
|
* The shell executable.
|
|
*/
|
|
executable?: string;
|
|
|
|
/**
|
|
* The arguments to be passed to the shell executable.
|
|
*/
|
|
args?: string[];
|
|
|
|
/**
|
|
* Which kind of quotes the shell supports.
|
|
*/
|
|
quoting?: ShellQuotingOptions;
|
|
}
|
|
|
|
export interface CommandOptions {
|
|
|
|
/**
|
|
* The shell to use if the task is a shell command.
|
|
*/
|
|
shell?: ShellConfiguration;
|
|
|
|
/**
|
|
* The current working directory of the executed program or shell.
|
|
* If omitted VSCode's current workspace root is used.
|
|
*/
|
|
cwd?: string;
|
|
|
|
/**
|
|
* The environment of the executed program or shell. If omitted
|
|
* the parent process' environment is used.
|
|
*/
|
|
env?: { [key: string]: string; };
|
|
}
|
|
|
|
export namespace CommandOptions {
|
|
export const defaults: CommandOptions = { cwd: '${workspaceFolder}' };
|
|
}
|
|
|
|
export enum RevealKind {
|
|
/**
|
|
* Always brings the terminal to front if the task is executed.
|
|
*/
|
|
Always = 1,
|
|
|
|
/**
|
|
* Only brings the terminal to front if a problem is detected executing the task
|
|
* (e.g. the task couldn't be started because).
|
|
*/
|
|
Silent = 2,
|
|
|
|
/**
|
|
* The terminal never comes to front when the task is executed.
|
|
*/
|
|
Never = 3
|
|
}
|
|
|
|
export namespace RevealKind {
|
|
export function fromString(this: void, value: string): RevealKind {
|
|
switch (value.toLowerCase()) {
|
|
case 'always':
|
|
return RevealKind.Always;
|
|
case 'silent':
|
|
return RevealKind.Silent;
|
|
case 'never':
|
|
return RevealKind.Never;
|
|
default:
|
|
return RevealKind.Always;
|
|
}
|
|
}
|
|
}
|
|
|
|
export enum PanelKind {
|
|
|
|
/**
|
|
* Shares a panel with other tasks. This is the default.
|
|
*/
|
|
Shared = 1,
|
|
|
|
/**
|
|
* Uses a dedicated panel for this tasks. The panel is not
|
|
* shared with other tasks.
|
|
*/
|
|
Dedicated = 2,
|
|
|
|
/**
|
|
* Creates a new panel whenever this task is executed.
|
|
*/
|
|
New = 3
|
|
}
|
|
|
|
export namespace PanelKind {
|
|
export function fromString(value: string): PanelKind {
|
|
switch (value.toLowerCase()) {
|
|
case 'shared':
|
|
return PanelKind.Shared;
|
|
case 'dedicated':
|
|
return PanelKind.Dedicated;
|
|
case 'new':
|
|
return PanelKind.New;
|
|
default:
|
|
return PanelKind.Shared;
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface PresentationOptions {
|
|
/**
|
|
* Controls whether the task output is reveal in the user interface.
|
|
* Defaults to `RevealKind.Always`.
|
|
*/
|
|
reveal: RevealKind;
|
|
|
|
/**
|
|
* Controls whether the command associated with the task is echoed
|
|
* in the user interface.
|
|
*/
|
|
echo: boolean;
|
|
|
|
/**
|
|
* Controls whether the panel showing the task output is taking focus.
|
|
*/
|
|
focus: boolean;
|
|
|
|
/**
|
|
* Controls if the task panel is used for this task only (dedicated),
|
|
* shared between tasks (shared) or if a new panel is created on
|
|
* every task execution (new). Defaults to `TaskInstanceKind.Shared`
|
|
*/
|
|
panel: PanelKind;
|
|
|
|
/**
|
|
* Controls whether to show the "Terminal will be reused by tasks, press any key to close it" message.
|
|
*/
|
|
showReuseMessage: boolean;
|
|
|
|
/**
|
|
* Controls whether to clear the terminal before executing the task.
|
|
*/
|
|
clear: boolean;
|
|
|
|
/**
|
|
* Controls whether the task is executed in a specific terminal group using split panes.
|
|
*/
|
|
group?: string;
|
|
}
|
|
|
|
export namespace PresentationOptions {
|
|
export const defaults: PresentationOptions = {
|
|
echo: true, reveal: RevealKind.Always, focus: false, panel: PanelKind.Shared, showReuseMessage: true, clear: false
|
|
};
|
|
}
|
|
|
|
export enum RuntimeType {
|
|
Shell = 1,
|
|
Process = 2,
|
|
CustomExecution = 3
|
|
}
|
|
|
|
export namespace RuntimeType {
|
|
export function fromString(value: string): RuntimeType {
|
|
switch (value.toLowerCase()) {
|
|
case 'shell':
|
|
return RuntimeType.Shell;
|
|
case 'process':
|
|
return RuntimeType.Process;
|
|
case 'customExecution':
|
|
return RuntimeType.CustomExecution;
|
|
default:
|
|
return RuntimeType.Process;
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface QuotedString {
|
|
value: string;
|
|
quoting: ShellQuoting;
|
|
}
|
|
|
|
export type CommandString = string | QuotedString;
|
|
|
|
export namespace CommandString {
|
|
export function value(value: CommandString): string {
|
|
if (Types.isString(value)) {
|
|
return value;
|
|
} else {
|
|
return value.value;
|
|
}
|
|
}
|
|
}
|
|
|
|
export interface CommandConfiguration {
|
|
|
|
/**
|
|
* The task type
|
|
*/
|
|
runtime?: RuntimeType;
|
|
|
|
/**
|
|
* The command to execute
|
|
*/
|
|
name?: CommandString;
|
|
|
|
/**
|
|
* Additional command options.
|
|
*/
|
|
options?: CommandOptions;
|
|
|
|
/**
|
|
* Command arguments.
|
|
*/
|
|
args?: CommandString[];
|
|
|
|
/**
|
|
* The task selector if needed.
|
|
*/
|
|
taskSelector?: string;
|
|
|
|
/**
|
|
* Whether to suppress the task name when merging global args
|
|
*
|
|
*/
|
|
suppressTaskName?: boolean;
|
|
|
|
/**
|
|
* Describes how the task is presented in the UI.
|
|
*/
|
|
presentation?: PresentationOptions;
|
|
}
|
|
|
|
export namespace TaskGroup {
|
|
export const Clean: 'clean' = 'clean';
|
|
|
|
export const Build: 'build' = 'build';
|
|
|
|
export const Rebuild: 'rebuild' = 'rebuild';
|
|
|
|
export const Test: 'test' = 'test';
|
|
|
|
export function is(value: string): value is string {
|
|
return value === Clean || value === Build || value === Rebuild || value === Test;
|
|
}
|
|
}
|
|
|
|
export type TaskGroup = 'clean' | 'build' | 'rebuild' | 'test';
|
|
|
|
|
|
export const enum TaskScope {
|
|
Global = 1,
|
|
Workspace = 2,
|
|
Folder = 3
|
|
}
|
|
|
|
export namespace TaskSourceKind {
|
|
export const Workspace: 'workspace' = 'workspace';
|
|
export const Extension: 'extension' = 'extension';
|
|
export const InMemory: 'inMemory' = 'inMemory';
|
|
}
|
|
|
|
export interface TaskSourceConfigElement {
|
|
workspaceFolder: IWorkspaceFolder;
|
|
file: string;
|
|
index: number;
|
|
element: any;
|
|
}
|
|
|
|
interface BaseTaskSource {
|
|
readonly kind: string;
|
|
readonly label: string;
|
|
}
|
|
|
|
export interface WorkspaceTaskSource extends BaseTaskSource {
|
|
readonly kind: 'workspace';
|
|
readonly config: TaskSourceConfigElement;
|
|
readonly customizes?: KeyedTaskIdentifier;
|
|
}
|
|
|
|
export interface ExtensionTaskSource extends BaseTaskSource {
|
|
readonly kind: 'extension';
|
|
readonly extension?: string;
|
|
readonly scope: TaskScope;
|
|
readonly workspaceFolder: IWorkspaceFolder | undefined;
|
|
}
|
|
|
|
export interface ExtensionTaskSourceTransfer {
|
|
__workspaceFolder: UriComponents;
|
|
__definition: { type: string;[name: string]: any };
|
|
}
|
|
|
|
export interface InMemoryTaskSource extends BaseTaskSource {
|
|
readonly kind: 'inMemory';
|
|
}
|
|
|
|
export type TaskSource = WorkspaceTaskSource | ExtensionTaskSource | InMemoryTaskSource;
|
|
|
|
export interface TaskIdentifier {
|
|
type: string;
|
|
[name: string]: any;
|
|
}
|
|
|
|
export interface KeyedTaskIdentifier extends TaskIdentifier {
|
|
_key: string;
|
|
}
|
|
|
|
export interface TaskDependency {
|
|
workspaceFolder: IWorkspaceFolder;
|
|
task: string | KeyedTaskIdentifier | undefined;
|
|
}
|
|
|
|
export const enum GroupType {
|
|
default = 'default',
|
|
user = 'user'
|
|
}
|
|
|
|
export interface ConfigurationProperties {
|
|
|
|
/**
|
|
* The task's name
|
|
*/
|
|
name?: string;
|
|
|
|
/**
|
|
* The task's name
|
|
*/
|
|
identifier?: string;
|
|
|
|
/**
|
|
* the task's group;
|
|
*/
|
|
group?: string;
|
|
|
|
/**
|
|
* The group type
|
|
*/
|
|
groupType?: GroupType;
|
|
|
|
/**
|
|
* The presentation options
|
|
*/
|
|
presentation?: PresentationOptions;
|
|
|
|
/**
|
|
* The command options;
|
|
*/
|
|
options?: CommandOptions;
|
|
|
|
/**
|
|
* Whether the task is a background task or not.
|
|
*/
|
|
isBackground?: boolean;
|
|
|
|
/**
|
|
* Whether the task should prompt on close for confirmation if running.
|
|
*/
|
|
promptOnClose?: boolean;
|
|
|
|
/**
|
|
* The other tasks this task depends on.
|
|
*/
|
|
dependsOn?: TaskDependency[];
|
|
|
|
/**
|
|
* The problem watchers to use for this task
|
|
*/
|
|
problemMatchers?: Array<string | ProblemMatcher>;
|
|
}
|
|
|
|
export enum RunOnOptions {
|
|
default = 1,
|
|
folderOpen = 2
|
|
}
|
|
|
|
export interface RunOptions {
|
|
reevaluateOnRerun?: boolean;
|
|
runOn?: RunOnOptions;
|
|
}
|
|
|
|
export namespace RunOptions {
|
|
export const defaults: RunOptions = { reevaluateOnRerun: true, runOn: RunOnOptions.default };
|
|
}
|
|
|
|
export abstract class CommonTask {
|
|
|
|
/**
|
|
* The task's internal id
|
|
*/
|
|
_id: string;
|
|
|
|
/**
|
|
* The cached label.
|
|
*/
|
|
_label: string;
|
|
|
|
type?: string;
|
|
|
|
runOptions: RunOptions;
|
|
|
|
configurationProperties: ConfigurationProperties;
|
|
|
|
_source: BaseTaskSource;
|
|
|
|
private _taskLoadMessages: string[] | undefined;
|
|
|
|
protected constructor(id: string, label: string | undefined, type: string | undefined, runOptions: RunOptions,
|
|
configurationProperties: ConfigurationProperties, source: BaseTaskSource) {
|
|
this._id = id;
|
|
if (label) {
|
|
this._label = label;
|
|
}
|
|
if (type) {
|
|
this.type = type;
|
|
}
|
|
this.runOptions = runOptions;
|
|
this.configurationProperties = configurationProperties;
|
|
this._source = source;
|
|
}
|
|
|
|
public getDefinition(useSource?: boolean): KeyedTaskIdentifier | undefined {
|
|
return undefined;
|
|
}
|
|
|
|
public getMapKey(): string {
|
|
return this._id;
|
|
}
|
|
|
|
public getRecentlyUsedKey(): string | undefined {
|
|
return undefined;
|
|
}
|
|
|
|
public clone(): Task {
|
|
return this.fromObject(Objects.assign({}, <any>this));
|
|
}
|
|
|
|
protected abstract fromObject(object: any): Task;
|
|
|
|
public getWorkspaceFolder(): IWorkspaceFolder | undefined {
|
|
return undefined;
|
|
}
|
|
|
|
public getTelemetryKind(): string {
|
|
return 'unknown';
|
|
}
|
|
|
|
public matches(key: string | KeyedTaskIdentifier | undefined, compareId: boolean = false): boolean {
|
|
if (key === undefined) {
|
|
return false;
|
|
}
|
|
if (Types.isString(key)) {
|
|
return key === this._label || key === this.configurationProperties.identifier || (compareId && key === this._id);
|
|
}
|
|
let identifier = this.getDefinition(true);
|
|
return identifier !== undefined && identifier._key === key._key;
|
|
}
|
|
|
|
public getQualifiedLabel(): string {
|
|
let workspaceFolder = this.getWorkspaceFolder();
|
|
if (workspaceFolder) {
|
|
return `${this._label} (${workspaceFolder.name})`;
|
|
} else {
|
|
return this._label;
|
|
}
|
|
}
|
|
|
|
public getTaskExecution(): TaskExecution {
|
|
let result: TaskExecution = {
|
|
id: this._id,
|
|
task: <any>this
|
|
};
|
|
return result;
|
|
}
|
|
|
|
public addTaskLoadMessages(messages: string[] | undefined) {
|
|
if (this._taskLoadMessages === undefined) {
|
|
this._taskLoadMessages = [];
|
|
}
|
|
if (messages) {
|
|
this._taskLoadMessages = this._taskLoadMessages.concat(messages);
|
|
}
|
|
}
|
|
|
|
get taskLoadMessages(): string[] | undefined {
|
|
return this._taskLoadMessages;
|
|
}
|
|
}
|
|
|
|
export class CustomTask extends CommonTask {
|
|
|
|
type: '$customized'; // CUSTOMIZED_TASK_TYPE
|
|
|
|
/**
|
|
* Indicated the source of the task (e.g tasks.json or extension)
|
|
*/
|
|
_source: WorkspaceTaskSource;
|
|
|
|
hasDefinedMatchers: boolean;
|
|
|
|
/**
|
|
* The command configuration
|
|
*/
|
|
command: CommandConfiguration;
|
|
|
|
public constructor(id: string, source: WorkspaceTaskSource, label: string, type: string, command: CommandConfiguration | undefined,
|
|
hasDefinedMatchers: boolean, runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
|
|
super(id, label, undefined, runOptions, configurationProperties, source);
|
|
this._source = source;
|
|
this.hasDefinedMatchers = hasDefinedMatchers;
|
|
if (command) {
|
|
this.command = command;
|
|
}
|
|
}
|
|
|
|
public customizes(): KeyedTaskIdentifier | undefined {
|
|
if (this._source && this._source.customizes) {
|
|
return this._source.customizes;
|
|
}
|
|
return undefined;
|
|
}
|
|
|
|
public getDefinition(useSource: boolean = false): KeyedTaskIdentifier {
|
|
if (useSource && this._source.customizes !== undefined) {
|
|
return this._source.customizes;
|
|
} else {
|
|
let type: string;
|
|
const commandRuntime = this.command ? this.command.runtime : undefined;
|
|
switch (commandRuntime) {
|
|
case RuntimeType.Shell:
|
|
type = 'shell';
|
|
break;
|
|
|
|
case RuntimeType.Process:
|
|
type = 'process';
|
|
break;
|
|
|
|
case RuntimeType.CustomExecution:
|
|
type = 'customExecution';
|
|
break;
|
|
|
|
case undefined:
|
|
type = '$composite';
|
|
break;
|
|
|
|
default:
|
|
throw new Error('Unexpected task runtime');
|
|
}
|
|
|
|
let result: KeyedTaskIdentifier = {
|
|
type,
|
|
_key: this._id,
|
|
id: this._id
|
|
};
|
|
return result;
|
|
}
|
|
}
|
|
|
|
public static is(value: any): value is CustomTask {
|
|
return value instanceof CustomTask;
|
|
}
|
|
|
|
public getMapKey(): string {
|
|
let workspaceFolder = this._source.config.workspaceFolder;
|
|
return workspaceFolder ? `${workspaceFolder.uri.toString()}|${this._id}` : this._id;
|
|
}
|
|
|
|
public getRecentlyUsedKey(): string | undefined {
|
|
interface CustomKey {
|
|
type: string;
|
|
folder: string;
|
|
id: string;
|
|
}
|
|
let workspaceFolder = this._source.config.workspaceFolder;
|
|
if (!workspaceFolder) {
|
|
return undefined;
|
|
}
|
|
let key: CustomKey = { type: CUSTOMIZED_TASK_TYPE, folder: workspaceFolder.uri.toString(), id: this.configurationProperties.identifier! };
|
|
return JSON.stringify(key);
|
|
}
|
|
|
|
public getWorkspaceFolder(): IWorkspaceFolder {
|
|
return this._source.config.workspaceFolder;
|
|
}
|
|
|
|
public getTelemetryKind(): string {
|
|
if (this._source.customizes) {
|
|
return 'workspace>extension';
|
|
} else {
|
|
return 'workspace';
|
|
}
|
|
}
|
|
|
|
protected fromObject(object: CustomTask): CustomTask {
|
|
return new CustomTask(object._id, object._source, object._label, object.type, object.command, object.hasDefinedMatchers, object.runOptions, object.configurationProperties);
|
|
}
|
|
}
|
|
|
|
export class ConfiguringTask extends CommonTask {
|
|
|
|
/**
|
|
* Indicated the source of the task (e.g tasks.json or extension)
|
|
*/
|
|
_source: WorkspaceTaskSource;
|
|
|
|
configures: KeyedTaskIdentifier;
|
|
|
|
public constructor(id: string, source: WorkspaceTaskSource, label: string | undefined, type: string | undefined,
|
|
configures: KeyedTaskIdentifier, runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
|
|
super(id, label, type, runOptions, configurationProperties, source);
|
|
this._source = source;
|
|
this.configures = configures;
|
|
}
|
|
|
|
public static is(value: any): value is ConfiguringTask {
|
|
return value instanceof ConfiguringTask;
|
|
}
|
|
|
|
protected fromObject(object: any): Task {
|
|
return object;
|
|
}
|
|
|
|
}
|
|
|
|
export class ContributedTask extends CommonTask {
|
|
|
|
/**
|
|
* Indicated the source of the task (e.g tasks.json or extension)
|
|
*/
|
|
_source: ExtensionTaskSource;
|
|
|
|
defines: KeyedTaskIdentifier;
|
|
|
|
hasDefinedMatchers: boolean;
|
|
|
|
/**
|
|
* The command configuration
|
|
*/
|
|
command: CommandConfiguration;
|
|
|
|
public constructor(id: string, source: ExtensionTaskSource, label: string, type: string | undefined, defines: KeyedTaskIdentifier,
|
|
command: CommandConfiguration, hasDefinedMatchers: boolean, runOptions: RunOptions,
|
|
configurationProperties: ConfigurationProperties) {
|
|
super(id, label, type, runOptions, configurationProperties, source);
|
|
this.defines = defines;
|
|
this.hasDefinedMatchers = hasDefinedMatchers;
|
|
this.command = command;
|
|
}
|
|
|
|
public getDefinition(): KeyedTaskIdentifier {
|
|
return this.defines;
|
|
}
|
|
|
|
public static is(value: any): value is ContributedTask {
|
|
return value instanceof ContributedTask;
|
|
}
|
|
|
|
public getMapKey(): string {
|
|
let workspaceFolder = this._source.workspaceFolder;
|
|
return workspaceFolder
|
|
? `${this._source.scope.toString()}|${workspaceFolder.uri.toString()}|${this._id}`
|
|
: `${this._source.scope.toString()}|${this._id}`;
|
|
}
|
|
|
|
public getRecentlyUsedKey(): string | undefined {
|
|
interface ContributedKey {
|
|
type: string;
|
|
scope: number;
|
|
folder?: string;
|
|
id: string;
|
|
}
|
|
|
|
let key: ContributedKey = { type: 'contributed', scope: this._source.scope, id: this._id };
|
|
if (this._source.scope === TaskScope.Folder && this._source.workspaceFolder) {
|
|
key.folder = this._source.workspaceFolder.uri.toString();
|
|
}
|
|
return JSON.stringify(key);
|
|
}
|
|
|
|
public getWorkspaceFolder(): IWorkspaceFolder | undefined {
|
|
return this._source.workspaceFolder;
|
|
}
|
|
|
|
public getTelemetryKind(): string {
|
|
return 'extension';
|
|
}
|
|
|
|
protected fromObject(object: ContributedTask): ContributedTask {
|
|
return new ContributedTask(object._id, object._source, object._label, object.type, object.defines, object.command, object.hasDefinedMatchers, object.runOptions, object.configurationProperties);
|
|
}
|
|
}
|
|
|
|
export class InMemoryTask extends CommonTask {
|
|
/**
|
|
* Indicated the source of the task (e.g tasks.json or extension)
|
|
*/
|
|
_source: InMemoryTaskSource;
|
|
|
|
type: 'inMemory';
|
|
|
|
public constructor(id: string, source: InMemoryTaskSource, label: string, type: string,
|
|
runOptions: RunOptions, configurationProperties: ConfigurationProperties) {
|
|
super(id, label, type, runOptions, configurationProperties, source);
|
|
this._source = source;
|
|
}
|
|
|
|
public static is(value: any): value is InMemoryTask {
|
|
return value instanceof InMemoryTask;
|
|
}
|
|
|
|
public getTelemetryKind(): string {
|
|
return 'composite';
|
|
}
|
|
|
|
protected fromObject(object: InMemoryTask): InMemoryTask {
|
|
return new InMemoryTask(object._id, object._source, object._label, object.type, object.runOptions, object.configurationProperties);
|
|
}
|
|
}
|
|
|
|
export type Task = CustomTask | ContributedTask | InMemoryTask;
|
|
|
|
export interface TaskExecution {
|
|
id: string;
|
|
task: Task;
|
|
}
|
|
|
|
export enum ExecutionEngine {
|
|
Process = 1,
|
|
Terminal = 2
|
|
}
|
|
|
|
export namespace ExecutionEngine {
|
|
export const _default: ExecutionEngine = ExecutionEngine.Terminal;
|
|
}
|
|
|
|
export const enum JsonSchemaVersion {
|
|
V0_1_0 = 1,
|
|
V2_0_0 = 2
|
|
}
|
|
|
|
export interface TaskSet {
|
|
tasks: Task[];
|
|
extension?: IExtensionDescription;
|
|
}
|
|
|
|
export interface TaskDefinition {
|
|
extensionId: string;
|
|
taskType: string;
|
|
required: string[];
|
|
properties: IJSONSchemaMap;
|
|
}
|
|
|
|
export class TaskSorter {
|
|
|
|
private _order: Map<string, number> = new Map();
|
|
|
|
constructor(workspaceFolders: IWorkspaceFolder[]) {
|
|
for (let i = 0; i < workspaceFolders.length; i++) {
|
|
this._order.set(workspaceFolders[i].uri.toString(), i);
|
|
}
|
|
}
|
|
|
|
public compare(a: Task, b: Task): number {
|
|
let aw = a.getWorkspaceFolder();
|
|
let bw = b.getWorkspaceFolder();
|
|
if (aw && bw) {
|
|
let ai = this._order.get(aw.uri.toString());
|
|
ai = ai === undefined ? 0 : ai + 1;
|
|
let bi = this._order.get(bw.uri.toString());
|
|
bi = bi === undefined ? 0 : bi + 1;
|
|
if (ai === bi) {
|
|
return a._label.localeCompare(b._label);
|
|
} else {
|
|
return ai - bi;
|
|
}
|
|
} else if (!aw && bw) {
|
|
return -1;
|
|
} else if (aw && !bw) {
|
|
return +1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
export const enum TaskEventKind {
|
|
DependsOnStarted = 'dependsOnStarted',
|
|
Start = 'start',
|
|
ProcessStarted = 'processStarted',
|
|
Active = 'active',
|
|
Inactive = 'inactive',
|
|
Changed = 'changed',
|
|
Terminated = 'terminated',
|
|
ProcessEnded = 'processEnded',
|
|
End = 'end'
|
|
}
|
|
|
|
|
|
export const enum TaskRunType {
|
|
SingleRun = 'singleRun',
|
|
Background = 'background'
|
|
}
|
|
|
|
export interface TaskEvent {
|
|
kind: TaskEventKind;
|
|
taskId?: string;
|
|
taskName?: string;
|
|
runType?: TaskRunType;
|
|
group?: string;
|
|
processId?: number;
|
|
exitCode?: number;
|
|
terminalId?: number;
|
|
__task?: Task;
|
|
}
|
|
|
|
export const enum TaskRunSource {
|
|
User, // Default
|
|
FolderOpen,
|
|
ConfigurationChange
|
|
}
|
|
|
|
export namespace TaskEvent {
|
|
export function create(kind: TaskEventKind.ProcessStarted | TaskEventKind.ProcessEnded, task: Task, processIdOrExitCode?: number): TaskEvent;
|
|
export function create(kind: TaskEventKind.Start, task: Task, terminalId?: number): TaskEvent;
|
|
export function create(kind: TaskEventKind.DependsOnStarted | TaskEventKind.Start | TaskEventKind.Active | TaskEventKind.Inactive | TaskEventKind.Terminated | TaskEventKind.End, task: Task): TaskEvent;
|
|
export function create(kind: TaskEventKind.Changed): TaskEvent;
|
|
export function create(kind: TaskEventKind, task?: Task, processIdOrExitCodeOrTerminalId?: number): TaskEvent {
|
|
if (task) {
|
|
let result: TaskEvent = {
|
|
kind: kind,
|
|
taskId: task._id,
|
|
taskName: task.configurationProperties.name,
|
|
runType: task.configurationProperties.isBackground ? TaskRunType.Background : TaskRunType.SingleRun,
|
|
group: task.configurationProperties.group,
|
|
processId: undefined as number | undefined,
|
|
exitCode: undefined as number | undefined,
|
|
terminalId: undefined as number | undefined,
|
|
__task: task,
|
|
};
|
|
if (kind === TaskEventKind.Start) {
|
|
result.terminalId = processIdOrExitCodeOrTerminalId;
|
|
} else if (kind === TaskEventKind.ProcessStarted) {
|
|
result.processId = processIdOrExitCodeOrTerminalId;
|
|
} else if (kind === TaskEventKind.ProcessEnded) {
|
|
result.exitCode = processIdOrExitCodeOrTerminalId;
|
|
}
|
|
return Object.freeze(result);
|
|
} else {
|
|
return Object.freeze({ kind: TaskEventKind.Changed });
|
|
}
|
|
}
|
|
}
|
|
|
|
export namespace KeyedTaskIdentifier {
|
|
function sortedStringify(literal: any): string {
|
|
const keys = Object.keys(literal).sort();
|
|
let result: string = '';
|
|
for (let position in keys) {
|
|
let stringified = literal[keys[position]];
|
|
if (stringified instanceof Object) {
|
|
stringified = sortedStringify(test);
|
|
} else if (typeof stringified === 'string') {
|
|
stringified = stringified.replace(/,/g, ',,');
|
|
}
|
|
result += keys[position] + ',' + stringified + ',';
|
|
}
|
|
return result;
|
|
}
|
|
export function create(value: TaskIdentifier): KeyedTaskIdentifier {
|
|
const resultKey = sortedStringify(value);
|
|
console.log(resultKey);
|
|
return { _key: resultKey, type: value.taskType };
|
|
}
|
|
}
|
|
|
|
export namespace TaskDefinition {
|
|
export function createTaskIdentifier(external: TaskIdentifier, reporter: { error(message: string): void; }): KeyedTaskIdentifier | undefined {
|
|
let definition = TaskDefinitionRegistry.get(external.type);
|
|
if (definition === undefined) {
|
|
// We have no task definition so we can't sanitize the literal. Take it as is
|
|
let copy = Objects.deepClone(external);
|
|
delete copy._key;
|
|
return KeyedTaskIdentifier.create(copy);
|
|
}
|
|
|
|
let literal: { type: string;[name: string]: any } = Object.create(null);
|
|
literal.type = definition.taskType;
|
|
let required: Set<string> = new Set();
|
|
definition.required.forEach(element => required.add(element));
|
|
|
|
let properties = definition.properties;
|
|
for (let property of Object.keys(properties)) {
|
|
let value = external[property];
|
|
if (value !== undefined && value !== null) {
|
|
literal[property] = value;
|
|
} else if (required.has(property)) {
|
|
let schema = properties[property];
|
|
if (schema.default !== undefined) {
|
|
literal[property] = Objects.deepClone(schema.default);
|
|
} else {
|
|
switch (schema.type) {
|
|
case 'boolean':
|
|
literal[property] = false;
|
|
break;
|
|
case 'number':
|
|
case 'integer':
|
|
literal[property] = 0;
|
|
break;
|
|
case 'string':
|
|
literal[property] = '';
|
|
break;
|
|
default:
|
|
reporter.error(nls.localize(
|
|
'TaskDefinition.missingRequiredProperty',
|
|
'Error: the task identifier \'{0}\' is missing the required property \'{1}\'. The task identifier will be ignored.', JSON.stringify(external, undefined, 0), property
|
|
));
|
|
return undefined;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return KeyedTaskIdentifier.create(literal);
|
|
}
|
|
}
|