import { workspace , window , RelativePattern , WorkspaceFolder , Uri , StatusBarAlignment , StatusBarItem } from "vscode" ; import * as util from "./common/utils" ; import * as log from "./common/log" ; import constants from "./common/constants" ; import { configuration } from "./common/configuration" ; let cacheBuilding = false ; let folderCaching = false ; let cancel = false ; const taskGlobs = { } ; export interface ICacheItem { uri : Uri ; folder : WorkspaceFolder ; } export const filesCache = new Map ( ) ; export async function addFolderToCache ( folder ? , logPad = "" ) { log . write ( "Add folder to cache" , 3 , logPad ) ; log . value ( "   folder" , ! folder ? "entire workspace" : folder . name , 3 , logPad ) ; await waitForCache ( ) ; await waitForFolderCaching ( ) ; folderCaching = true ; cacheBuilding = true ; if ( ! cancel && configuration . get < boolean > ( "enableAnt" ) ) { await buildCache ( "ant" , util . getAntGlobPattern ( ) , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableAppPublisher" ) ) { await buildCache ( "app-publisher" , constants . GLOB_APPPUBLISHER , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableBash" ) ) { await buildCache ( "bash" , constants . GLOB_BASH , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableBatch" ) ) { await buildCache ( "batch" , constants . GLOB_BATCH , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableGradle" ) ) { await buildCache ( "gradle" , constants . GLOB_GRADLE , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableGrunt" ) ) { await buildCache ( "grunt" , constants . GLOB_GRUNT , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableGulp" ) ) { await buildCache ( "gulp" , constants . GLOB_GULP , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableMake" ) ) { await buildCache ( "make" , constants . GLOB_MAKE , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableMaven" ) ) { await buildCache ( "maven" , constants . GLOB_MAVEN , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableNpm" ) ) { await buildCache ( "npm" , constants . GLOB_NPM , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableNsis" ) ) { await buildCache ( "nsis" , constants . GLOB_NSIS , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enablePerl" ) ) { await buildCache ( "perl" , constants . GLOB_PERL , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enablePowershell" ) ) { await buildCache ( "powershell" , constants . GLOB_POWERSHELL , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enablePython" ) ) { await buildCache ( "python" , constants . GLOB_PYTHON , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enablePipenv" ) ) { await buildCache ( "pipenv" , constants . GLOB_PIPENV , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableRuby" ) ) { await buildCache ( "ruby" , constants . GLOB_RUBY , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableTsc" ) ) { await buildCache ( "tsc" , constants . GLOB_TSC , folder , false , logPad + "   " ) ; } if ( ! cancel && configuration . get < boolean > ( "enableWorkspace" ) ) { await buildCache ( "workspace" , constants . GLOB_WORKSPACE , folder , false , logPad + "   " ) ; } cacheBuilding = false ; folderCaching = false ; if ( cancel ) { log . write ( "Add folder to cache cancelled" , 3 , logPad ) ; } else { log . write ( "Add folder to cache complete" , 3 , logPad ) ; } cancel = false ; } export async function buildCache ( taskType , fileGlob , wsfolder ? , setCacheBuilding = true , logPad = "" ) { const taskAlias = ! util . isScriptType ( taskType ) ? taskType : "script" ; log . methodStart ( "build file cache" , 2 , logPad , true , [ [ "folder" , ! wsfolder ? "entire workspace" : wsfolder . name ] , [ "task type" , taskType ] , [ "task alias" , taskAlias ] , [ "glob" , fileGlob ] , [ "setCacheBuilding" , setCacheBuilding . toString ( ) ] ] ) ; if ( ! filesCache . get ( taskAlias ) ) { filesCache . set ( taskAlias , new Set ( ) ) ; } const fCache = filesCache . get ( taskAlias ) , dispTaskType = util . properCase ( taskType ) ; if ( ! fCache || ! dispTaskType ) { return ; } if ( setCacheBuilding ) { await waitForCache ( ) ; cacheBuilding = true ; } const statusBarSpace = window . createStatusBarItem ( StatusBarAlignment . Left , - 10000 ) ; statusBarSpace . tooltip = "Task Explorer is building the task cache" ; statusBarSpace . show ( ) ; if ( taskGlobs [ taskType ] && taskAlias !== "script" ) { if ( taskGlobs [ taskType ] !== fileGlob ) { fCache . clear ( ) ; } } taskGlobs [ taskType ] = fileGlob ; if ( ! wsfolder ) { log . blank ( 1 ) ; log . write ( "   Build cache - Scan all projects for taskType '" + taskType + "' (" + dispTaskType + ")" , 1 , logPad ) ; await buildFolderCaches ( fCache , dispTaskType , fileGlob , statusBarSpace , setCacheBuilding , logPad + "   " ) ; } else { await buildFolderCache ( fCache , wsfolder , dispTaskType , fileGlob , statusBarSpace , setCacheBuilding , logPad + "   " ) ; } disposeStatusBarSpace ( statusBarSpace ) ; if ( setCacheBuilding ) { cancel = false ; cacheBuilding = false ; } log . methodDone ( "build file cache" , 2 , logPad , true ) ; } async function buildFolderCache ( fCache , folder , taskType , fileGlob , statusBarSpace , setCacheBuilding , logPad = "" ) { if ( cancel ) { cancelInternal ( setCacheBuilding , statusBarSpace ) ; return ; } const logMsg = "Scan project " + folder . name + " for " + taskType + " tasks" ; log . methodStart ( logMsg , 1 , logPad , true ) ; statusBarSpace . text = getStatusString ( "Scanning for " + taskType + " tasks in project " + folder . name , 65 ) ; try { const relativePattern = new RelativePattern ( folder , fileGlob ) ; const paths = await workspace . findFiles ( relativePattern , util . getExcludesGlob ( folder ) ) ; for ( const fpath of paths ) { if ( cancel ) { cancelInternal ( setCacheBuilding , statusBarSpace ) ; return ; } if ( ! util . isExcluded ( fpath . path , "   " ) ) { fCache . add ( { uri : fpath , folder } ) ; log . value ( "   Added to cache" , fpath . fsPath , 3 , logPad ) ; } } } catch ( error ) { log . error ( error . toString ( ) ) ; } log . methodDone ( logMsg , 1 , logPad , true ) ; } async function buildFolderCaches ( fCache , taskType , fileGlob , statusBarSpace , setCacheBuilding , logPad = "" ) { if ( workspace . workspaceFolders ) { for ( const folder of workspace . workspaceFolders ) { await buildFolderCache ( fCache , folder , taskType , fileGlob , statusBarSpace , setCacheBuilding , logPad ) ; } } } export async function addFileToCache ( taskAlias , uri ) { if ( ! filesCache . get ( taskAlias ) ) { filesCache . set ( taskAlias , new Set ( ) ) ; } const taskCache = filesCache . get ( taskAlias ) , wsf = workspace . getWorkspaceFolder ( uri ) ; if ( taskCache && wsf ) { taskCache . add ( { uri , folder : wsf } ) ; } } function cancelInternal ( setCacheBuilding , statusBarSpace ) { if ( setCacheBuilding ) { cacheBuilding = false ; cancel = false ; } disposeStatusBarSpace ( statusBarSpace ) ; log . write ( "   Cache building cancelled" , 1 ) ; } export async function cancelBuildCache ( wait ? ) { let waitCount = 20 ; if ( ! cacheBuilding ) { return ; } cancel = true ; while ( wait && cacheBuilding && waitCount > 0 ) { waitCount -- ; await util . timeout ( 500 ) ; } } function disposeStatusBarSpace ( statusBarSpace ) { statusBarSpace ?. hide ( ) ; statusBarSpace ?. dispose ( ) ; } function getStatusString ( msg , statusLength = 0 ) { if ( msg ) { if ( statusLength > 0 ) { if ( msg . length < statusLength ) { for ( let i = msg . length ; i < statusLength ; i ++ ) { msg += " " ; } } else { msg = msg . substring ( 0 , statusLength - 3 ) + "..." ; } } return "$(loading~spin) " + msg ; } return "" ; } export async function rebuildCache ( logPad = "" ) { log . blank ( 1 ) ; log . write ( "rebuild cache" , 1 , logPad ) ; filesCache . clear ( ) ; await addFolderToCache ( undefined , logPad ) ; } export async function removeFileFromCache ( taskAlias , uri , logPad = "" ) { log . blank ( 1 ) ; log . write ( "remove file from cache" , 1 , logPad ) ; log . value ( "   task type" , taskAlias , 2 , logPad ) ; log . value ( "   file" , uri . fsPath , 2 , logPad ) ; if ( ! filesCache . get ( taskAlias ) ) { return ; } const taskCache = filesCache . get ( taskAlias ) ; const toRemove = [ ] ; if ( taskCache ) { for ( const item of taskCache ) { if ( item . uri . fsPath === uri . fsPath ) { toRemove . push ( item ) ; } } if ( toRemove . length > 0 ) { for ( const tr of toRemove ) { taskCache . delete ( tr ) ; } } } } export async function waitForCache ( ) { while ( cacheBuilding === true || folderCaching === true ) { await util . timeout ( 100 ) ; } } async function waitForFolderCaching ( ) { while ( folderCaching === true ) { await util . timeout ( 100 ) ; } }