Skip to content

Commit

Permalink
prompt user to choose parser to parse task output
Browse files Browse the repository at this point in the history
- before a task runs, prompt the user to choose which parser to use to
parse the task output, and write user's choice into `tasks.json`
- part of #4212

Signed-off-by: Liang Huang <liang.huang@ericsson.com>
  • Loading branch information
Liang Huang committed Sep 5, 2019
1 parent 8054da5 commit 71bee03
Show file tree
Hide file tree
Showing 4 changed files with 229 additions and 67 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## v0.11.0

- [task] added `tasks.fetchTasks()` and `tasks.executeTask()` to plugins API [#6058](https://github.com/theia-ide/theia/pull/6058)
- [task] prompt user to choose parser to parse task output [#5877](https://github.com/theia-ide/theia/pull/5877)

Breaking changes:

Expand Down
82 changes: 74 additions & 8 deletions packages/task/src/browser/task-configurations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -359,13 +359,7 @@ export class TaskConfigurations implements Disposable {
return;
}

const isDetectedTask = this.isDetectedTask(task);
let sourceFolderUri: string | undefined;
if (isDetectedTask) {
sourceFolderUri = task._scope;
} else {
sourceFolderUri = task._source;
}
const sourceFolderUri: string | undefined = this.getSourceFolderUriFromTask(task);
if (!sourceFolderUri) {
console.error('Global task cannot be customized');
return;
Expand Down Expand Up @@ -396,9 +390,25 @@ export class TaskConfigurations implements Disposable {
customization[p] = task[p];
}
});
const problemMatcher: string[] = [];
if (task.problemMatcher) {
if (Array.isArray(task.problemMatcher)) {
problemMatcher.push(...task.problemMatcher.map(t => {
if (typeof t === 'string') {
return t;
} else {
return t.name!;
}
}));
} else if (typeof task.problemMatcher === 'string') {
problemMatcher.push(task.problemMatcher);
} else {
problemMatcher.push(task.problemMatcher.name!);
}
}
return {
...customization,
problemMatcher: []
problemMatcher: problemMatcher.map(name => name.startsWith('$') ? name : `$${name}`)
};
}

Expand Down Expand Up @@ -465,6 +475,51 @@ export class TaskConfigurations implements Disposable {
this.tasksMap = newTaskMap;
}

/**
* saves the names of the problem matchers to be used to parse the output of the given task to `tasks.json`
* @param task task that the problem matcher(s) are applied to
* @param problemMatchers name(s) of the problem matcher(s)
*/
async saveProblemMatcherForTask(task: TaskConfiguration, problemMatchers: string[]): Promise<void> {
const sourceFolderUri: string | undefined = this.getSourceFolderUriFromTask(task);
if (!sourceFolderUri) {
console.error('Global task cannot be customized');
return;
}
const configFileUri = this.getConfigFileUri(sourceFolderUri);
const configuredAndCustomizedTasks = await this.getTasks();
if (configuredAndCustomizedTasks.some(t => !!this.taskDefinitionRegistry.getDefinition(t))) { // task is already in `tasks.json`
try {
const content = (await this.fileSystem.resolveContent(configFileUri)).content;
const errors: ParseError[] = [];
const jsonTasks = jsoncparser.parse(content, errors).tasks;
if (errors.length > 0) {
for (const e of errors) {
console.error(`Error parsing ${configFileUri}: error: ${e.error}, length: ${e.length}, offset: ${e.offset}`);
}
} else {
if (jsonTasks) {
const ind = jsonTasks.findIndex((t: TaskConfiguration) => t.type === task.type && t.label === task.label);
const newTask = Object.assign(jsonTasks[ind], { problemMatcher: problemMatchers.map(name => name.startsWith('$') ? name : `$${name}`) });
jsonTasks[ind] = newTask;
}
const updatedTasks = JSON.stringify({ tasks: jsonTasks });
const formattingOptions = { tabSize: 4, insertSpaces: true, eol: '' };
const edits = jsoncparser.format(updatedTasks, undefined, formattingOptions);
const updatedContent = jsoncparser.applyEdits(updatedTasks, edits);
const resource = await this.resourceProvider(new URI(configFileUri));
Resource.save(resource, { content: updatedContent });
}
} catch (e) {
console.error(`Failed to save task configuration for ${task.label} task. ${e.toString()}`);
return;
}
} else { // task is not in `tasks.json`
task.problemMatcher = problemMatchers;
this.saveTask(configFileUri, task);
}
}

private getSourceFolderFromConfigUri(configFileUri: string): string {
return new URI(configFileUri).parent.parent.path.toString();
}
Expand All @@ -482,4 +537,15 @@ export class TaskConfigurations implements Disposable {
type: task.taskType || task.type
});
}

private getSourceFolderUriFromTask(task: TaskConfiguration): string | undefined {
const isDetectedTask = this.isDetectedTask(task);
let sourceFolderUri: string | undefined;
if (isDetectedTask) {
sourceFolderUri = task._scope;
} else {
sourceFolderUri = task._source;
}
return sourceFolderUri;
}
}
11 changes: 11 additions & 0 deletions packages/task/src/browser/task-problem-matcher-registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ export class ProblemMatcherRegistry {
return this.matchers[name];
}

/**
* Returns all registered problem matchers in the registry.
*/
getAll(): NamedProblemMatcher[] {
const all: NamedProblemMatcher[] = [];
for (const matcherName of Object.keys(this.matchers)) {
all.push(this.get(matcherName)!);
}
return all;
}

/**
* Transforms the `ProblemMatcherContribution` to a `ProblemMatcher`
*
Expand Down
Loading

0 comments on commit 71bee03

Please sign in to comment.