问题如何将多个工作流连接在一起?目标学习如何从多个CWL工作流描述构建嵌套工作流。
工作流是将多个工具组合起来执行更大的操作的方法。我们也可以把工作流看作是工具本身;一个CWL工作流可以作为另一个CWL工作流的一个步骤,如果工作流引擎支持子工作流特性需求:
requirements:SubworkflowFeatureRequirement: {}
下面是一个使用1st-workflow.cwl作为一个嵌套的工作流:
nestedworkflows.cwl
#!/usr/bin/env cwl-runnercwlVersion: v1.0class: Workflowinputs: []outputs:classout:type: FileoutputSource: compile/compiled_classrequirements:SubworkflowFeatureRequirement: {}steps:compile:run: 1st-workflow.cwlin:tarball: create-tar/tar_compressed_java_filename_of_file_to_extract:default: "Hello.java"out: [compiled_class]create-tar:in: []out: [tar_compressed_java_file]run:class: CommandLineToolrequirements:InitialWorkDirRequirement:listing:- entryname: Hello.javaentry: |public class Hello {public static void main(String[] argv) {System.out.println("Hello from Java");}}inputs: []baseCommand: [tar, --create, --file=hello.tar, Hello.java]outputs:tar_compressed_java_file:type: Filestreamable: trueoutputBinding:glob: "hello.tar"
CWL工作流可以像命令行工具一样作为一个步骤使用,它的CWL文件包含在run中。然后,工作流输入(inp和ex)和输出(classout)可以被映射为步骤的输入/输出。
compile:run: 1st-workflow.cwlin:inp:source: create-tar/tarex:default: "Hello.java"out: [classout]
我们1st-workflow.cwl是用工作流输入参数化的,所以在运行它时,我们必须提供一个作业文件来表示tar文件和*.java文件名。这通常是最佳实践,因为这意味着它可以在多个父工作流中重用,甚至在同一个工作流中的多个步骤中重用。
这里我们使用default:来硬编码“Hello”。作为ex输入,我们的工作流程也需要一个在inp的tar文件,我们将在create-tar步骤中准备它。在这一点上,重构第一个工作流可能是个好主意。使cwl具有更具体的输入/输出名称,因为这些名称也在其作为工具使用时出现。
还可以采用不那么通用的方法,避免作业文件中的外部依赖关系。因此,在这个工作流中,我们可以在将其添加到tar文件之前,使用前面提到的InitialWorkDirRequirement需求生成一个硬编码的Hello.java文件。
create-tar:requirements:InitialWorkDirRequirement:listing:- entryname: Hello.javaentry: |public class Hello {public static void main(String[] argv) {System.out.println("Hello from Java");}}
在这种情况下,我们的步骤可以假设Hello.java,而不是参数化,所以只要CWL工作流引擎支持shellcommandrequire,我们就可以使用更简单的参数形式:
run:class: CommandLineToolrequirements:ShellCommandRequirement: {}arguments:- shellQuote: falsevalueFrom: >tar cf hello.tar Hello.java
注意这里使用了shellQuote: false,否则shell会尝试执行带引号的二进制文件”tar cf hello.tar Hello.java”。
这里的>块意味着换行符被剥离,因此可以在多行中编写单个命令。类似地,我们上面使用的|将保留换行符,并与shellcommandrerequirement相结合,这将允许嵌入shell脚本。不过,在CWL中应该少用Shell命令,因为这意味着你“跳出”了工作流,不再获得可重用的组件、来源或可伸缩性。为了再现性和可移植性,建议只使用带有DockerRequirement提示的shell命令,这样命令就可以在可预测的shell环境中执行。
你是否注意到我们没有将tar cf工具分割成一个单独的文件,而是将其嵌入到CWL工作流文件中?这通常不是最佳实践,因为工具无法重用。在本例中这样做的原因是,命令行是用文件名硬编码的,这些文件名只在此工作流中有意义。
在本例中,我们必须在外部准备一个tar文件,但这只是因为我们的内部工作流被设计为将其作为输入。对内部工作流更好的重构是采用一个要编译的Java文件列表,这将简化其在其他工作流中作为工具步骤的使用。
嵌套工作流是一个强大的特性,可以生成更高级的功能和可重用的工作流单元——但就像创建CWL工具描述一样,必须注意提高它在多个工作流中的可用性。
