用户教程--Commandline

第一个例子

最简单的 "hello world "程序。它接受一个输入参数,向终端或工作日志写一条信息,不产生永久输出。CWL文档是用JSON或YAML编写的,或两者混合编写。我们将在本指南中使用YAML。如果你不熟悉YAML,参考这个快速教程在新窗口打开对CWL中使用的YAML有所帮助。

首先,创建一个名为1st-tool.cwl的文件,如下框所示。使用一个可以指定生成YAML或JSON文本的文本编辑器会对你有所帮助。无论你使用什么文本编辑器,在此处缩进都不应该使用制表符来创建。

1st-tool.cwl:

#!/usr/bin/env cwl-runner

cwlVersion: v1.0	#字段指示文档使用的 CWL 的版本
class: CommandLineTool	#字段表示此文档运用了命令行工具。

baseCommand: echo    #该程序提供了实际运行的程序的名称。 是bash和C的内置程序。

inputs:	#该部分描述了CWL的输入。这是输入参数的列表(有关格式的更多信息,请参阅YAML 指南),每个参数包括标识符、数据类型和可选的参数。该字段表示此输入参数应如何显示在命令行上。在此示例中,字段指示它应在命令行上的位置。
  message:
	type: string
    inputBinding:
      position: 1

outputs: []	#此工具没有正式输出,因此该部分是一个空列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14

之后,产生一个“echo-job.yml”文件(如下),该文件是另一个输入文件。

message: Hello world!
1

最后使用sixbox run命令执行:

sixbox run ./1st-tool.cwl ./echo-job.yml
1

输出结果如下:

$ sixbox run ./1st-tool.cwl ./echo-job.yml
INFO: Setting workdir to /home/test/dist
INFO: Setting workdir to /data/users/lidong/sixbox-linux-test/sixbox-linux/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/1st-tool.cwl' to 'file:///data/users/lidong/sixbox-linux-test/sixbox-linux/cwl/1st-tool.cwl'
INFO [job 1st-tool.cwl] /tmp/3_8wx0e7$ echo \
    'Hello world!'
Hello world!
INFO [job 1st-tool.cwl] completed success
{}
INFO Final process status is success
1
2
3
4
5
6
7
8
9
10
11

基本输入参数

CWL可以设计输入参数列表,每个参数都有参数名称,并添加注释哪些类型的值对该参数有效。Inputs的type可用的原始字符类型可以是: string, int, long, float, double, and null; 复杂的类型是 array and record;此外,还有特殊类型的 File, Directory and Any

以下示例演示了不同类型的某些输入参数,并以不同的方式出现在命令行上。

首先,创建一个名为* inp.cwl* 的文件,其中包含以下:

#!/usr/bin/env cwl-runner
cwlVersion: v1.0
class: CommandLineTool
baseCommand: echo
inputs:
  example_flag:
    type: Boolean	#布尔类型。如果输入参数"example_flag"为"真",则将添加到命令行中。如果为“假”,则不添加任何标志。
    inputBinding:
      position: 1
      prefix: -f	#软件参数
  example_string:
    type: string	#字符串类型以其string值显示在命令行上。如果提供,则可选。例如:--example-string hello
    inputBinding:
      position: 3
      prefix: --example-string
  example_int:
    type: int		#整数(和浮点)类型显示在带有十进制文本表示的命令行上。
    inputBinding:
      position: 2
      prefix: -i
      separate: false	#当该项为“假”(默认值为“真”)时,前缀和值合并为单个参数。例如:-i42
  example_file:
    type: File?	#问号结尾代表该参数是可选择的,如果YAML文件中有设置eample_file参数,则该参数有用,例如:--file=/tmp/random/path/whale.txt 
    inputBinding:
      prefix: --file=
      separate: false
      position: 4

outputs: []
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

创建一个文件“inp-job.yml

example_flag: true
example_string: hello
example_int: 42
example_file:
  class: File
  path: whale.txt
1
2
3
4
5
6

注意 "example_file",是一个文件类型,必须作为一个对象提供,其字段为class: Filepath

接下来,通过在命令行输入touch whale.txt,用touch创建一个whale.txt,然后用工具包装器和命令行上的输入对象调用sixbox,使用命令sixbox run ./inp.cwl ./inp-job.yml。下面的方框内的文字描述了这两个命令和命令行的预期输出。

$ touch whale.txt
$ sixbox run ./inp.cwl ./inp-job.yml
INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/inp.cwl' to 'file:///data/users/lidong/sixbox-linux-test/sixbox-linux/cwl/inp.cwl'
INFO [job inp.cwl] /tmp/qbnz5ol6$ echo \
    -f \
    -i42 \
    --example-string \
    hello \
    --file=/tmp/nmprvcao/stg31c9708e-c28c-4ad2-8a13-ccedc91a4a1f/whale.txt
-f -i42 --example-string hello --file=/tmp/nmprvcao/stg31c9708e-c28c-4ad2-8a13-ccedc91a4a1f/whale.txt
INFO [job inp.cwl] completed success
{}
INFO Final process status is success

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

