import { Task , TaskGroup , WorkspaceFolder , ShellExecution , Uri , window , workspace } from "vscode" ; import * as path from "path" ; import * as util from "../common/utils" ; import * as log from "../common/log" ; import { execSync } from "child_process" ; import { parseStringPromise } from "xml2js" ; import { configuration } from "../common/configuration" ; import { filesCache } from "../cache" ; import { TaskExplorerProvider } from "./provider" ; import { TaskExplorerDefinition } from "../taskDefinition" ; interface StringMap { [ s ] : string ; } export class AntTaskProvider extends TaskExplorerProvider implements TaskExplorerProvider { constructor ( ) { super ( "ant" ) ; } public createTask ( target , cmdName , folder , uri , xArgs ? ) { const cwd = path . dirname ( uri . fsPath ) , def = this . getDefaultDefinition ( target , folder , uri ) ; let args = [ target ] , options = { cwd } ; if ( process . platform === "win32" && configuration . get ( "enableAnsiconForAnt" ) === true ) { let ansicon = "ansicon.exe" ; const ansiPath = configuration . get ( "pathToAnsicon" ) ; if ( ansiPath && util . pathExists ( ansiPath ) ) { ansicon = ansiPath ; if ( ! ansicon . endsWith ( "ansicon.exe" ) && ! ansicon . endsWith ( "\\" ) ) { ansicon = path . join ( ansicon , "ansicon.exe" ) ; } else if ( ! ansicon . endsWith ( "ansicon.exe" ) ) { ansicon += "ansicon.exe" ; } } args = [ "-logger" , "org.apache.tools.ant.listener.AnsiColorLogger" , target ] ; options = { cwd , executable : ansicon } ; } if ( def . fileName && def . fileName . toLowerCase ( ) !== "build.xml" ) { args . push ( "-f" ) ; args . push ( def . fileName ) ; } const execution = new ShellExecution ( this . getCommand ( ) , args , options ) ; return new Task ( def , folder , cmdName ? cmdName : target , "ant" , execution , undefined ) ; } public async readTasks ( logPad = "" ) { log . methodStart ( "detect ant files" , 1 , logPad , true ) ; const allTasks = [ ] ; const visitedFiles = new Set ( ) ; const paths = filesCache . get ( "ant" ) ; if ( workspace . workspaceFolders && paths ) { for ( const fobj of paths ) { if ( ! util . isExcluded ( fobj . uri . path ) && ! visitedFiles . has ( fobj . uri . fsPath ) ) { visitedFiles . add ( fobj . uri . fsPath ) ; const tasks = await this . readUriTasks ( fobj . uri , undefined , logPad + "   " ) ; log . write ( "   processed ant file" , 3 , logPad ) ; log . value ( "      file" , fobj . uri . fsPath , 3 , logPad ) ; log . value ( "      targets in file" , tasks . length , 3 , logPad ) ; allTasks . push ( ... tasks ) ; } } } log . value ( "   # of tasks" , allTasks . length , 2 , logPad ) ; log . methodDone ( "detect ant files" , 1 , logPad , true ) ; return allTasks ; } private async findAllAntScripts ( path , logPad = "" ) { const scripts = { } ; const useAnt = configuration . get < boolean > ( "useAnt" ) ; log . methodStart ( "find ant targets" , 1 , logPad , true , [ [ "use ant" , useAnt ] ] ) ; if ( useAnt === true ) { this . findTasksWithAnt ( scripts ) ; } else { await this . findTasksWithXml2Js ( path , scripts ) ; } log . methodDone ( "find ant targets complete" , 1 , logPad , true ) ; return scripts ; } public getDocumentPosition ( taskName , documentText ) { if ( ! taskName || ! documentText ) { return 0 ; } taskName = taskName . replace ( " - Default" , "" ) ; let idx = this . getDocumentPositionLine ( "name=" , taskName , documentText , 6 ) ; if ( idx > 0 ) { const scriptOffset2 = this . getDocumentPositionLine ( "name=" , taskName , documentText , 6 , idx + 1 ) ; if ( scriptOffset2 > 0 ) { idx = scriptOffset2 ; } } return idx ; } private findTasksWithAnt ( scripts ) { let stdout ; try { stdout = execSync ( this . getCommand ( ) + " -f " + path + " -p" ) ; } catch ( ex ) { this . logException ( ex ) ; return ; } if ( stdout ) { let text = stdout . toString ( ) ; let defaultTask = text . match ( /(Default target: )([\w\-]+)/i ) ; if ( defaultTask && defaultTask . length > 2 ) { defaultTask = defaultTask [ 2 ] ; defaultTask = defaultTask . trim ( ) ; } text = text . split ( "\n" ) ; for ( const i in text ) { if ( text . hasOwnProperty ( i ) ) { const line = text [ i ] . trim ( ) ; if ( ! line || line . match ( /(target[s]{0,1}:|Buildfile:)/i ) ) { continue ; } log . value ( "   Found target (ant -p)" , line ) ; scripts [ defaultTask === line ? line + " - Default" : line ] = line ; } } } } private logException ( ex ) { log . error ( [ "*** Error running/executing ant!!" , "Check to ensure the path to ant/ant.bat is correct" , ex ?. toString ( ) ] ) ; window . showInformationMessage ( "Error running/executing ant!!  Check to ensure the path to ant/ant.bat is correct" ) ; } private async findTasksWithXml2Js ( path , scripts ) { const buffer = util . readFileSync ( path ) ; const text = await parseStringPromise ( buffer ) ; if ( text && text . project && text . project . target ) { const defaultTask = text . project . $ . default ; const targets = text . project . target ; for ( const tgt of targets ) { if ( tgt . $ && tgt . $ . name ) { log . value ( "   Found target (cst.)" , tgt . $ . name ) ; scripts [ defaultTask === tgt . $ . name ? tgt . $ . name + " - Default" : tgt . $ . name ] = tgt . $ . name ; } } } } private getCommand ( ) { let ant = "ant" ; if ( process . platform === "win32" ) { ant = "ant.bat" ; } if ( configuration . get ( "pathToAnt" ) ) { ant = configuration . get ( "pathToAnt" ) ; if ( process . platform === "win32" && ant . endsWith ( "\\ant" ) ) { ant += ".bat" ; } } return ant ; } public getDefaultDefinition ( target , folder , uri ) { const def = { type : "ant" , script : target , target , path : util . getRelativePath ( folder , uri ) , fileName : path . basename ( uri . path ) , uri } ; return def ; } public async readUriTasks ( uri , wsFolder ? , logPad = "" ) { const result = [ ] ; const folder = wsFolder || workspace . getWorkspaceFolder ( uri ) ; log . methodStart ( "read ant file uri task" , 1 , logPad , true , [ [ "path" , uri ?. fsPath ] , [ "project folder" , folder ?. name ] ] ) ; if ( folder ) { const scripts = await this . findAllAntScripts ( uri . fsPath , logPad + "   " ) ; if ( scripts ) { for ( const s of Object . keys ( scripts ) ) { const task = this . createTask ( scripts [ s ] ? scripts [ s ] : s , s , folder , uri ) ; task . group = TaskGroup . Build ; result . push ( task ) ; } } } log . methodDone ( "read ant file uri task" , 1 , logPad , true ) ; return result ; } }