|
666 | 666 |
|
667 | 667 | *empty.yml*
|
668 | 668 | ```
|
669 |
| - - $include: examples/empty.yml |
670 |
| - - | |
| 669 | + {} |
| 670 | + | |
671 | 671 | ```
|
672 | 672 |
|
673 | 673 | We can then run `expression.cwl`:
|
|
877 | 877 | connecting the input parameter `src` to the output parameter of `untar`
|
878 | 878 | using `untar/example_out`. The output of this step `classfile` is
|
879 | 879 | connected to the `outputs` section for the Workflow, described above.
|
| 880 | +
|
| 881 | + - | |
| 882 | + ## Nested workflows |
| 883 | +
|
| 884 | + Workflows are ways to combine multiple tools to perform a larger |
| 885 | + operations. We can also think of a workflow as being a tool itself; |
| 886 | + a CWL workflow can be used as a step in another CWL workflow, if the |
| 887 | + workflow engine supports the `SubworkflowFeatureRequirement`: |
| 888 | +
|
| 889 | +
|
| 890 | + ``` |
| 891 | + requirements: |
| 892 | + - class: SubworkflowFeatureRequirement |
| 893 | + ``` |
| 894 | +
|
| 895 | + Here's an example workflow that uses our `1st-workflow.cwl` as a |
| 896 | + nested workflow: |
| 897 | +
|
| 898 | + ``` |
| 899 | + - $include: examples/nestedworkflows.cwl |
| 900 | + - | |
| 901 | + ``` |
| 902 | +
|
| 903 | + A CWL `Workflow` can be used as a `step` just like a |
| 904 | + `CommandLineTool`, it's CWL file is included with `run`. |
| 905 | + The workflow inputs (`inp` and `ex`) |
| 906 | + and outputs (`classout`) then can be mapped to become the |
| 907 | + step's input/outputs. |
| 908 | +
|
| 909 | + ``` |
| 910 | + compile: |
| 911 | + run: 1st-workflow.cwl |
| 912 | + in: |
| 913 | + inp: |
| 914 | + source: create-tar/tar |
| 915 | + ex: |
| 916 | + default: "Hello.java" |
| 917 | + out: [classout] |
| 918 | + ``` |
| 919 | +
|
| 920 | + Our `1st-workflow.cwl` was parameterized with workflow inputs, |
| 921 | + so when running it we had to provide a job file to denote |
| 922 | + the tar file and `*.java` filename. This is generally best-practice, |
| 923 | + as it means it can be reused in multiple parent workflows, |
| 924 | + or even in multiple steps within the same workflow. |
| 925 | +
|
| 926 | + Here we use `default:` to hard-code |
| 927 | + `"Hello.java" as the `ex` input, |
| 928 | + however our workflow also requires a tar file at `inp`, |
| 929 | + which we will prepare in the `create-tar` step. |
| 930 | + At this point it is probably a good idea to refactor |
| 931 | + `1st-workflow.cwl` to have more specific input/output names, |
| 932 | + as those also appear in its usage as a tool. |
| 933 | +
|
| 934 | + It is also possible to do a less generic approach and avoid |
| 935 | + external dependencies in the job file. So in this workflow we can |
| 936 | + generate a hard-coded `Hello.java` file using the |
| 937 | + previously mentioned `InitialWorkDirRequirement` requirement, before |
| 938 | + adding it to a tar file. |
| 939 | +
|
| 940 | + ``` |
| 941 | + create-tar: |
| 942 | + requirements: |
| 943 | + - class: InitialWorkDirRequirement |
| 944 | + listing: |
| 945 | + - entryname: Hello.java |
| 946 | + entry: | |
| 947 | + public class Hello { |
| 948 | + public static void main(String[] argv) { |
| 949 | + System.out.println("Hello from Java"); |
| 950 | + } |
| 951 | + } |
| 952 | + ``` |
| 953 | +
|
| 954 | + In this case our step can assume `Hello.java` rather than be |
| 955 | + parameterized, so we can use a simpler `arguments` form |
| 956 | + as long as the CWL workflow wngine supports the |
| 957 | + `ShellCommandRequirement`: |
| 958 | +
|
| 959 | + ``` |
| 960 | + run: |
| 961 | + class: CommandLineTool |
| 962 | + requirements: |
| 963 | + - class: ShellCommandRequirement |
| 964 | + arguments: |
| 965 | + - shellQuote: false |
| 966 | + valueFrom: > |
| 967 | + tar cf hello.tar Hello.java |
| 968 | + ``` |
| 969 | +
|
| 970 | + Note the use of `shellQuote: false` here, otherwise the shell will try |
| 971 | + to execute the quoted binary `"tar cf hello.tar Hello.java"`. |
| 972 | +
|
| 973 | + Here the `>` block means that newlines are stripped, so it's possible to write |
| 974 | + the single command on multiple lines. Similarly, the `|` we used above will |
| 975 | + preserve newlines, combined with `ShellCommandRequirement` this would |
| 976 | + allow embedding a shell script. |
| 977 | + Shell commands should however be used sparingly in CWL, as it |
| 978 | + means you "jump out" of the workflow and no longer get |
| 979 | + reusable components, provenance or scalability. For reproducibility |
| 980 | + and portability it is recommended to only use shell commands together |
| 981 | + with a `DockerRequirement` hint, so that |
| 982 | + the commands are executed in a predictable shell environment. |
| 983 | +
|
| 984 | + Did you notice that we didn't split out the `tar cf` tool to a separate |
| 985 | + file, but rather embedded it within the CWL Workflow file? This is generally |
| 986 | + not best practice, as the tool then can't be reused. The reason for doing it |
| 987 | + in this case is because the command line is hard-coded with filenames that |
| 988 | + only make sense within this workflow. |
| 989 | +
|
| 990 | + In this example we had to prepare a tar file outside, but only because |
| 991 | + our inner workflow was designed to take that as an input. A better |
| 992 | + refactoring of the inner workflow would be to take a list of |
| 993 | + Java files to compile, which would simplify its usage as a tool |
| 994 | + step in other workflows. |
0 commit comments