输入文件是只读的(read-only)。如果你想更新一个输入文件,你必须先把它复制到输出目录。

返回输出文件

CWL可以设计输出参数列表。每个参数都有参数名称,并描述哪些类型的值对该参数有效。CWL 下运行时,起始工作目录是指定的输出目录。底层工具或脚本必须以在输出目录中创建文件的形式记录其结果。CWL 工具返回的输出参数要么是输出文件本身,要么来自对这些文件内容的检查。

以下示例演示了如何从tar压缩文件中提取文件。

#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: [tar, --extract]  #第一个是运行命令,第二个是强制参数
inputs:
  tarfile:
    type: File
    inputBinding:
      prefix: --file
outputs:
  example_out:
    type: File
    outputBinding:	# 该字段由输出目录中文件的名称组成。如果您事先不知道文件的名称,您可以使用通配符模式,如。glob: '*.txt'
      glob: hello.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

tar-job.yml:

tarfile:
  class: File
  path: hello.tar
1
2
3

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/tar.cwl' to 'file:///home/test/cwl/tar.cwl'
INFO [job tar.cwl] /tmp/a10rqvd9$ tar \
    --extract \
    --file \
    /tmp/jfs3u10a/stge6ed51da-dbc2-4379-9dec-609335983482/hello.tar
INFO [job tar.cwl] completed success
{
    "example_out": {
        "location": "file:///home/test/dist/hello.txt",
        "basename": "hello.txt",
        "class": "File",
        "checksum": "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709",
        "size": 0,
        "path": "/home/test/dist/hello.txt"
    }
}
INFO Final process status is success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

捕获标准输出

要捕获一个工具的标准输出流,在stdout字段中添加输出流应该去的文件名,然后在相应的输出参数上添加type: stdout

stdout.cwl:

#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: echo
stdout: output.txt
inputs:
  message:
    type: string
    inputBinding:
      position: 1
outputs:
  example_out:
    type: stdout
1
2
3
4
5
6
7
8
9
10
11
12
13
14

echo-job.yml:

message: Hello world!
1

输出:

INFO: Setting workdir to /home/test/dist
INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/stdout.cwl' to 'file:///home/test/cwl/stdout.cwl'
INFO [job stdout.cwl] /tmp/vfgayl00$ echo \
    'Hello world!' > /tmp/vfgayl00/output.txt
INFO [job stdout.cwl] completed success
{
    "example_out": {
        "location": "file:///home/test/dist/output.txt",
        "basename": "output.txt",
        "class": "File",
        "checksum": "sha1$47a013e660d408619d894b20806b1d5086aab03b",
        "size": 13,
        "path": "/home/test/dist/output.txt"
    }
}
INFO Final process status is success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

参数参考

在以前的一个例子中,我们用 "tar "程序提取了一个文件。然而,那个例子是非常有限的,因为它假定我们感兴趣的文件叫做 "hello.txt",并将其写入.cwl文件中。这不是最好的方法,因为 "hello.txt "的文件名可能不同,或者取决于使用的输入文件。为了避免这种情况,我们可以在参数文件(.yml)中指定我们想要的文件名。在这个例子中,你将看到如何从其他字段动态地引用输入参数的值,这将使我们能够指定要提取的文件的名称。

tar-param.cwl:

#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: [tar, --extract]
inputs:
  tarfile:
    type: File
    inputBinding:
      prefix: --file
  extractfile:
    type: string
    inputBinding:
      position: 1
outputs:
  extracted_file:
    type: File
    outputBinding:
      glob: $(inputs.extractfile)  # 参数参考文件可以写作:  $(inputs.extractfile), $(inputs["extractfile"]), and $(inputs['extractfile']) ,如果要引用tar文件的目录文件,可以写作 $(inputs.tarfile.path)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

tar-param-job.yml:

tarfile:
  class: File
  path: hello.tar
extractfile: goodbye.txt
1
2
3
4

创建你的输入文件,用工具包装器和命令行中的输入对象调用sixbox run

$ rm hello.tar || true && touch goodbye.txt && tar -cvf hello.tar goodbye.txt
$ sixbox run ./tar-param.cwl ./tar-param-job.yml
INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/tar-param.cwl' to 'file:///home/test/cwl/tar-param.cwl'
INFO [job tar-param.cwl] /tmp/by9zrutv$ tar \
    --extract \
    --file \
    /tmp/egesl7cv/stgd58a515a-b892-4e81-8edb-30a6055002f5/hello.tar \
    goodbye.txt
INFO [job tar-param.cwl] completed success
{
    "extracted_file": {
        "location": "file:///home/test/dist/goodbye.txt",
        "basename": "goodbye.txt",
        "class": "File",
        "checksum": "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709",
        "size": 0,
        "path": "/home/test/dist/goodbye.txt"
    }
}
INFO Final process status is success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

运行Docker内软件

