# flow-classes.psm1
<#
 The engine that runs an individual Workflow.

History:
  EC2619 - original from V3 code with major restructuring

#>

<##.mod-doc
flow-classes.psm1
================

_PSEC version 0.0.9_

#### Classes rational ####

This module contains the class definitions for the classes used in the workflow system.

Unlike Java, Powershell cannot handle circular references so this contortion was resorted to. Namesly:

1. Define all classes in 'classes' module that is included.
2. Extend each class with ....Exec class that has logic for each and rely on fact Powershell can find methods at runtime.


#>

<#.std-parms
.parm $cfg Loaded config file
.parm $task Task reference pointer
.parm $par Parent panel (container)
.parm $flow Flow reference pointer
.parm $lab Label reference pointer
#>

using namespace System.Collections;
using module .\gui-classes.psm1
using module .\gui-utils.psm1

set-strictmode -version 2.0

enum TaskType {
  Java
  Manual
  Script
  NodeJS
  CfgErr
}

<#.md
.desc
A subclass of the Form class used to implement the Workflow GUI
.details
This subclass contains a few more properties used to manage the Workflow GUI
#>
class WflForm : Form { #---- properties ---- [hashtable] $tasks; [object[]] $taskList; [Task] $cycleController; # cycleController - one per form [hashtable] $cycle; # current settings of cycleController [Task] $activeTask; # EC8C20 - global pointer [Flow] $flow; # Related @@Flow [string] $psecBase; # Where PSEC is running from [string] $baseLocn; # Where base workflow is located [int] $helpW = 1000; # default width of help. Override in setup [int] $helpH = 670; # default height of help. Override in setup #---- constructors ---- WflForm([System.Object]$peer,[string]$title,[int32]$wid,[int32]$hgt) :base($peer,$title,$wid,$hgt) { $this.tasks = @{} $this.taskList = @() $this.cycle = @{} } } <#.md .desc The main Flow object used in the GUI Workflow application described in @@link.wfl-impl .details This is extended by FlowExec so that custom objects can be added to a particular workflow. #> #>
class Flow { # Container object #---- properties ---- [Form] $wflForm; #Related @@Form [string] $wflName; #public name [string] $cfgPath; #static CFG path [hashtable] $dynHT; #current values, likely stowed [string] $dynPath; #dynamic CFG path [string] $flowPath; #base path to flow task dirs [string] $libPath; #base path to lib flow task dirs [PSCustomObject]$libSetup; #lib setup execution script [PSCustomObject]$flowSetup; #flow setup execution script [TaskFlowStruc] $tfs; #Global @@Task @@Flow structure [ArrayList] $tasks; # List of Tasks [int16] $majorStepSeq; [int16] $minorStepSeq; [task] $priorTask; [task] $minorPriorTask; #---- constructors ---- Flow([string]$wflName,[TaskFlowStruc]$tfs){ $this.wflName = $wflName; $this.tfs = $tfs; $this.tasks = New-Object ArrayList; } #---- methods ---- <#.md .desc return vital parts of *Flow* object. #>
[String]ToString() { $out = 'Flow.{0},[t={1},cfg={2}]' -f $this.wflName,$this.tasks.count,$this.cfgPath return $out } } <#.md .desc This structure (or its extension) is passed to all @@Task script files as the *tfs* parameter. .details It is used to contain and pass information between tasks and to provide custom information to the tasks. The $globMap is used to contain named structures that may be passed between tasks. The developer is advised to come up with a meaningful naming strategy so the use of the structures can easily be found with an editor. The tfs extension or the class definitions for the $globMap need to be defined in the x-setup.psm where x is the flow name. #>
class TaskFlowStruc { # base class that can be extended in setup to provide workflow specific values and methods [hashtable]$pathFuncs; #: Array of paths [hashtable]$pathStrs; #: Converted array of paths for optimization [hashtable]$globMap; #: Array of globals depending on application TaskFlowStruc() { $this.pathFuncs = @{}; $this.pathStrs = @{}; $this.globMap = @{}; } } <#.md .desc combine @@Elem to the the @@Task and @@Flow with a processing function that handles the action. .details Used by action processors #> #>
class ActionSet { #---- properties ---- [Flow]$flow; [Task]$task; [ScriptBlock]$func; #---- constructors ---- ActionSet([Flow]$flow,[Task]$task,[ScriptBlock]$func) { $this.flow = $flow; $this.task = $task; $this.func = $func; }
[void] actionMethod([Elem]$elem,[Object]$ctx) { hlog("action method invoked func=$($null -ne $this.func)") if ($null -ne $this.func) { [void](& $this.func $this $elem $ctx) } } } <#.md .desc Implemention context for a Manual type Task. .details Used by manual step processors #>
class ManStep { #Manual Step #---- properties ---- [task] $task; [string] $name; [int16] $line; [boolean] $bIgnore; #do not reflect change to Brief [elem] $chkBox; #---- methods ----
[String]ToString() { $out = "ManStep.{0}[{1},{2}]" -f $this.ix,$this.name,$this.bIgnore return $out } } <#.md .desc Exit for a run completion. .details This allows for processing to be added when a @@Task ends (such as starting the Excel processor). #>
class RunDone { #Manual Step #---- properties ---- [Task] $task; [string] $outstr; [hashtable] $parmsHT; #---- constructors ---- RunDone([Task]$task) { $this.task = $task; $this.outstr = ""; $this.parmsHT = @{}; } #---- methods ----
[String]ToString() { $out = "RunDone.{0}[{1},{2}]" -f $this.task.type,$this.task.name return $out } } <#.md .desc Implemention context for a @@Task viewing. .details This is a placeholder class that allows for a subclass to be defined without using circular references in multiple modules (which breaks Powershell). #>
class ViewTask { #---- properties ---- [Flow] $flow; #Related @@Flow [Task] $taskPtr #Related @@Task [Panel] $menuPan #Related left side @@Panel [Panel] $statPan #Related right side @@Panel [Div] $anchors #Anchors we might need #---- constructors ---- ViewTask([Flow]$flow,[Task]$task,[Panel]$menuPan,[Panel]$statPan,[Div]$anchors) { $this.flow = $flow; $this.taskPtr = $task; $this.menuPan = $menuPan; $this.statPan = $statPan; $this.anchors = $anchors; $task.viewTask = $this; } } <#.md .desc Main Workflow context .details This is the main object of each Workflow step. It also is used to register @@Elem objects so they can be found by name. There are many copies of the same @@Panel pattern. A naming scheme would become overly complex. The altenative, which is what is used, is to register names against the Task and have a lookup mechanism. The Task has many pointers to other objects. The Task type property differentiates between the type of task inplemented. .Notes The Task is used by both the @@Config and the @@workflow. Consequently phase 1 of the creation of the Task object populates the linkage. Phase 2 populates the @@GUI components. #>
class Task { #---- properties ---- [int16] $seq; # seq of execution [string] $name; # task name [string] $desc; # from config. Error desc if configuration error [string] $title; # from config [TaskType] $type; # from config [hashtable] $taskCfg; #task CFG nodez`z` [string] $stepLabel; # Menu step label [string] $execlocn; # Exec configuration and status files [string] $execdef; # Exec definition file pointer [string] $execOvrDef; # EC1B13: Exec override definition file pointer for lib rtn [string] $statlocn; # Exec Brief file path [string] $loglocn; # Exec logfile save locn [string] $datalocn; # Exec results (data) outputs [string] $helplocn; # location of help files [string] $optlocn; # location of saved options settings [string] $liblocn; # EC0517 Lib location of libary task [string] $libBase; # EC0517 base Lib location [hashtable] $methods; # task defined methods [hashtable] $vbls; # task defined variables (strings) [PSCustomObject] $custObj; # container for above; [PSCustomObject] $overObj; # override object [scriptBlock] $init; [scriptBlock] $exec; [scriptBlock] $done; [scriptBlock] $fail; [boolean] $bLibTask; # Runs from library EC0516 [Form] $form; # Owning form [Flow] $flow; # Owning flow [TaskFlowStruc] $tfs; # Easy access to flow global parms [ViewTask] $viewTask; # Placeholder class for subclass implementation [Div] $menuDiv; # where menu is [Label] $statElem; [boolean] $bBroken; # errors detected that prohibit running at all [boolean] $bRunFail; # Run did not complete sucessfully [boolean] $bRunGood; # Run did complete sucessfully [boolean] $bRunStale; # Last run is stale [boolean] $bRunLocked; # Step cannot be run due to dependencies [boolean] $bRunLapsed; # Dependent step older that step dependent on #[boolean] $bRunNext; # Step s/b run next or is independant [boolean] $bIsCurrent; # Step s/b run next or is independant #[boolean] $bRunnable; # Can run task #[boolean] $bRunLater; # Dependent or previous not bRunGood [boolean] $bWhenShow; # true if whenFail active and s/b shown [boolean] $bShowPath; # EC1B13 - showe Jave class path [int64] $runTS; # timestamp of last good run or 0 [int32] $defLogWid = 600; # Log width. Can be changed by def- script [int32] $defLogHgt = 500; # Log Height. Can be changed by def- script [TabPanel] $tabPan; [hashtable] $hooks; #elem find mechanism [hashtable] $htOpts; #EC9C10 - allow params task access to option settings [Object[]] $options; #dynamic options [Task[]] $dependsOn; #Prior Tasks this one depends on [boolean] $bDevpExpose; #Expose WhenFail task for developer [Task[]] $whenFail; #Only active on failure of X. X immediately preceeds X or prev has same whenFail [Task] $priorTask; #Prior Tasks (sequential, skips whenFail) [collections.IDictionary] $brief; #last good brief or null [int64] $briefTS; #write TS or 0 (unix epoch) [ManStep[]] $manSteps; #manual steps control block [scriptBlock] $parseBriefObject; [Object] $commObj; # EC8C18 - exec started Comm Obj (eg Excel) [elem] $autoStartFlag; # - auto start flag [hashtable] $startAppOpts; # - auto start name [dialog] $prevLogDlg; # EC9B29 - close dlg on run [div] $hdrDiv; # EC9B29 - hdr panel for task [div] $bodyDiv; # EC9B29 - body panel for task [string] $origWinSize; # EC9B29 - detect resize logic needed #---- constructors ---- Task([string]$name,[string]$strType,[string]$title,[string]$desc) { $this.methods = [ordered]@{} $this.vbls = [ordered]@{} switch($strType) { "java" {$this.type = [TaskType]::Java} "manual" {$this.type = [TaskType]::Manual} "script" {$this.type = [TaskType]::Script} "nodejs" {$this.type = [TaskType]::NodeJS} "cfg-err" {$this.type = [TaskType]::CfgErr} default {throw "$strType task type not implemented"} } $this.name = $name $this.desc = $desc $this.title = $title if ($this.desc -eq "") {$this.desc = $this.title} $this.hooks = @{} } #---- methods ---- # create a find-by-name hooking scheme.
[void]hook([elem]$elem) { if ($this.hooks[$elem.name] -ne $null) {throw "attempt to hook duplicate elem $($elem.name)"} $this.hooks[$elem.name] = $elem; #hlog("hooked $elem to $this"); }
[Elem]find([string]$name) { if ($this.hooks[$name] -eq $null) {throw "attempt to find elem $name failed"} return $this.hooks[$name]; }
[Elem]optFind([string]$name) { return $this.hooks[$name]; }
[string]toString() { return "Task.$($this.name)[$($this.type),$($this.seq)]"; } }
X
PSEC - Powershell Enhanced Capability
1.2.1
  src: flow-classes.psm1

Copyright © 2018-2021, 2022, Rexcel System Inc.