十一 Advanced Inputs
如何描述哪些参数必须和不必须使用?
学习如何使用记录来描述输入之间的关系。
有时候一个工具几个参数必须一起使用(相互依赖) ,或者几个参数不能一起使用(排他)。 可以使用记录和类型联合将参数组合在一起来描述这两种情况。
record.cwl
#!/usr/bin/env cwl-runner
cwlVersion: v1.0
class: CommandLineTool
inputs:
dependent_parameters: ******
type:
type: record
name: dependent_parameters
fields:
itemA:
type: string
inputBinding:
prefix: -A
itemB:
type: string
inputBinding:
prefix: -B
exclusive_parameters: ******
type:
- type: record
name: itemC
fields:
itemC:
type: string
inputBinding:
prefix: -C
- type: record
name: itemD
fields:
itemD:
type: string
inputBinding:
prefix: -D
outputs:
example_out:
type: stdout
stdout: output.txt
baseCommand: echo
record-job1.yml
dependent_parameters:
itemA: one
exclusive_parameters:
itemC: three
$ cwl-runner record.cwl record-job1.yml
Workflow error, try again with --debug for more information:
Invalid job input record:
record-job1.yml:1:1: the `dependent_parameters` field is not valid because
missing required field `itemB`
在第一个例子中,你不能只使用itemA
而不使用itemB
。
record-job2.yml
dependent_parameters:
itemA: one
itemB: two
exclusive_parameters:
itemC: three
itemD: four
$ cwl-runner record.cwl record-job2.yml
record-job2.yml:6:3: invalid field `itemD`, expected one of: 'itemC'
[job record.cwl] /home/example$ echo \
-A \
one \
-B \
two \
-C \
three > /home/example/output.txt
[job record.cwl] completed success
{
"example_out": {
"location": "file:///home/example/11-records/output.txt",
"basename": "output.txt",
"class": "File",
"checksum": "sha1$329fe3b598fed0dfd40f511522eaf386edb2d077",
"size": 23,
"path": "/home/example/output.txt"
}
}
Final process status is success
$ cat output.txt
-A one -B two -C three
在第二个示例中,itemC
和itemD
是排他的,因此只有itemC
被添加到命令行,itemD
被忽略。
record-job3.yml
dependent_parameters:
itemA: one
itemB: two
exclusive_parameters:
itemD: four
$ cwl-runner record.cwl record-job3.yml
[job record.cwl] /home/example$ echo \
-A \
one \
-B \
two \
-D \
four > /home/example/output.txt
[job record.cwl] completed success
{
"example_out": {
"location": "file:///home/example/output.txt",
"basename": "output.txt",
"class": "File",
"checksum": "sha1$77f572b28e441240a5e30eb14f1d300bcc13a3b4",
"size": 22,
"path": "/home/example/output.txt"
}
}
Final process status is success
$ cat output.txt
-A one -B two -D four
在第三个示例中,只提供了itemD
,因此它出现在命令行上。
总结
- 使用
record
字段将参数组在一起。 - 同一参数中的多个
record
被视为排他的。
十二 环境变量
工具在受限制的环境中运行,并且不从父进程继承大多数环境变量。 可以使用EnvVarRequirement
为工具设置环境变量。
env.cwl
#!/usr/bin/env cwl-runner
cwlVersion: v1.0
class: CommandLineTool
baseCommand: env
requirements: ******
EnvVarRequirement:
envDef:
HELLO: $(inputs.message)
inputs:
message: string
outputs:
example_out:
type: stdout
stdout: output.txt
echo-job.yml
message: Hello world!
$ cwl-runner env.cwl echo-job.yml
[job env.cwl] /home/example$ env > /home/example/output.txt
[job env.cwl] completed success
{
"example_out": {
"location": "file:///home/example/output.txt",
"basename": "output.txt",
"class": "File",
"checksum": "sha1$1ca16a840b14807b2fd3323022c476b06a150e2f",
"size": 94,
"path": "/home/example/output.txt"
}
}
Final process status is success
$ cat output.txt
HELLO=Hello world!
PATH=/bin:/usr/bin:/usr/local/bin
HOME=/home/example
TMPDIR=/tmp/tmp63Obpk
总结
- T工具在一个受限制的环境中运行,只有一组最小的环境变量。
- 使用
EnvVarRequirement
字段在工具的环境中设置环境变量。
十三 JavaScript Expressions
-
如果我想动态创建值,而 cwl 没有提供内置的方法,我该怎么做。
-
Learn how to insert JavaScript expressions into a CWL description.学习如何在CWL描述中插入JavaScript表达式。
如果你需要操纵输入参数,包括InlineJavascriptRequirement
,然后在任何参数引用是合法的地方,你都可以提供一个 javascript 片段,这个片段将由 CWL runner 进行评估。
注意: javascript 表达式只能在绝对必要的时候使用。 在操作文件名、扩展名、路径等时,考虑是否可以使用内置的文件属性,如 basename、 nameroot、 nameext 等。
expression.cwl
#!/usr/bin/env cwl-runner
cwlVersion: v1.0
class: CommandLineTool
baseCommand: echo
requirements:
InlineJavascriptRequirement: {}
inputs: []
outputs:
example_out:
type: stdout
stdout: output.txt
arguments:
- prefix: -A
valueFrom: $(1+1)
- prefix: -B
valueFrom: $("/foo/bar/baz".split('/').slice(-1)[0])
- prefix: -C
valueFrom: |
${
var r = [];
for (var i = 10; i >= 1; i--) {
r.push(i);
}
return r;
}
因为这个工具不需要任何inputs
,我们可以用一个(几乎)空的文件运行它:
empty.yml
{}
empty.yml’包含一个空 json 对象的描述。 Json 对象描述包含在大括号 {}
中,因此空对象仅由一组空括号表示。
运行expression.cwl
:
$ cwl-runner expression.cwl empty.yml
[job expression.cwl] /home/example$ echo \
-A \
2 \
-B \
baz \
-C \
10 \
9 \
8 \
7 \
6 \
5 \
4 \
3 \
2 \
1 > /home/example/output.txt
[job expression.cwl] completed success
{
"example_out": {
"location": "file:///home/example/output.txt",
"basename": "output.txt",
"class": "File",
"checksum": "sha1$a739a6ff72d660d32111265e508ed2fc91f01a7c",
"size": 36,
"path": "/home/example/output.txt"
}
}
Final process status is success
$ cat output.txt
-A 2 -B baz -C 10 9 8 7 6 5 4 3 2 1
注意:需求必须以数组的形式提供,每个条目(在这种情况下,只有class: InlineJavascriptRequirement
)) 通过-
标记。 使用相同的语法来描述附加的命令行参数。
Where are JavaScript expressions allowed?
Just like parameter references, you can use JavaScript Expressions only in certain fields. These are:
- From
CommandLineTool
arguments
valueFrom
stdin
stdout
stderr
- From CommandInputParameter
format
secondaryFiles
- From
inputBinding
valueFrom
- From CommandOutputParamater
format
secondaryFiles
- From CommandOutputBinding
glob
outputEval
- From
Workflow
- From InputParameter and WorkflowOutputParameter
format
secondaryFiles
- From
steps
- From WorkflowStepInput
valueFrom
- From ExpressionTool
expression
- From InputParameter and ExpressionToolOutputParameter
format
secondaryFiles
- From
ResourceRequirement
coresMin
coresMax
ramMin
ramMax
tmpdirMin
tmpdirMax
outdirMin
outdirMax
- From
InitialWorkDirRequirement
listing
- in Dirent
entry
entryname
- From
EnvVarRequirement
- From EnvironmentDef
envValue
总结
- 如果指定了使用
InlineJavascriptRequirement
,你可以包含 Javascript 表达式,这些表达式将被 cwl runner评估. - 表达式只在特定的字段中有效。
- 表达式应该只在没有内置的 CWL 解决方案存在时使用。
十四 Creating Files at Runtime
Questions
- 我是否在运行时从输入参数创建所需的输入文件?
- 我如何调用脚本而不仅仅是一个简单的命令行?
- 除了
inputBinding
,我还能如何向工具传递参数?
Objectives
- 学习如何在运行中动态地创建文件
- 学习如何在 bash 脚本中使用表达式。
有时候,需要动态地根据输入参数创建一个文件,例如一个工具,希望从文件而不是命令行参数读取输入配置,或者需要一个小型的wrapper shell 脚本。
要生成这样的文件,我们可以使用InitialWorkDirRequirement
。
createfile.cwl
class: CommandLineTool
cwlVersion: v1.0
baseCommand: ["sh", "example.sh"]
requirements:
InitialWorkDirRequirement: ******
listing:
- entryname: example.sh
entry: |-
PREFIX='Message is:'
MSG="\${PREFIX} $(inputs.message)"
echo \${MSG}
inputs:
message: string
outputs:
example_out:
type: stdout
stdout: output.txt
在创建文件之前,任何表达式(比如$(inputs.message)
都会被 CWL引擎展开; 这里在 inputmessage
处插入value值。
Tip
CWL表达式独立于命令行工具调用期间后面使用的任何 shell 变量。 例如上面的 \${PREFIX}
扩展为 ${PREFIX}
,由 shell 脚本而不是 cwl 引擎进行计算。
为了测试上面的CWL工具,使用这个作业提供 input的value值message
:
echo-job.yml
message: Hello world!
在我们开始之前,让我们看看每一步的细节。命令 baseCommand: ["sh", "example.sh"]
将执行命令sh example.sh
。 这将运行我们在 shell 中创建的文件。
InitialWorkDirRequirement
需要一个listing
。由于listing
是一个YAML数组,我们需要在数组的每个元素的第一行上有一个-
。在本例中,我们只有一个元素。entryname:
可以有任何value值,但必须与baseCommand
中指定的值匹配。最后一部分是entry:
,后面跟着是|-
,这是YAML引用语法,意味着使用的是多行字符串(没有它,我们需要在一行上编写整个脚本)。
$ cwl-runner createfile.cwl echo-job.yml
[job createfile.cwl] /private/tmp/docker_tmphrqxxcdl$ sh \
example.sh > /private/tmp/docker_tmphrqxxcdl/output.txt
Could not collect memory usage, job ended before monitoring began.
[job createfile.cwl] completed success
{
"example_out": {
"location": "file:///home/example/output.txt",
"basename": "output.txt",
"class": "File",
"checksum": "sha1$9045abe4bd04dd8ccfe50c6ff61820b784b64aa7",
"size": 25,
"path": "/home/example/output.txt"
}
}
Final process status is success
$ cat output.txt
Message is: Hello world!
总结
- 使用
InitialWorkDirRequirement
来指定在工具运行时需要创建的输入文件。
十五 暂存输入文件
问题
- 如果工具需要将输出写入到其输入文件存储的目录,该怎么办?
通常,输入文件位于与输出目录分开的只读目录中。如果底层工具希望将其输出文件与输入文件一起写入同一目录,则会出现问题。使用InitialWorkDirRequirement
将输入文件暂存到输出目录中。在本例中,我们使用一个JavaScript表达式从其主目录路径中提取输入文件的base name。
linkfile.cwl
#!/usr/bin/env cwl-runner
cwlVersion: v1.0
class: CommandLineTool
hints:
DockerRequirement:
dockerPull: openjdk:9.0.1-11-slim
baseCommand: javac
requirements:
InitialWorkDirRequirement:
listing:
- $(inputs.src)
inputs:
src:
type: File
inputBinding:
position: 1
valueFrom: $(self.basename)
outputs:
classfile:
type: File
outputBinding:
glob: "*.class"
arguments-job.yml
src:
class: File
path: Hello.java
$ cwl-runner linkfile.cwl arguments-job.yml
[job 139928309171664] /home/example$ docker run -i --volume=/home/example/Hello.java:/var/lib/cwl/job557617295_examples/Hello.java:ro --volume=/home/example:/var/spool/cwl:rw --volume=/tmp/tmpmNbApw:/tmp:rw --workdir=/var/spool/cwl --read-only=true --net=none --user=1001 --rm --env=TMPDIR=/tmp java:7 javac Hello.java
Final process status is success
{
"classfile": {
"size": 416,
"location": "/home/example/Hello.class",
"checksum": "sha1$2f7ac33c1f3aac3f1fec7b936b6562422c85b38a",
"class": "File"
}
}
总结
- 输入文件通常保存在只读目录中。
- 使用
InitialWorkDirRequirement
将输入文件暂存到工作目录中。
网友评论