Docker容器是为软件及其依赖环境提供简化安装的一个工具。但是,容器也有意与主机系统隔离,因此,为了在 Docker 容器内运行CWL,还需要做其他工作,以确保容器内提供输入文件,并从容器中恢复输出文件。Sixbox可以自动执行此工作,允许客户使用 Docker 简化软件管理,同时避免调用和管理 Docker 容器的复杂性。

sixbox run的职责之一是调整输入文件的路径,以反映它们显示在容器内的位置。

此示例在 Docker 容器内运行一个简单的 Node.js脚本,然后将" Hello World"打到屏上。

docker.cwl:

#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: node	#告诉CWL我们将在一个容器中运行此命令。该参数的值与docker容器传递的命令值相同
hints:	#为该部分中的工具指定 Docker 。
  DockerRequirement:
    dockerPull: node:slim
inputs:
  src:
    type: File
    inputBinding:
      position: 1
outputs:
  example_out:
    type: stdout
stdout: output.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

docker-job.yml:

src:
  class: File
  path: hello.js
1
2
3

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/docker.cwl' to 'file:///home/test/cwl/docker.cwl'
INFO [job docker.cwl] /tmp/tmpgugLND$ docker \
    run \
    -i \
    --volume=/tmp/tmpgugLND:/var/spool/cwl:rw \
    --volume=/tmp/tmpSs5JoN:/tmp:rw \
    --volume=/home/test/cwl/hello.js:/var/lib/cwl/job369354770_examples/hello.js:ro \
    --workdir=/var/spool/cwl \
    --read-only=true \
    --user=1000 \
    --rm \
    --env=TMPDIR=/tmp \
    --env=HOME=/var/spool/cwl \
    node:slim \
    node \
    /var/lib/cwl/job369354770_examples/hello.js > /tmp/tmpgugLND/output.txt
[job docker.cwl] completed success
{
    "example_out": {
        "location": "file:///home/me/cwl/user_guide/output.txt",
        "basename": "output.txt",
        "class": "File",
        "checksum": "sha1$648a6a6ffffdaa0badb23b8baf90b6168dd16b3a",
        "size": 12,
        "path": "/home/me/cwl/user_guide/output.txt"
    }
}
Final process status is success
$ cat output.txt
Hello World
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

注意sixbox run已经构建了一个Docker命令行来运行脚本。

在这个例子中,脚本hello.js的路径在容器外是/home/test/cwl/hello.js,但在容器内是/var/lib/cwl/job369354770_examples/hello.js,这反映在node命令的调用中。

其他参数

有时工具需要额外的命令行选项,这些选项并不完全对应于输入参数。

在这个例子中,我们将用Java编译器把一个java源文件编译成一个类文件。默认情下,"javac "将在与源文件相同的目录下创建类文件。然而,CWL输入文件(以及它们出现的目录)可能是只读的,所以我们需要指示 "javac "将类文件写到指定的输出目录中。

arguments.cwl:

#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
label: Example trivial wrapper for Java 9 compiler
hints:
  DockerRequirement:
    dockerPull: openjdk:9.0.1-11-slim
baseCommand: javac
arguments: ["-d", $(runtime.outdir)]	#这里添加了一个额外的参数,该参数是运行时间参数, See the Runtime Environment section of the CWL specification for details.$(runtime.outdir),$(runtime.tmpdir),$(runtime.ram),$(runtime.cores),$(runtime.outdirSize),$(runtime.tmpdirSize)
inputs:
  src:
    type: File
    inputBinding:
      position: 1
outputs:
  classfile:
    type: File
    outputBinding:
      glob: "*.class"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

arguments-job.yml:

src:
  class: File
  path: Hello.java
1
2
3

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/arguments.cwl' to 'file:///home/test/cwl/arguments.cwl'
INFO [job arguments.cwl] /tmp/tmpwYALo1$ docker \
 run \
 -i \
 --volume=/home/peter/work/common-workflow-language/v1.0/examples/Hello.java:/var/lib/cwl/stg8939ac04-7443-4990-a518-1855b2322141/Hello.java:ro \
 --volume=/tmp/tmpwYALo1:/var/spool/cwl:rw \
 --volume=/tmp/tmpptIAJ8:/tmp:rw \
 --workdir=/var/spool/cwl \
 --read-only=true \
 --user=1001 \
 --rm \
 --env=TMPDIR=/tmp \
 --env=HOME=/var/spool/cwl \
 java:7 \
 javac \
 -d \
 /var/spool/cwl \
 /var/lib/cwl/stg8939ac04-7443-4990-a518-1855b2322141/Hello.java
