Skip to content

Commit

Permalink
wip create problem marker from task output
Browse files Browse the repository at this point in the history
  • Loading branch information
elaihau committed Apr 8, 2019
1 parent 237e6b2 commit b621819
Show file tree
Hide file tree
Showing 25 changed files with 1,428 additions and 43 deletions.
7 changes: 7 additions & 0 deletions packages/plugin-ext/src/common/plugin-protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { ExtPluginApi } from './plugin-ext-api-contribution';
import { IJSONSchema, IJSONSchemaSnippet } from '@theia/core/lib/common/json-schema';
import { RecursivePartial } from '@theia/core/lib/common/types';
import { PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/common/preferences/preference-schema';
import { TaskDefinitionContribution, ProblemMatcherContribution, ProblemPatternContribution } from '@theia/task/lib/common';

export const hostedServicePath = '/services/hostedPlugin';

Expand Down Expand Up @@ -66,6 +67,9 @@ export interface PluginPackageContribution {
keybindings?: PluginPackageKeybinding[];
debuggers?: PluginPackageDebuggersContribution[];
snippets: PluginPackageSnippetsContribution[];
taskDefinitions?: TaskDefinitionContribution[];
problemMatchers?: ProblemMatcherContribution[];
problemPatterns?: ProblemPatternContribution[];
}

export interface PluginPackageViewContainer {
Expand Down Expand Up @@ -359,6 +363,9 @@ export interface PluginContribution {
keybindings?: Keybinding[];
debuggers?: DebuggerContribution[];
snippets?: SnippetContribution[];
taskDefinitions?: TaskDefinitionContribution[];
problemMatchers?: ProblemMatcherContribution[];
problemPatterns?: ProblemPatternContribution[];
}

export interface SnippetContribution {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugin-ext/src/hosted/browser/hosted-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export class HostedPluginSupport {
}

if (plugin.model.contributes) {
this.contributionHandler.handleContributions(plugin.model.contributes);
this.contributionHandler.handleContributions(plugin.model.contributes, plugin.model.id);
}
}

Expand Down
13 changes: 13 additions & 0 deletions packages/plugin-ext/src/hosted/node/scanners/scanner-theia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import { deepClone } from '@theia/core/lib/common/objects';
import { FileUri } from '@theia/core/lib/node/file-uri';
import { PreferenceSchema, PreferenceSchemaProperties } from '@theia/core/lib/common/preferences/preference-schema';
import { RecursivePartial } from '@theia/core/lib/common/types';
import { TaskDefinitionContribution, ProblemMatcherContribution, ProblemPatternContribution } from '@theia/task/lib/common/task-protocol';

namespace nls {
export function localize(key: string, _default: string) {
Expand Down Expand Up @@ -184,6 +185,18 @@ export class TheiaPluginScanner implements PluginScanner {
contributions.debuggers = debuggers;
}

if (rawPlugin.contributes!.taskDefinitions) {
contributions.taskDefinitions = rawPlugin.contributes!.taskDefinitions as TaskDefinitionContribution[];
}

if (rawPlugin.contributes!.problemMatchers) {
contributions.problemMatchers = rawPlugin.contributes!.problemMatchers as ProblemMatcherContribution[];
}

if (rawPlugin.contributes!.problemPatterns) {
contributions.problemPatterns = rawPlugin.contributes!.problemPatterns as ProblemPatternContribution[];
}

contributions.snippets = this.readSnippets(rawPlugin);
return contributions;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { MonacoSnippetSuggestProvider } from '@theia/monaco/lib/browser/monaco-s
import { PluginSharedStyle } from './plugin-shared-style';
import { CommandRegistry } from '@theia/core';
import { BuiltinThemeProvider } from '@theia/core/lib/browser/theming';
import { TaskDefinitionRegistry, ProblemMatcherRegistry, ProblemPatternRegistry } from '@theia/task/lib/common';

@injectable()
export class PluginContributionHandler {
Expand Down Expand Up @@ -60,7 +61,16 @@ export class PluginContributionHandler {
@inject(PluginSharedStyle)
protected readonly style: PluginSharedStyle;

handleContributions(contributions: PluginContribution): void {
@inject(TaskDefinitionRegistry)
protected readonly taskDefinitionRegistry: TaskDefinitionRegistry;

@inject(ProblemMatcherRegistry)
protected readonly problemMatcherRegistry: ProblemMatcherRegistry;

@inject(ProblemPatternRegistry)
protected readonly problemPatternRegistry: ProblemPatternRegistry;

handleContributions(contributions: PluginContribution, modelId: string): void {
if (contributions.configuration) {
this.updateConfigurationSchema(contributions.configuration);
}
Expand Down Expand Up @@ -150,6 +160,19 @@ export class PluginContributionHandler {
});
}
}

if (contributions.taskDefinitions) {
contributions.taskDefinitions.forEach(def => this.taskDefinitionRegistry.register(def, modelId));
}

if (contributions.problemMatchers) {
contributions.problemMatchers.forEach(matcher => this.problemMatcherRegistry.register(matcher));
}

if (contributions.problemPatterns) {
contributions.problemPatterns.forEach(pattern => this.problemPatternRegistry.register(pattern.name!, pattern));
// TODO consider creating NamedProblemPattern interface
}
}

protected pluginCommandIconId = 0;
Expand Down
6 changes: 4 additions & 2 deletions packages/plugin-ext/src/plugin/types-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1686,12 +1686,14 @@ export class Task {
if (this.taskExecution instanceof ProcessExecution) {
Object.assign(this.taskDefinition, {
type: 'process',
id: this.taskExecution.computeId()
id: this.taskExecution.computeId(),
taskType: this.taskDefinition!.type
});
} else if (this.taskExecution instanceof ShellExecution) {
Object.assign(this.taskDefinition, {
type: 'shell',
id: this.taskExecution.computeId()
id: this.taskExecution.computeId(),
taskType: this.taskDefinition!.type
});
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/process/src/node/process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ export abstract class Process {
return this.errorEmitter.event;
}

abstract onData(listener: (buffer: string) => void): void;
abstract onDataClosed(listener: (exitCode: number, signal?: number) => void): void;

protected emitOnStarted() {
this.startEmitter.fire({});
}
Expand Down
8 changes: 8 additions & 0 deletions packages/process/src/node/raw-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ export class RawProcess extends Process {
}
}

onData(listener: (buffer: string) => void): void {
this.output.on('data', listener);
}

onDataClosed(listener: (exitCode: number, signal?: number) => void): void {
this.output.on('close', listener);
}

get pid() {
return this.process.pid;
}
Expand Down
8 changes: 8 additions & 0 deletions packages/process/src/node/terminal-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,12 @@ export class TerminalProcess extends Process {
this.terminal.write(data);
}

onData(listener: (buffer: string) => void): void {
this.terminal.on('data', listener);
}

onDataClosed(listener: (exitCode: number, signal?: number) => void): void {
this.terminal.on('exit', listener);
// this.ringBuffer.getStream().on('close', listener); // TODO check if we should listen to the `close` from the buffer
}
}
3 changes: 2 additions & 1 deletion packages/task/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
"@theia/terminal": "^0.5.0",
"@theia/variable-resolver": "^0.5.0",
"@theia/workspace": "^0.5.0",
"jsonc-parser": "^2.0.2"
"jsonc-parser": "^2.0.2",
"vscode-uri": "^1.0.1"
},
"publishConfig": {
"access": "public"
Expand Down
6 changes: 1 addition & 5 deletions packages/task/src/browser/process/process-task-resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,9 @@ export class ProcessTaskResolver implements TaskResolver {
const options = { context: new URI(taskConfig._source).withScheme('file') };
const processTaskConfig = taskConfig as ProcessTaskConfiguration;
const result: ProcessTaskConfiguration = {
type: processTaskConfig.type,
_source: processTaskConfig._source,
_scope: processTaskConfig._scope,
label: processTaskConfig.label,
...processTaskConfig,
command: await this.variableResolverService.resolve(processTaskConfig.command, options),
args: processTaskConfig.args ? await this.variableResolverService.resolveArray(processTaskConfig.args, options) : undefined,
options: processTaskConfig.options,
windows: processTaskConfig.windows ? {
command: await this.variableResolverService.resolve(processTaskConfig.windows.command, options),
args: processTaskConfig.windows.args ? await this.variableResolverService.resolveArray(processTaskConfig.windows.args, options) : undefined,
Expand Down
53 changes: 47 additions & 6 deletions packages/task/src/browser/task-configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
********************************************************************************/

import { inject, injectable } from 'inversify';
import { TaskConfiguration } from '../common/task-protocol';
import { TaskConfiguration, TaskCutomization } from '../common/task-protocol';
import { Disposable, DisposableCollection, ResourceProvider } from '@theia/core/lib/common';
import URI from '@theia/core/lib/common/uri';
import { FileSystemWatcher, FileChangeEvent } from '@theia/filesystem/lib/browser/filesystem-watcher';
Expand Down Expand Up @@ -47,6 +47,8 @@ export class TaskConfigurations implements Disposable {
* For the inner map (i.e., task config map), the key is task label and value TaskConfiguration
*/
protected tasksMap = new Map<string, Map<string, TaskConfiguration>>();
protected taskCustomizations: TaskCutomization[] = [];

protected watchedConfigFileUris: string[] = [];
protected watchersMap = new Map<string, Disposable>(); // map of watchers for task config files, where the key is folder uri

Expand Down Expand Up @@ -173,6 +175,10 @@ export class TaskConfigurations implements Disposable {
this.tasksMap.delete(source);
}

getTaskCustomizations(type: string): TaskCutomization[] {
return this.taskCustomizations.filter(c => c.type === type);
}

/** returns the string uri of where the config file would be, if it existed under a given root directory */
protected getConfigFileUri(rootDir: string): string {
return new URI(rootDir).resolve(this.TASKFILEPATH).resolve(this.TASKFILE).toString();
Expand All @@ -198,23 +204,29 @@ export class TaskConfigurations implements Disposable {
* If reading a config file wasn't successful then does nothing.
*/
protected async refreshTasks(configFileUri: string) {
const tasksConfigsArray = await this.readTasks(configFileUri);
if (tasksConfigsArray) {
const configuredTasksArray = await this.readTasks(configFileUri);
if (configuredTasksArray) {
// only clear tasks map when successful at parsing the config file
// this way we avoid clearing and re-filling it multiple times if the
// user is editing the file in the auto-save mode, having momentarily
// non-parsing JSON.
this.removeTasks(configFileUri);

if (tasksConfigsArray.length > 0) {
if (configuredTasksArray.length > 0) {
const newTaskMap = new Map<string, TaskConfiguration>();
for (const task of tasksConfigsArray) {
for (const task of configuredTasksArray) {
newTaskMap.set(task.label, task);
}
const source = this.getSourceFolderFromConfigUri(configFileUri);
this.tasksMap.set(source, newTaskMap);
}
}

const cutomizations = await this.readTaskCustomizations(configFileUri);
if (cutomizations) {
this.taskCustomizations.length = 0;
this.taskCustomizations = cutomizations;
}
}

/** parses a config file and extracts the tasks launch configurations */
Expand All @@ -234,7 +246,10 @@ export class TaskConfigurations implements Disposable {
console.error(`Error parsing ${uri}: error: ${e.error}, length: ${e.length}, offset: ${e.offset}`);
}
} else {
return this.filterDuplicates(tasks['tasks']).map(t => Object.assign(t, { _source: this.getSourceFolderFromConfigUri(uri) }));
return this.filterDuplicates(
// tslint:disable-next-line:no-any
(tasks['tasks'] as Array<any>).filter(t => TaskConfiguration.is(t))
).map(t => Object.assign(t, { _source: this.getSourceFolderFromConfigUri(uri) }));
}
} catch (err) {
console.error(`Error(s) reading config file: ${uri}`);
Expand Down Expand Up @@ -301,4 +316,30 @@ export class TaskConfigurations implements Disposable {
private getSourceFolderFromConfigUri(configFileUri: string): string {
return new URI(configFileUri).parent.parent.path.toString();
}

// TODO put the file read logic into a separate function and reuse
protected async readTaskCustomizations(uri: string): Promise<TaskCutomization[] | undefined> {
if (!await this.fileSystem.exists(uri)) {
return undefined;
} else {
try {
const response = await this.fileSystem.resolveContent(uri);

const strippedContent = jsoncparser.stripComments(response.content);
const errors: ParseError[] = [];
const tasks = jsoncparser.parse(strippedContent, errors);

if (errors.length) {
for (const e of errors) {
console.error(`Error parsing ${uri}: error: ${e.error}, length: ${e.length}, offset: ${e.offset}`);
}
} else {
// tslint:disable-next-line:no-any
return (tasks['tasks'] as Array<any>).filter(t => !TaskConfiguration.is(t));
}
} catch (err) {
console.error(`Error(s) reading config file: ${uri}`);
}
}
}
}
16 changes: 15 additions & 1 deletion packages/task/src/browser/task-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ import { TaskConfigurations } from './task-configurations';
import { ProvidedTaskConfigurations } from './provided-task-configurations';
import { TaskFrontendContribution } from './task-frontend-contribution';
import { createCommonBindings } from '../common/task-common-module';
import { TaskServer, taskPath } from '../common/task-protocol';
import {
TaskServer, taskPath,
problemMatcherPath, ProblemMatcherRegistry,
problemPatternPath, ProblemPatternRegistry,
taskDefinitionPath, TaskDefinitionRegistry
} from '../common/task-protocol';
import { TaskWatcher } from '../common/task-watcher';
import { bindProcessTaskModule } from './process/process-task-frontend-module';
import { TaskSchemaUpdater } from './task-schema-updater';
Expand All @@ -51,6 +56,15 @@ export default new ContainerModule(bind => {
const taskWatcher = ctx.container.get(TaskWatcher);
return connection.createProxy<TaskServer>(taskPath, taskWatcher.getTaskClient());
}).inSingletonScope();
bind(TaskDefinitionRegistry).toDynamicValue(({ container }) =>
WebSocketConnectionProvider.createProxy(container, taskDefinitionPath)
).inSingletonScope();
bind(ProblemMatcherRegistry).toDynamicValue(({ container }) =>
WebSocketConnectionProvider.createProxy(container, problemMatcherPath)
).inSingletonScope();
bind(ProblemPatternRegistry).toDynamicValue(({ container }) =>
WebSocketConnectionProvider.createProxy(container, problemPatternPath)
).inSingletonScope();

createCommonBindings(bind);

Expand Down
Loading

0 comments on commit b621819

Please sign in to comment.