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 = / ^ j a k e \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+ }
0 commit comments