Final process status is success
{
  "classfile": {
    "size": 416,
    "location": "/home/example/Hello.class",
    "checksum": "sha1$2f7ac33c1f3aac3f1fec7b936b6562422c85b38a",
    "class": "File"
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

在这里,我们使用arguments字段向命令行添加一个额外的参数,这个参数并不与特定的输入参数相联系。

arguments: ["-d", $(runtime.outdir)]
1

这个例子引用了一个运行时参数。运行时参数提供了工具实际执行时的硬件或软件环境信息。$(runtime.outir)参数是指定输出目录的路径。其他参数包括$(runtime.tmpdir), $(runtime.ram), $(runtime.cores), $(runtime.outdirSize), 和$(runtime.tmpdirSize)。详情见CWL规范中的运行时环境在新窗口打开部分。

Array输入

在命令行中添加代表输入参数的数组是很容易的。有两种方法来指定一个数组参数。首先是提供类型字段,type: arrayitems,用以定义数组中可能出现的有效数据类型的项目。另外,可以在类型名称后面加上括号[],表示输入参数是该类型的数组。

array-inputs.cwl:

#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
inputs:	#阵列值应串联成由分离器字符串分离的单个参数
  filesA:
    type: string[]
    inputBinding:
      prefix: -A
      position: 1

  filesB:
    type:
      type: array
      items: string
      inputBinding:
        prefix: -B=
        separate: false
    inputBinding:
      position: 2
  filesC:
    type: string[]
    inputBinding:
      prefix: -C=
      itemSeparator: ","
      separate: false
      position: 4

outputs:
  example_out:
    type: stdout
stdout: output.txt
baseCommand: echo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

array-inputs-job.yml:

filesA: [one, two, three]
filesB: [four, five, six]
filesC: [seven, eight, nine]
1
2
3

输出:

$ sixbox run ./array-inputs.cwl ./array-inputs-job.yml
INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/array-inputs.cwl' to 'file:///home/test/cwl/array-inputs.cwl'
INFO [job array-inputs.cwl] /tmp/tmpwYALo1$ echo \
    -A \
    one \
    two \
    three \
    -B=four \
    -B=five \
    -B=six \
    -C=seven,eight,nine > /home/examples/output.txt
[job array-inputs.cwl] completed success
{
    "example_out": {
        "location": "file:///home/examples/output.txt",
        "basename": "output.txt",
        "class": "File",
        "checksum": "sha1$91038e29452bc77dcd21edef90a15075f3071540",
        "size": 60,
        "path": "/home/examples/output.txt"
    }
}
Final process status is success
$ cat output.txt
-A one two three -B=four -B=five -B=six -C=seven,eight,nine
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

inputBinding可以出现在外部数组参数定义或内部数组元素定义中,这些在构建命令行时产生不同的行为,如上所示。此外,itemSeparator字段,如果提供的话,指定数组值应该被串联成一个由item separator字符串分隔的单一参数。

注意,在array-inputs-job.yml中,输入的数组被指定在方括号[]内。数组也可以用多行来表达,其中没有定义相关键的数组值用前面的-来标记。这将在下一课中演示,并在YAML指南在新窗口打开中进行了更详细的讨论。你可以指定数组的数组、记录的数组和其他复杂的类型。

Array输出

你也可以使用glob将多个输出文件捕获为一个文件阵列。

array-outputs.cwl:

#!/usr/bin/env cwl-runner

cwlVersion: v1.0
class: CommandLineTool
baseCommand: touch
inputs:
  touchfiles:
    type:
      type: array
      items: string
    inputBinding:
      position: 1
outputs:
  output:
    type:
      type: array
      items: File
    outputBinding:
      glob: "*.txt"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

array-outputs-job.yml:

touchfiles:
  - foo.txt
  - bar.dat
  - baz.txt
1
2
3
4

输出;

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/array-outputs.cwl' to 'file:///home/test/cwl/array-outputs.cwl'
INFO [job array-outputs.cwl] /tmp/efbg6e0m$ touch \
    foo.txt \
    bar.dat \
    baz.txt
INFO [job array-outputs.cwl] completed success
{
    "output": [
        {
            "location": "file:///home/test/dist/baz.txt",
            "basename": "baz.txt",
            "class": "File",
            "checksum": "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709",
            "size": 0,
            "path": "/home/test/dist/baz.txt"
        },
        {
            "location": "file:///home/test/dist/foo.txt",
            "basename": "foo.txt",
            "class": "File",
            "checksum": "sha1$da39a3ee5e6b4b0d3255bfef95601890afd80709",
            "size": 0,
            "path": "/home/test/dist/foo.txt"
        }
    ]
}
INFO Final process status is success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

正如YAML指南在新窗口打开中所描述的,预期输出的数组在array-outputs-job.yml中被指定,每个条目都用前面的-标记。这种格式也可以在CWL描述中用来标记数组中的条目,在接下来的几个章节中都有演示。

高级输入

有时,软件工具有几个参数必须一起存在(它们是依赖的)或几个无法一起存在(它们是排他性的)。可以使用记录和类型组合将参数组合在一起来描述这两个条件。

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

record-job1.yml:

dependent_parameters:
  itemA: one
exclusive_parameters:
  itemC: three
1
2
3
4

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/record.cwl' to 'file:///home/test/cwl/record.cwl'
ERROR Workflow error, try again with --debug for more information:
Invalid job input record:
../cwl/record-job1.yml:1:1: the `dependent_parameters` field is not valid because
                              missing required field `itemB`
1
2
3
4
5
6
7

在第一个例子中,你在没提供参数 itemB,你不能用参数 itemA

record-job2.yml:

dependent_parameters:
  itemA: one
  itemB: two
exclusive_parameters:
  itemC: three
  itemD: four
1
2
3
4
5
6

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/record.cwl' to 'file:///home/test/cwl/record.cwl'
../cwl/record-job2.yml:6:3: Warning: invalid field `itemD`, expected one of: 'itemC'
INFO [job record.cwl] /tmp/2ed6ph1z$ echo \
    -A \
    one \
    -B \
    two \
    -C \
    three > /tmp/2ed6ph1z/output.txt
INFO [job record.cwl] completed success
{
    "example_out": {
        "location": "file:///home/test/dist/output.txt",
        "basename": "output.txt",
        "class": "File",
        "checksum": "sha1$329fe3b598fed0dfd40f511522eaf386edb2d077",
        "size": 23,
        "path": "/home/test/dist/output.txt"
    }
}
INFO Final process status is success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

在第二个例子中,你在同时提供参数itemC and itemD ,因为这俩是排他的,所以只有 itemC 有作用, itemD 被忽略。

record-job3.yml:

dependent_parameters:
  itemA: one
  itemB: two
exclusive_parameters:
  itemD: four
1
2
3
4
5

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/record.cwl' to 'file:///home/test/cwl/record.cwl'
INFO [job record.cwl] /tmp/i8uov7tb$ echo \
    -A \
    one \
    -B \
    two \
    -D \
    four > /tmp/i8uov7tb/output.txt
INFO [job record.cwl] completed success
{
    "example_out": {
        "location": "file:///home/test/dist/output.txt",
        "basename": "output.txt",
        "class": "File",
        "checksum": "sha1$77f572b28e441240a5e30eb14f1d300bcc13a3b4",
        "size": 22,
        "path": "/home/test/dist/output.txt"
    }
}
INFO Final process status is success
$ cat output.txt
-A one -B two -D four
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

在第三个示例中,仅提供itemD,因此它显示在命令行中。

环境变量

你可以使用EnvVarRequirement为CWL设置环境变量。

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

echo-job.yml:

message: Hello world!
1

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/env.cwl' to 'file:///home/test/cwl/env.cwl'
INFO [job env.cwl] /tmp/vx64cdln$ env > /tmp/vx64cdln/output.txt
INFO [job env.cwl] completed success
{
    "example_out": {
        "location": "file:///home/test/dist/output.txt",
        "basename": "output.txt",
        "class": "File",
        "checksum": "sha1$1506902f7cfff6955995c27126dc16dfc0cc0664",
        "size": 125,
        "path": "/home/test/dist/output.txt"
    }
}
INFO Final process status is success
root@d9313ab9e20e dist]# cat output.txt 
HELLO=Hello world!
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
HOME=/tmp/vx64cdln
TMPDIR=/tmp/s_7lxtyh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

JavaScript表达式

如果你需要操作输入参数,包括要求InlineJavascriptRequirement,并且参数引用是合法的。那么你可以提供一个Javascript片段,由sixbox run来评估该参数是否合法。

注意:只有在绝对必要时才能使用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;
      }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

