diff --git a/modules/nextflow/src/main/groovy/nextflow/script/WorkflowDef.groovy b/modules/nextflow/src/main/groovy/nextflow/script/WorkflowDef.groovy index 22d052af44..c4269ad505 100644 --- a/modules/nextflow/src/main/groovy/nextflow/script/WorkflowDef.groovy +++ b/modules/nextflow/src/main/groovy/nextflow/script/WorkflowDef.groovy @@ -24,6 +24,8 @@ import nextflow.exception.MissingProcessException import nextflow.exception.MissingValueException import nextflow.exception.ScriptRuntimeException import nextflow.extension.CH +import nextflow.plugin.Plugins +import nextflow.plugin.WorkflowInterceptor import nextflow.util.TestOnly /** * Models a script workflow component @@ -181,6 +183,17 @@ class WorkflowDef extends BindableDef implements ChainableDef, IterableDef, Exec } Object run(Object[] args) { + final interceptor = name != null ? Plugins.getExtension(WorkflowInterceptor) : null + if( interceptor != null ) { + final result = interceptor.intercept(this, args, { runDefault(args) }) + if( result instanceof ChannelOut ) + this.output = result + return result + } + return runDefault(args) + } + + private Object runDefault(Object[] args) { binding = new WorkflowBinding(owner) ExecutionStack.push(this) try { diff --git a/modules/nf-commons/src/main/nextflow/plugin/WorkflowInterceptor.groovy b/modules/nf-commons/src/main/nextflow/plugin/WorkflowInterceptor.groovy new file mode 100644 index 0000000000..58d15dc405 --- /dev/null +++ b/modules/nf-commons/src/main/nextflow/plugin/WorkflowInterceptor.groovy @@ -0,0 +1,32 @@ +package nextflow.plugin + +import org.pf4j.ExtensionPoint + +/** + * Extension point for intercepting named workflow execution. + * + * Plugins implement this interface to gain control before + * each named workflow runs. The interceptor uses the + * {@code proceed} callback to decide whether to execute + * the original workflow logic: + * - Call {@code proceed()} to execute normally, optionally + * post-processing the result (e.g. archiving) + * - Return without calling {@code proceed()} to skip + * execution (e.g. restore from archive) + * + * Entry workflows (name is null) are never intercepted. + * + * @author Zhibo Huang + */ +interface WorkflowInterceptor extends ExtensionPoint { + + /** + * Intercept the execution of a named workflow. + * + * @param workflow the named workflow definition (WorkflowDef) + * @param args the arguments passed to the workflow + * @param proceed callback that executes the original workflow logic + * @return the workflow execution result (ChannelOut) + */ + Object intercept(Object workflow, Object[] args, Closure proceed) +}