Skip to content

Commit 87cfa19

Browse files
committed
Fixes microsoft#25518: Cannot associate a problem matcher with an auto detected tasks
1 parent a331c64 commit 87cfa19

16 files changed

Lines changed: 502 additions & 90 deletions

File tree

build/npm/postinstall.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ const extensions = [
3333
'html',
3434
'git',
3535
'gulp',
36-
'grunt'
36+
'grunt',
37+
'jake'
3738
];
3839

3940
extensions.forEach(extension => npmInstall(`extensions/${extension}`));

extensions/grunt/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
"Other"
1313
],
1414
"scripts": {
15-
"compile": "gulp compile-extension:gulp",
16-
"watch": "gulp watch-extension:gulp"
15+
"compile": "gulp compile-extension:grunt",
16+
"watch": "gulp watch-extension:grunt"
1717
},
1818
"dependencies": {
1919
"vscode-nls": "^2.0.2"

extensions/gulp/src/main.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ async function getGulpTasks(): Promise<vscode.Task[]> {
103103
let { stdout, stderr } = await exec(commandLine, { cwd: workspaceRoot });
104104
if (stderr) {
105105
channel.appendLine(stderr);
106+
channel.show(true);
106107
}
107108
let result: vscode.Task[] = [];
108109
if (stdout) {

extensions/jake/package.json

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
{
2+
"name": "jake",
3+
"publisher": "vscode",
4+
"description": "Extension to add Jake capabilities to VSCode.",
5+
"displayName": "Jake support for VSCode",
6+
"version": "0.0.1",
7+
"engines": {
8+
"vscode": "*"
9+
},
10+
"enableProposedApi": true,
11+
"categories": [
12+
"Other"
13+
],
14+
"scripts": {
15+
"compile": "gulp compile-extension:jake",
16+
"watch": "gulp watch-extension:jake"
17+
},
18+
"dependencies": {
19+
"vscode-nls": "^2.0.2"
20+
},
21+
"devDependencies": {
22+
"@types/node": "^7.0.18"
23+
},
24+
"main": "./out/main",
25+
"activationEvents": [
26+
"onCommand:workbench.action.tasks.runTask",
27+
"onCommand:workbench.action.tasks.build",
28+
"onCommand:workbench.action.tasks.test"
29+
],
30+
"contributes": {
31+
"configuration": {
32+
"id": "jake",
33+
"type": "object",
34+
"title": "Jake",
35+
"properties": {
36+
"jake.autoDetect": {
37+
"type": "string",
38+
"enum": [
39+
"off",
40+
"on"
41+
],
42+
"default": "on",
43+
"description": "%config.jake.autoDetect%"
44+
}
45+
}
46+
}
47+
}
48+
}

extensions/jake/package.nls.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"config.jake.autoDetect": "Controls whether auto detection of Jake tasks is on or off. Default is on."
3+
}

extensions/jake/src/main.ts

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
'use strict';
6+
7+
import * as path from 'path';
8+
import * as fs from 'fs';
9+
import * as cp from 'child_process';
10+
import * as vscode from 'vscode';
11+
import * as nls from 'vscode-nls';
12+
13+
const localize = nls.config(process.env.VSCODE_NLS_CONFIG)();
14+
15+
type AutoDetect = 'on' | 'off';
16+
let taskProvider: vscode.Disposable | undefined;
17+
18+
export function activate(_context: vscode.ExtensionContext): void {
19+
let workspaceRoot = vscode.workspace.rootPath;
20+
if (!workspaceRoot) {
21+
return;
22+
}
23+
let pattern = path.join(workspaceRoot, '{Jakefile,Jakefile.js}');
24+
let jakePromise: Thenable<vscode.Task[]> | undefined = undefined;
25+
let fileWatcher = vscode.workspace.createFileSystemWatcher(pattern);
26+
fileWatcher.onDidChange(() => jakePromise = undefined);
27+
fileWatcher.onDidCreate(() => jakePromise = undefined);
28+
fileWatcher.onDidDelete(() => jakePromise = undefined);
29+
30+
function onConfigurationChanged() {
31+
let autoDetect = vscode.workspace.getConfiguration('jake').get<AutoDetect>('autoDetect');
32+
if (taskProvider && autoDetect === 'off') {
33+
jakePromise = undefined;
34+
taskProvider.dispose();
35+
taskProvider = undefined;
36+
} else if (!taskProvider && autoDetect === 'on') {
37+
taskProvider = vscode.workspace.registerTaskProvider({
38+
provideTasks: () => {
39+
if (!jakePromise) {
40+
jakePromise = getJakeTasks();
41+
}
42+
return jakePromise;
43+
}
44+
});
45+
}
46+
}
47+
vscode.workspace.onDidChangeConfiguration(onConfigurationChanged);
48+
onConfigurationChanged();
49+
}
50+
51+
export function deactivate(): void {
52+
if (taskProvider) {
53+
taskProvider.dispose();
54+
}
55+
}
56+
57+
function exists(file: string): Promise<boolean> {
58+
return new Promise<boolean>((resolve, _reject) => {
59+
fs.exists(file, (value) => {
60+
resolve(value);
61+
});
62+
});
63+
}
64+
65+
function exec(command: string, options: cp.ExecOptions): Promise<{ stdout: string; stderr: string }> {
66+
return new Promise<{ stdout: string; stderr: string }>((resolve, reject) => {
67+
cp.exec(command, options, (error, stdout, stderr) => {
68+
if (error) {
69+
reject({ error, stdout, stderr });
70+
}
71+
resolve({ stdout, stderr });
72+
});
73+
});
74+
}
75+
76+
async function getJakeTasks(): Promise<vscode.Task[]> {
77+
let workspaceRoot = vscode.workspace.rootPath;
78+
let emptyTasks: vscode.Task[] = [];
79+
if (!workspaceRoot) {
80+
return emptyTasks;
81+
}
82+
let jakefile = path.join(workspaceRoot, 'Jakefile');
83+
if (!await exists(jakefile)) {
84+
jakefile = path.join(workspaceRoot, 'Jakefile.js');
85+
if (! await exists(jakefile)) {
86+
return emptyTasks;
87+
}
88+
}
89+
90+
let jakeCommand: string;
91+
let platform = process.platform;
92+
if (platform === 'win32' && await exists(path.join(workspaceRoot!, 'node_modules', '.bin', 'jake.cmd'))) {
93+
jakeCommand = path.join('.', 'node_modules', '.bin', 'jake.cmd');
94+
} else if ((platform === 'linux' || platform === 'darwin') && await exists(path.join(workspaceRoot!, 'node_modules', '.bin', 'jake'))) {
95+
jakeCommand = path.join('.', 'node_modules', '.bin', 'jake');
96+
} else {
97+
jakeCommand = 'jake';
98+
}
99+
100+
let commandLine = `${jakeCommand} --tasks`;
101+
let channel = vscode.window.createOutputChannel('tasks');
102+
try {
103+
let { stdout, stderr } = await exec(commandLine, { cwd: workspaceRoot });
104+
if (stderr) {
105+
channel.appendLine(stderr);
106+
channel.show(true);
107+
}
108+
let result: vscode.Task[] = [];
109+
if (stdout) {
110+
let buildTask: { task: vscode.Task | undefined, rank: number } = { task: undefined, rank: 0 };
111+
let testTask: { task: vscode.Task | undefined, rank: number } = { task: undefined, rank: 0 };
112+
let lines = stdout.split(/\r{0,1}\n/);
113+
for (let line of lines) {
114+
if (line.length === 0) {
115+
continue;
116+
}
117+
let regExp = /^jake\s+([^\s]+)\s/g;
118+
let matches = regExp.exec(line);
119+
if (matches && matches.length === 2) {
120+
let taskName = matches[1];
121+
let task = new vscode.ShellTask(`jake: ${taskName}`, `${jakeCommand} ${taskName}`);
122+
task.identifier = `jake.${taskName}`;
123+
result.push(task);
124+
let lowerCaseLine = line.toLowerCase();
125+
if (lowerCaseLine === 'build') {
126+
buildTask = { task, rank: 2 };
127+
} else if (lowerCaseLine.indexOf('build') !== -1 && buildTask.rank < 1) {
128+
buildTask = { task, rank: 1 };
129+
} else if (lowerCaseLine === 'test') {
130+
testTask = { task, rank: 2 };
131+
} else if (lowerCaseLine.indexOf('test') !== -1 && testTask.rank < 1) {
132+
testTask = { task, rank: 1 };
133+
}
134+
}
135+
}
136+
if (buildTask.task) {
137+
buildTask.task.group = vscode.TaskGroup.Build;
138+
}
139+
if (testTask.task) {
140+
testTask.task.group = vscode.TaskGroup.Test;
141+
}
142+
}
143+
return result;
144+
} catch (err) {
145+
if (err.stderr) {
146+
channel.appendLine(err.stderr);
147+
}
148+
channel.appendLine(localize('execFailed', 'Auto detecting Jake failed with error: {0}', err.error ? err.error.toString() : 'unknown'));
149+
return emptyTasks;
150+
}
151+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
/// <reference path='../../../../src/vs/vscode.d.ts'/>
7+
/// <reference path='../../../../src/vs/vscode.proposed.d.ts'/>
8+
/// <reference types='@types/node'/>

extensions/jake/tsconfig.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es6",
4+
"module": "commonjs",
5+
"lib": [
6+
"es2016"
7+
],
8+
"outDir": "./out",
9+
"strictNullChecks": true,
10+
"noImplicitAny": true,
11+
"noImplicitReturns": true,
12+
"noUnusedLocals": true,
13+
"noUnusedParameters": true
14+
},
15+
"include": [
16+
"src/**/*"
17+
]
18+
}

src/vs/workbench/api/node/extHostTask.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -268,15 +268,15 @@ namespace ShellConfiguration {
268268

269269
namespace Tasks {
270270

271-
export function from(tasks: vscode.Task[], uuidMap: UUIDMap): TaskSystem.Task[] {
271+
export function from(tasks: vscode.Task[], extension: IExtensionDescription, uuidMap: UUIDMap): TaskSystem.Task[] {
272272
if (tasks === void 0 || tasks === null) {
273273
return [];
274274
}
275275
let result: TaskSystem.Task[] = [];
276276
try {
277277
uuidMap.start();
278278
for (let task of tasks) {
279-
let converted = fromSingle(task, uuidMap);
279+
let converted = fromSingle(task, extension, uuidMap);
280280
if (converted) {
281281
result.push(converted);
282282
}
@@ -287,7 +287,7 @@ namespace Tasks {
287287
return result;
288288
}
289289

290-
function fromSingle(task: vscode.Task, uuidMap: UUIDMap): TaskSystem.Task {
290+
function fromSingle(task: vscode.Task, extension: IExtensionDescription, uuidMap: UUIDMap): TaskSystem.Task {
291291
if (typeof task.name !== 'string' || typeof task.identifier !== 'string') {
292292
return undefined;
293293
}
@@ -306,6 +306,7 @@ namespace Tasks {
306306
command.echo = behaviour.echo;
307307
let result: TaskSystem.Task = {
308308
_id: uuidMap.getUUID(task.identifier),
309+
_source: { kind: TaskSystem.TaskSourceKind.Extension, detail: extension.id },
309310
name: task.name,
310311
identifier: task.identifier,
311312
group: types.TaskGroup.is(task.group) ? task.group : undefined,
@@ -421,7 +422,7 @@ export class ExtHostTask extends ExtHostTaskShape {
421422
}
422423
return asWinJsPromise(token => handler.provider.provideTasks(token)).then(value => {
423424
return {
424-
tasks: Tasks.from(value, this.getUUIDMap(handler.extension.id)),
425+
tasks: Tasks.from(value, handler.extension, this.getUUIDMap(handler.extension.id)),
425426
extension: handler.extension
426427
};
427428
});

0 commit comments

Comments
 (0)