由于这个工具不需要任何输入,我们可以用一个(几乎)空的参数文件运行它。

empty.yml:

{}
1

empty.yml包含一个空JSON对象的描述。JSON对象的描述包含在大括号{}内,所以一个空对象只是由一组空括号表示。

输出:

$ sixbox run ./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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/expression.cwl' to 'file:///home/test/cwl/expression.cwl'
INFO [job expression.cwl] /tmp/q70gwnzv$ echo \
    -A \
    2 \
    -B \
    baz \
    -C \
    10 \
    9 \
    8 \
    7 \
    6 \
    5 \
    4 \
    3 \
    2 \
    1 > /tmp/q70gwnzv/output.txt
INFO [job expression.cwl] completed success
{
    "example_out": {
        "location": "file:///home/test/dist/output.txt",
        "basename": "output.txt",
        "class": "File",
        "checksum": "sha1$a739a6ff72d660d32111265e508ed2fc91f01a7c",
        "size": 36,
        "path": "/home/test/dist/output.txt"
    }
}
INFO Final process status is success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

注意上述例子:

requirements:
  InlineJavascriptRequirement: {}
1
2

但作为一个数组,每个条目(在这种情况下,只有class:InlineJavascriptRequirement)也可以用"-"标记。 同样的语法也用于描述额外的命令行参数。

equirements:
  - class: InlineJavascriptRequirement
1
2

在运行时创建文件

有时,需要从输入参数(例如有些软件工具期望从文件而不是命令行参数中读取其输入配置)或需要shell脚本来快速创建文件。

要生成此类文件,我们可以使用InitialWorkDirRequirement

createfile.cwl

class: CommandLineTool
cwlVersion: v1.0
baseCommand: ["sh", "example.sh"] 	# 执行命令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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

任何像$(inputs.message)这样的表达式都会在创建文件之前被sixbox run展开

