Merge branch '2411-check-copyright'
[arvados.git] / doc / user / cwl / cwl-style.html.textile.liquid
1 ---
2 layout: default
3 navsection: userguide
4 title: Best Practices for writing CWL
5 ...
6 {% comment %}
7 Copyright (C) The Arvados Authors. All rights reserved.
8
9 SPDX-License-Identifier: CC-BY-SA-3.0
10 {% endcomment %}
11
12 * To run on Arvados, a workflow should provide a @DockerRequirement@ in the @hints@ section.
13
14 * Build a reusable library of components.  Share tool wrappers and subworkflows between projects.  Make use of and contribute to "community maintained workflows and tools":https://github.com/common-workflow-language/workflows and tool registries such as "Dockstore":http://dockstore.org .
15
16 * When combining a parameter value with a string, such as adding a filename extension, write @$(inputs.file.basename).ext@ instead of @$(inputs.file.basename + 'ext')@.  The first form is evaluated as a simple text substitution, the second form (using the @+@ operator) is evaluated as an arbitrary Javascript expression and requires that you declare @InlineJavascriptRequirement@.
17
18 * Avoid declaring @InlineJavascriptRequirement@ or @ShellCommandRequirement@ unless you specifically need them.  Don't include them "just in case" because they change the default behavior and may imply extra overhead.
19
20 * Don't write CWL scripts that access the Arvados SDK.  This is non-portable; a script that access Arvados directly won't work with @cwltool@ or crunch v2.
21
22 * CommandLineTools wrapping custom scripts should represent the script as an input parameter with the script file as a default value.  Use @secondaryFiles@ for scripts that consist of multiple files.  For example:
23
24 <pre>
25 cwlVersion: v1.0
26 class: CommandLineTool
27 baseCommand: python
28 inputs:
29   script:
30     type: File
31     inputBinding: {position: 1}
32     default:
33       class: File
34       location: bclfastq.py
35       secondaryFiles:
36         - class: File
37           location: helper1.py
38         - class: File
39           location: helper2.py
40   inputfile:
41     type: File
42     inputBinding: {position: 2}
43 outputs:
44   out:
45     type: File
46     outputBinding:
47       glob: "*.fastq"
48 </pre>
49
50 * You can get the designated temporary directory using @$(runtime.tmpdir)@ in your CWL file, or from the @$TMPDIR@ environment variable in your script.
51
52 * Similarly, you can get the designated output directory using $(runtime.outdir), or from the @HOME@ environment variable in your script.
53
54 * Use @ExpressionTool@ to efficiently rearrange input files between steps of a Workflow.  For example, the following expression accepts a directory containing files paired by @_R1_@ and @_R2_@ and produces an array of Directories containing each pair.
55
56 <pre>
57 class: ExpressionTool
58 cwlVersion: v1.0
59 inputs:
60   inputdir: Directory
61 outputs:
62   out: Directory[]
63 requirements:
64   InlineJavascriptRequirement: {}
65 expression: |
66   ${
67     var samples = {};
68     for (var i = 0; i < inputs.inputdir.listing.length; i++) {
69       var file = inputs.inputdir.listing[i];
70       var groups = file.basename.match(/^(.+)(_R[12]_)(.+)$/);
71       if (groups) {
72         if (!samples[groups[1]]) {
73           samples[groups[1]] = [];
74         }
75         samples[groups[1]].push(file);
76       }
77     }
78     var dirs = [];
79     for (var key in samples) {
80       dirs.push({"class": "Directory",
81                  "basename": key,
82                  "listing": [samples[key]]});
83     }
84     return {"out": dirs};
85   }
86 </pre>
87
88 * Avoid specifying resource requirements in CommandLineTool.  Prefer to specify them in the workflow.  You can provide a default resource requirement in the top level @hints@ section, and individual steps can override it with their own resource requirement.
89
90 <pre>
91 cwlVersion: v1.0
92 class: Workflow
93 inputs:
94   inp: File
95 hints:
96   ResourceRequirement:
97     ramMin: 1000
98     coresMin: 1
99     tmpdirMin: 45000
100 steps:
101   step1:
102     in: {inp: inp}
103     out: [out]
104     run: tool1.cwl
105   step2:
106     in: {inp: step1/inp}
107     out: [out]
108     run: tool2.cwl
109     hints:
110       ResourceRequirement:
111         ramMin: 2000
112         coresMin: 2
113         tmpdirMin: 90000
114 </pre>
115
116 * Instead of scattering separate steps, prefer to scatter over a subworkflow.
117
118 With the following pattern, @step1@ has to wait for all samples to complete before @step2@ can start computing on any samples.  This means a single long-running sample can prevent the rest of the workflow from moving on:
119
120 <pre>
121 cwlVersion: v1.0
122 class: Workflow
123 inputs:
124   inp: File
125 steps:
126   step1:
127     in: {inp: inp}
128     scatter: inp
129     out: [out]
130     run: tool1.cwl
131   step2:
132     in: {inp: step1/inp}
133     scatter: inp
134     out: [out]
135     run: tool2.cwl
136   step3:
137     in: {inp: step2/inp}
138     scatter: inp
139     out: [out]
140     run: tool3.cwl
141 </pre>
142
143 Instead, scatter over a subworkflow.  In this pattern, a sample can proceed to @step2@ as soon as @step1@ is done, independently of any other samples.
144 Example: (note, the subworkflow can also be put in a separate file)
145
146 <pre>
147 cwlVersion: v1.0
148 class: Workflow
149 steps:
150   step1:
151     in: {inp: inp}
152     scatter: inp
153     out: [out]
154     run:
155       class: Workflow
156       inputs:
157         inp: File
158       outputs:
159         out:
160           type: File
161           outputSource: step3/out
162       steps:
163         step1:
164           in: {inp: inp}
165           out: [out]
166           run: tool1.cwl
167         step2:
168           in: {inp: step1/inp}
169           out: [out]
170           run: tool2.cwl
171         step3:
172           in: {inp: step2/inp}
173           out: [out]
174           run: tool3.cwl
175 </pre>
176
177 * When migrating from crunch v1 API (--api=jobs) to the crunch v2 API (--api=containers) there are a few differences in behavior:
178 ** The tool is limited to accessing only collections which are explicitly listed in the input, and further limited to only the subdirectories of collections listed in input.  For example, given an explicit file input @/dir/subdir/file1.txt@, a tool will not be able to implicitly access the file @/dir/file2.txt@.  Use @secondaryFiles@ or a @Directory@ input to describe trees of files.
179 ** Files listed in @InitialWorkDirRequirement@ appear in the output directory as normal files (not symlinks) but cannot be moved, renamed or deleted.  These files will be added to the output collection but without any additional copies of the underlying data.
180 ** Tools are disallowed network access by default.  Tools which require network access must include @arv:APIRequirement: {}@ in their @requirements@ section.