import { OrgFormationError } from '../org-formation-error' ; import { IBuildTask , IBuildTaskConfiguration } from './build-configuration' ; import { UpdateOrganizationTaskProvider } from './tasks/organization-task' ; import { UpdateStacksBuildTaskProvider } from './tasks/update-stacks-task' ; import { IncludeTaskProvider } from './tasks/include-task' ; import { IPerformTasksCommandArgs } from '~commands/index' ; import { ITrackedTask } from '~state/persisted-state' ; import { PluginProvider } from '~plugin/plugin' ; import { PluginBuildTaskProvider } from '~plugin/plugin-task' ; import { CfnExpressionResolver } from '~core/cfn-expression-resolver' ; export class BuildTaskProvider { private static SingleInstance : BuildTaskProvider ; private providers : Record < string , IBuildTaskProvider < any > > = { } ; constructor ( providers ) { for ( const provider of providers ) { this . providers [ provider . type ] = provider ; } } private static GetBuildTaskProvider ( ) { if ( BuildTaskProvider . SingleInstance ) { return BuildTaskProvider . SingleInstance ; } const buildTaskProviders = [ new UpdateStacksBuildTaskProvider ( ) , new UpdateOrganizationTaskProvider ( ) , new IncludeTaskProvider ( ) , ] ; for ( const plugin of PluginProvider . GetPlugins ( ) ) { buildTaskProviders . push ( new PluginBuildTaskProvider < any , any , any > ( plugin ) ) ; } return BuildTaskProvider . SingleInstance = new BuildTaskProvider ( buildTaskProviders ) ; } public static createValidationTask ( configuration , command , resolver ) { const taskProvider = this . GetBuildTaskProvider ( ) ; const provider = taskProvider . providers [ configuration . Type ] ; if ( provider === undefined ) { throw new OrgFormationError ( `unable to load file ${ configuration . FilePath }, unknown configuration type ${ configuration . Type }` ) ; } const validationTask = provider . createTaskForValidation ( configuration , command , resolver ) ; return validationTask ; } static createPrintTask ( configuration , command , resolver ) { const taskProvider = this . GetBuildTaskProvider ( ) ; const provider = taskProvider . providers [ configuration . Type ] ; if ( provider === undefined ) { throw new OrgFormationError ( `unable to load file ${ configuration . FilePath }, unknown configuration type ${ configuration . Type }` ) ; } const validationTask = provider . createTaskForPrint ( configuration , command , resolver ) ; return validationTask ; } public static createBuildTask ( configuration , command , resolver ) { const taskProvider = this . GetBuildTaskProvider ( ) ; const provider = taskProvider . providers [ configuration . Type ] ; if ( provider === undefined ) { throw new OrgFormationError ( `unable to load file ${ configuration . FilePath }, unknown configuration type ${ configuration . Type }` ) ; } const task = provider . createTask ( configuration , command , resolver ) ; return task ; } public static createDeleteTask ( logicalId , type , physicalId , concurrencyForCleanup , command ) { const taskProvider = this . GetBuildTaskProvider ( ) ; const provider = taskProvider . providers [ type ] ; if ( provider === undefined ) { throw new OrgFormationError ( `unable to load file, unknown configuration type ${ type }` ) ; } const task = provider . createTaskForCleanup ( logicalId , physicalId , command , concurrencyForCleanup ) ; return task ; } public static enumTasksForCleanup ( previouslyTracked , tasks , command ) { const result = [ ] ; const currentTasks = BuildTaskProvider . recursivelyFilter ( tasks , t => t . physicalIdForCleanup !== undefined ) ; const physicalIds = currentTasks . map ( x => x . physicalIdForCleanup ) ; for ( const tracked of previouslyTracked ) { if ( ! physicalIds . includes ( tracked . physicalIdForCleanup ) ) { const deleteTask = this . createDeleteTask ( tracked . logicalName , tracked . type , tracked . physicalIdForCleanup , tracked . concurrencyForCleanup , command ) ; if ( deleteTask !== undefined ) { result . push ( deleteTask ) ; } } } return result ; } public static recursivelyFilter ( tasks , filter ) { const result = tasks . filter ( filter ) ; const tasksWithChildren = tasks . filter ( x => x . childTasks && x . childTasks . length > 0 ) ; const childrenFlattened = tasksWithChildren . reduce ( ( acc , x ) => acc . concat ( ... x . childTasks ) , [ ] ) ; if ( childrenFlattened . length > 0 ) { const resultFromChildren = BuildTaskProvider . recursivelyFilter ( childrenFlattened , filter ) ; return result . concat ( resultFromChildren ) ; } return result ; } public static createIsDependency ( buildTaskConfig ) { return ( task ) : boolean => { if ( task . type === 'update-organization' ) { return true ; } if ( task . childTasks && task . childTasks . length > 0 ) { if ( buildTaskConfig . Type !== task . type || buildTaskConfig . LogicalName !== task . name ) { const updateOrgTasks = this . recursivelyFilter ( task . childTasks , t => t . type === 'update-organization' ) ; if ( updateOrgTasks . length > 0 ) { return true ; } } } if ( typeof buildTaskConfig . DependsOn === 'string' ) { return task . name === buildTaskConfig . DependsOn ; } else if ( Array . isArray ( buildTaskConfig . DependsOn ) ) { return buildTaskConfig . DependsOn . includes ( task . name ) ; } } ; } } export interface IBuildTaskProvider < TConfig extends IBuildTaskConfiguration > { type : string ; createTask ( config , command , resolver ? ) : IBuildTask ; createTaskForValidation ( config , command , resolver ? ) : IBuildTask | undefined ; createTaskForPrint ( config , command , resolver ? ) : IBuildTask | undefined ; createTaskForCleanup ( logicalId , physicalId , command , concurrencyForCleanup , resolver ? ) : IBuildTask | undefined ; }