CWL 表达式与任何其他shell变量调用无关。这意味着,任何需要$字符的地方必须用\来转义,例如上面的${PREFIX},扩展到生成的文件中就是${PREFIX}。

echo-job.yml:

message: Hello world!
1

在我们运行之前,让我们更详细地看看每个步骤。基本命令baseCommand:["sh", "example.sh"] 将执行命令sh example.sh

InitialWorkDirRequirement需要一个列表。由于列表是一个YAML数组,我们需要在数组的每个元素的第一行加上一个-,在这种情况下,我们只有一个元素。 entryname:可以有任何值,但它必须与baseCommand中指定的内容一致。最后一部分是entry:,后面是|-,这是YAML的引号语法,意味着你正在使用一个多行字符串(如果没有它,我们将需要在一行中写下整个脚本)。(更多关于格式化的信息请参见YAML指南在新窗口打开)

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/createfile.cwl' to 'file:///home/test/cwl/createfile.cwl'
INFO [job createfile.cwl] /tmp/2ondtt_x$ sh \
    example.sh > /tmp/2ondtt_x/output.txt
INFO [job createfile.cwl] completed success
{
    "example_out": {
        "location": "file:///home/test/dist/output.txt",
        "basename": "output.txt",
        "class": "File",
        "checksum": "sha1$9045abe4bd04dd8ccfe50c6ff61820b784b64aa7",
        "size": 25,
        "path": "/home/test/dist/output.txt"
    }
}
INFO Final process status is success
$ cat output.txt
Message is: Hello world!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

分阶段输入文件

通常,输入文件位于与输出目录分开的仅读取目录中。如果一些软件工具希望将输出文件与输入文件一起写在同一目录中,则会导致问题。你使用InitialWorkDirRequirement将输入文件分阶段放到输出目录中。在此示例中,我们使用 JavaScript 表达式从其先前目录路径中提取输入文件的基本名称。

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"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

arguments-job.yml:

src:
  class: File
  path: Hello.java
1
2
3

输出:

INFO: Setting workdir to /home/test/sixbox-linux/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/linkfile.cwl' to 'file:///home/test/cwl/linkfile.cwl'
INFO [job linkfile.cwl] /tmp/440ouv26$ docker \
    run \
    -i \
    --mount=type=bind,source=/tmp/440ouv26,target=/kCEuXS \
    --mount=type=bind,source=/tmp/285tr1fc,target=/tmp \
    --mount=type=bind,source=/data/users/lidong/sixbox-linux-test/sixbox-linux/cwl/Hello.java,target=/kCEuXS/Hello.java,readonly \
    --workdir=/kCEuXS \
    --read-only=true \
    --user=1002:1002 \
    --rm \
    --env=TMPDIR=/tmp \
    --env=HOME=/kCEuXS \
    --cidfile=/tmp/fb8r8reu/20211105080320-738873.cid \
    openjdk:9.0.1-11-slim \
    javac \
    Hello.java
{
"classfile": {
  "size": 416,
  "location": "/home/example/Hello.class",
  "checksum": "sha1$2f7ac33c1f3aac3f1fec7b936b6562422c85b38a",
  "class": "File"
  }
}
Final process status is success
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

文件格式

工具和工作流程可以将文件类型作为输入,并将其作为输出。我们还建议指明文件类型的格式。这有助于为他人记录如何使用你的工具,同时允许你在创建参数文件时做一些简单的类型检查。

对于文件格式,我们建议引用现有的本体(例如我们的例子中的 EDAM),或在与他人共享工具之前,不要首先添加文件格式。您可以浏览__ IANA __在新窗口打开__EDAM __在新窗口打开现有文件格式列表。

metadata_example.cwl:

#!/usr/bin/env cwl-runner
cwlVersion: v1.0
class: CommandLineTool

label: An example tool demonstrating metadata.

inputs:
  aligned_sequences:
    type: File
    label: Aligned sequences in BAM format
    format: edam:format_2572
    inputBinding:
      position: 1

baseCommand: [ wc, -l ]

stdout: output.txt

outputs:
  report:
    type: stdout
    format: edam:format_1964
    label: A text file that contains a line count

$namespaces:
  edam: http://edamontology.org/
$schemas:
  - http://edamontology.org/EDAM_1.18.owl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

这个CWL描述的命令行格式等价于:

wc -l /path/to/aligned_sequences.ext > output.txt
1

sample.yml:

aligned_sequences:
    class: File
    format: http://edamontology.org/format_2572
    path: file-formats.bam
1
2
3
4

注意:为了运行下面的例子,你需要下载例子的输入文件,file-formats.bam。该文件可从https://github.com/common-workflow-language/user_guide/raw/gh-pages/_includes/cwl/16-file-formats/file-formats.bam,通过wget等方式下载。

wget https://github.com/common-workflow-language/user_guide/raw/gh-pages/_includes/cwl/16-file-formats/file-formats.bam
1

输出:

