import { PathLike , readdir , stat , Stats } from 'fs' ; import { resolve } from 'path' ; import { bindNodeCallback , from , Observable } from 'rxjs' ; import { catchError , mergeMap } from 'rxjs/operators' ; import { Logger } from '../../logging' ; import { PluginDiscoveryError } from './plugin_discovery_error' ; const fsReadDir$ = bindNodeCallback < string , string [ ] > ( readdir ) ; const fsStat$ = bindNodeCallback < PathLike , Stats > ( stat ) ; const maxScanDepth = 5 ; interface PluginSearchPathEntry { dir : string ; depth : number ; } param pluginDirs param log export function scanPluginSearchPaths ( pluginDirs , log ) { function recursiveScanFolder ( ent ) { return from ( [ ent ] ) . pipe ( mergeMap ( ( entry ) => { return findManifestInFolder ( entry . dir , ( ) => { if ( entry . depth > maxScanDepth ) { return [ ] ; } return mapSubdirectories ( entry . dir , ( subDir ) => recursiveScanFolder ( { dir : subDir , depth : entry . depth + 1 } ) ) ; } ) ; } ) ) ; } return from ( pluginDirs . map ( ( dir ) => ( { dir , depth : 0 } ) ) ) . pipe ( mergeMap ( ( entry ) => { log . debug ( `Scanning "${ entry . dir }" for plugin sub-directories...` ) ; return fsReadDir$ ( entry . dir ) . pipe ( mergeMap ( ( ) => recursiveScanFolder ( entry ) ) , catchError ( ( err ) => [ PluginDiscoveryError . invalidSearchPath ( entry . dir , err ) ] ) ) ; } ) ) ; } param dir param notFound function findManifestInFolder ( dir , notFound ) { return fsStat$ ( resolve ( dir , 'kibana.json' ) ) . pipe ( mergeMap ( ( stats ) => { if ( stats . isFile ( ) ) { return [ dir ] ; } return [ ] ; } ) , catchError ( ( manifestStatError ) => { if ( manifestStatError . code !== 'ENOENT' ) { return [ PluginDiscoveryError . invalidPluginPath ( dir , manifestStatError ) ] ; } return notFound ( ) ; } ) ) ; } param dir param mapFunc function mapSubdirectories ( dir , mapFunc ) { return fsReadDir$ ( dir ) . pipe ( mergeMap ( ( subDirs ) => subDirs . map ( ( subDir ) => resolve ( dir , subDir ) ) ) , mergeMap ( ( subDir ) => fsStat$ ( subDir ) . pipe ( mergeMap ( ( pathStat ) => ( pathStat . isDirectory ( ) ? mapFunc ( subDir ) : [ ] ) ) , catchError ( ( subDirStatError ) => [ PluginDiscoveryError . invalidPluginPath ( subDir , subDirStatError ) , ] ) ) ) ) ; }