INFO: Setting workdir to /home/test/dist
INFO ./sixbox 3.0.20210124104916
INFO Resolved '../cwl/createfile.cwl' to 'file:///home/test/cwl/metadata_example.cwl:'
INFO [job metadata_example.cwl] /tmp/tmpNWyAd6$ /bin/sh \
    -c \
    'wc' '-l' '/tmp/tmpBf6m9u/stge293ac74-3d42-45c9-b506-dd35ea3e6eea/file-formats.bam' > /tmp/tmpNWyAd6/output.txt
Final process status is success
{
  "report": {
    "format": "http://edamontology.org/format_1964",
    "checksum": "sha1$49dc5004959ba9f1d07b8c00da9c46dd802cbe79",
    "basename": "output.txt",
    "location": "file:///media/large_volume/testing/cwl_tutorial2/output.txt",
    "path": "/media/large_volume/testing/cwl_tutorial2/output.txt",
    "class": "File",
    "size": 80
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

元数据和授权

对于所有的开发者,我们建议为你的工具和工作流程提供以下最小的元数据。这个例子包括允许其他人引用你的工具的元数据。

metadata_example2.cwl:

#!/usr/bin/env cwl-runner
cwlVersion: v1.0
class: CommandLineTool

label: An example tool demonstrating metadata.
doc: Note that this is an example and the metadata is not necessarily consistent.

inputs:
  aligned_sequences:
    type: File
    label: Aligned sequences in BAM format
    format: edam:format_2572
    inputBinding:
      position: 1

baseCommand: [ wc, -l ]

stdout: output.txt

outputs:
  report:
    type: stdout
    format: edam:format_1964
    label: A text file that contains a line count

s:author:
  - class: s:Person
    s:identifier: https://orcid.org/0000-0002-6130-1021
    s:email: mailto:dyuen@oicr.on.ca
    s:name: Denis Yuen

s:contributor:
  - class: s:Person
    s:identifier: http://orcid.org/0000-0002-7681-6415
    s:email: mailto:briandoconnor@gmail.com
    s:name: Brian O'Connor

s:citation: https://dx.doi.org/10.6084/m9.figshare.3115156.v2
s:codeRepository: https://github.com/common-workflow-language/common-workflow-language
s:dateCreated: "2016-12-13"
s:license: https://spdx.org/licenses/Apache-2.0 

$namespaces:
  s: https://schema.org/
  edam: http://edamontology.org/

$schemas:
 - https://schema.org/version/latest/schemaorg-current-https.rdf
 - http://edamontology.org/EDAM_1.18.owl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

等同于以下命令:

wc -l /path/to/aligned_sequences.ext > output.txt
1

额外的例子:

这个例子包括将EDAM本体标签作为关键词(允许对相关工具进行分组),提示使用该工具的硬件要求,以及其他一些元数据字段。

metadata_example3.cwl:

#!/usr/bin/env cwl-runner
cwlVersion: v1.0
class: CommandLineTool

label: An example tool demonstrating metadata.
doc: Note that this is an example and the metadata is not necessarily consistent.

hints:
  ResourceRequirement:
    coresMin: 4

inputs:
  aligned_sequences:
    type: File
    label: Aligned sequences in BAM format
    format: edam:format_2572
    inputBinding:
      position: 1

baseCommand: [ wc, -l ]

stdout: output.txt

outputs:
  report:
    type: stdout
    format: edam:format_1964
    label: A text file that contains a line count

s:author:
  - class: s:Person
    s:identifier: https://orcid.org/0000-0002-6130-1021
    s:email: mailto:dyuen@oicr.on.ca
    s:name: Denis Yuen

s:contributor:
  - class: s:Person
    s:identifier: http://orcid.org/0000-0002-7681-6415
    s:email: mailto:briandoconnor@gmail.com
    s:name: Brian O'Connor

s:citation: https://dx.doi.org/10.6084/m9.figshare.3115156.v2
s:codeRepository: https://github.com/common-workflow-language/common-workflow-language
s:dateCreated: "2016-12-13"
s:license: https://spdx.org/licenses/Apache-2.0 

s:keywords: edam:topic_0091 , edam:topic_0622
s:programmingLanguage: C

$namespaces:
 s: https://schema.org/
 edam: http://edamontology.org/

$schemas:
 - https://schema.org/version/latest/schemaorg-current-http.rdf
 - http://edamontology.org/EDAM_1.18.owl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

自定义类型

有时你可能想编写自己的自定义类型,以便在CWL描述中使用和重复使用。使用这样的自定义类型可以减少对于相同类型进行多次描述,还允许直接对工具进行额外的自定义配置。

下面的例子是用于将标准生物表文件转换为 hd5格式的生物转换格式工具的 CWL 描述。

custom-types.cwl:

#!/usr/bin/env cwl-runner 
cwlVersion: v1.0
class: CommandLineTool

requirements:
  InlineJavascriptRequirement: {}
  ResourceRequirement:
    coresMax: 1
    ramMin: 100  # just a default, could be lowered
  SchemaDefRequirement:
    types:
      - $import: biom-convert-table.yaml

hints:
  DockerRequirement:
    dockerPull: 'quay.io/biocontainers/biom-format:2.1.6--py27_0'
  SoftwareRequirement:
    packages:
      biom-format:
        specs: [ "https://doi.org/10.1186/2047-217X-1-7" ]
        version: [ "2.1.6" ]

inputs:
  biom:
    type: File
    format: edam:format_3746  # BIOM
    inputBinding:
      prefix: --input-fp
  table_type:
    type: biom-convert-table.yaml#table_type
    inputBinding:
      prefix: --table-type

  header_key:
    type: string?
    doc: |
      The observation metadata to include from the input BIOM table file when
      creating a tsv table file. By default no observation metadata will be
      included.
    inputBinding:
      prefix: --header-key

baseCommand: [ biom, convert ]

arguments:
  - valueFrom: $(inputs.biom.nameroot).hdf5  
    prefix: --output-fp
  - --to-hdf5

outputs:
  result:
    type: File
    outputBinding: { glob: "$(inputs.biom.nameroot)*" }

$namespaces:
  edam: http://edamontology.org/
  s: https://schema.org/

$schemas:
  - http://edamontology.org/EDAM_1.16.owl
  - https://schema.org/version/latest/schemaorg-current-http.rdf

s:license: https://spdx.org/licenses/Apache-2.0
s:copyrightHolder: "EMBL - European Bioinformatics Institute"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64

custom-types.yml:

biom:
    class: File
    format: http://edamontology.org/format_3746
    path: rich_sparse_otu_table.biom
table_type: OTU table
1
2
3
4
5

注:** **要按照下面的示例操作,您需要下载示例输入文件, rich_sparse_otu_table.biom. 该文件在 https://raw.githubusercontent.com/common-workflow-language/user_guide/gh-pages/_includes/cwl/19-custom-types/rich_sparse_otu_table.biom在新窗口打开 您可以通过 wget下载

wget https://raw.githubusercontent.com/common-workflow-language/user_guide/gh-pages/_includes/cwl/19-custom-types/rich_sparse_otu_table.biom
1

指定软件要求

通常,软件工具CWL会为软件的特定版本编写。为了让其他人更容易使用您的描述,您可以在该部分中添加SoftwareRequirementhints字段,这也可以帮助避免混淆描述CWL是为哪个版本的工具而写的。

cwlVersion: v1.0
class: CommandLineTool

label: "InterProScan: protein sequence classifier"

doc: |
      Version 5.21-60 can be downloaded here:
      https://interproscan-docs.readthedocs.io/en/latest/HowToDownload.html

      Documentation on how to run InterProScan 5 can be found here:
      https://interproscan-docs.readthedocs.io/en/latest/HowToRun.html

requirements:
  ResourceRequirement:
    ramMin: 10240
    coresMin: 3
  SchemaDefRequirement:
    types:
      - $import: InterProScan-apps.yml

hints:
  SoftwareRequirement:
    packages:
      interproscan:
        specs: [ "https://identifiers.org/rrid/RRID:SCR_005829" ]
        version: [ "5.21-60" ]

inputs:
  proteinFile:
    type: File
    inputBinding:
      prefix: --input
  applications:
    type: InterProScan-apps.yml#apps[]?
    inputBinding:
      itemSeparator: ','
      prefix: --applications

baseCommand: interproscan.sh

arguments:
 - valueFrom: $(inputs.proteinFile.nameroot).i5_annotations
   prefix: --outfile
 - valueFrom: TSV
   prefix: --formats
 - --disable-precalc
 - --goterms
 - --pathways
 - valueFrom: $(runtime.tmpdir)
   prefix: --tempdir


outputs:
  i5Annotations:
    type: File
    format: iana:text/tab-separated-values
    outputBinding:
      glob: $(inputs.proteinFile.nameroot).i5_annotations

$namespaces:
 iana: https://www.iana.org/assignments/media-types/
 s: https://schema.org/
$schemas:
 - https://schema.org/version/latest/schemaorg-current-http.rdf

s:license: https://spdx.org/licenses/Apache-2.0
s:copyrightHolder: "EMBL - European Bioinformatics Institute"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

在这个例子中,描述的软件要求是InterProScan 5.21-60版本。

hints:
  SoftwareRequirement:
    packages:
      interproscan:
        specs: [ "https://identifiers.org/rrid/RRID:SCR_005829" ]
        version: [ "5.21-60" ]
1
2
3
4
5
6

根据你的sixbox run,这些提示可用于在作业运行前检查所需软件是否已安装和可用。

除了版本号,该工具的唯一资源标识符(URI)也以RRID在新窗口打开的形式给出。有RRID的资源可以在SciCrunch在新窗口打开注册表中查询,该注册表为寻找、跟踪和引用科学资源提供了一个门户。如果你想把一个工具指定为SoftwareRequirement,在SciCrunch在新窗口打开上搜索该工具,并使用它在注册表上被分配的RRID。(如果你想在SciCrunch上添加一个工具,请遵循这个教程在新窗口打开。)你可以使用这个RRID在你的需求描述的规格字段中提到这个工具( identifiers.org在新窗口打开)。