4. 常见问题#

4.1. How do I create non “File” types using evalFrom?#

cwlVersion: v1.0  # or v1.1
class: CommandLineTool
requirements:
  InlineJavascriptRequirement: {}

baseCommand: [ echo, "42" ]

inputs: []

stdout: my_number.txt

outputs:
  my_number:
    type: int
    outputBinding:
       glob: my_number.txt
       loadContents: True
       outputEval: $(parselnt(self[0].contents))

  my_number_as_string:
    type: string
    outputBinding:
       glob: my_number.txt
       loadContents: True
       outputEval: $(self[0].contents)

4.2. How do I rename an input file?#

本示例演示如何在工具描述 (tool description) 中更改输入文件名称。如果要使用工作流中其它步骤产生的文件,但又不想使用这些文件创建时的默认名称,这时候更名操作可以派上用场。

requirements:
  InitialWorkDirRequirement:
    listing:
      - entry: $(inputs.src1)
        entryName: newName
      - entry: $(inputs.src2)
        entryName: $(inputs.src1.basename)_custom_extension

4.3. How do I rename an output file?#

本示例演示更改输出文件名,不再使用某个工具赋予它的默认名称:

cwlVersion: v1.0
class: CommandLineTool
requirements:
  InlineJavascriptRequirement: {}

baseCommand: [ touch, otu_table.txt ]

inputs:
  otu_table_name: string

outputs:
 otu_table:
    type: File
    outputBinding:
      glob: otu_table.txt
      outputEval: ${self[0].basename=inputs.otu_table_name; return self;}

By modifying the basename field in the outputEval field, CWL workflow engines will rename the file using the new name for subsequent steps or as a workflow-level output.

4.4. How do I reference a local script?#

引用本地脚本有两种方法:

The first method involves adding the path to a folder containing your scripts to the PATH environment variable. This allows you to execute the shell script directly (without explicitly using the sh or bash commands).

首先,将 “shebang” 添加为文件首行:

#!/bin/bash

然后,用 chmod +x scriptname.sh 命令将脚本设为可执行。

最后,修改 PATH, 添加该脚本所在的目录。(把你自己的脚本保存在 $HOME/bin 目录下是较好的做法)。

export PATH=$PATH:$HOME/bin

这样,您就能用 baseCommand: scriptname.sh 直接运行脚本了。

#!/bin/bash
cwlVersion: v1.0
class: CommandLineTool
baseCommand: scriptname.sh

接下来若想共享您的工作,可将脚本存放在 Docker 格式的容器 (container) 中。

第二种方法是将 type: File 输入内容编写进脚本:

class: CommandLineTool

inputs:
  my_script:
     type: File
     inputBinding:
        position: 0


  # other inputs go here

baseCommand: sh

outputs: []

4.5. How can I set self-based input bindings for optional inputs?#

目前,如果缺失的可选输入项用到了 self, cwltool 将无法处理。在更高明的解决办法出现前,下面的例子可作为临时变通一用。

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

requirements: { InlineJavascriptRequirement: {} }

inputs:
  cfg:
    type: File?
    inputBinding:
      prefix: -cfg
      valueFrom: |
        ${ if(self === null) { return null;} else { return self.basename; } }

baseCommand: echo

outputs: []

4.6. How can I model a “one-or-the-other” parameter?#

以下示例演示的,是根据某个布尔参数的取值,来指定添加到命令行的字符串。

cwlVersion: v1.0
class: CommandLineTool
requirements:
  InlineJavascriptRequirement: {}
inputs:
  fancy_bool:
     type: boolean
     default: false  # or true
     inputBinding:
        valueFrom: ${if (self) { return "foo";} else { return "bar";}}

baseCommand: echo

outputs: []

4.7. How do I connect a solo value to an input that expects an array of that type?#

Add a MultipleInputFeatureRequirement along with linkMerge: merge_nested:

merge_nested

输入必须是一个数组,每个输入链接只包含一个条目。如果使用单个链接指定“merge_nested”,则链接中的值必须包含在单项列表中。

Which means “create a list with exactly these sources as elements”.

换言之:如果目标的类型是 File[](元素类型为 File 的数组),而源是单独一个 File,那么将 MultipleInputFeatureRequirements 添加到工作流级别的 requirements,并在目标步骤相应的 in 条目下添加 linkMerge: merge_nested

cwlVersion: v1.0
class: Workflow

requirements:
  MultipleInputFeatureRequirement: {}

inputs:
  readme: File

steps:
  first:
    run: tests/checker_wf/cat.cwl
    in:
     cat_in:  # type is File[]
       source: [ readme ]  # but the source is of type File
       linkMerge: merge_nested
    out: [txt]

outputs:
  result:
    type: File
    outputSource: first/txt

4.8. How do make an input optional? 💯#

若要令某个输入参数为可选,请在其类型声明中添加问号。

inputs:
  InputRead1:
    type: File
    inputBinding:
      position: 100

  #Optional Inputs
  isCasava:
    type: boolean?
    inputBinding:
      position: 1
      prefix: "--casava"

4.9. How do I specify an input that must come from a list of predefined values (i.e. How do I use enum inputs) ?#

某些命令行标志需要特定的参数值;对此,可以在 CWL 中声明枚举类型。此处指定 null, 这样的编程风格称为“长格式” (long form)。它的作用与其他输入上的问号相同。

Format:
  type:
    - "null"
    - type: enum
      symbols:
        - bam
        - sam
        - bam_mapped
        - sam_mapped
        - fastq
  inputBinding:
    position: 2
    prefix: "--format"

4.10. How do I describe dependent or exclusive input parameters(e.g. How do I use record inputs)?#

如果部分命令行标志之间存在 互斥依赖 的关系,可以为其定义专门的记录类型 (record type)。此处也可以指定 null 创建可选输入。

#Using record inputs to create mutually exclusive inputs

  Strand:
    type:
      - "null"
      - type: record
        name: forward
        fields:
          forward:
              type: boolean
              inputBinding:
                prefix: "--fr-stranded"

      - type: record
        name: reverse
        fields:
          reverse:
            type: boolean
            inputBinding:
              prefix: "--rf-stranded"

  PseudoBam:
    type: boolean?
    inputBinding:
      prefix: "--pseudobam"

#Using record inputs to create dependent inputs

  GenomeBam:
    type:
      - "null"
      - type: record
        name: genome_bam
        fields:
          genomebam:
            type: boolean
            inputBinding:
              prefix: "--genomebam"

          gtf:
            type: File
            inputBinding:
              prefix: "--gtf"

          chromosomes:
            type: File
            inputBinding:
              prefix: "--chromosomes"

4.11. How do I set mutually exclusive parameters?#

为了正确地设置记录输入类型的字段,您需要将字典传递给输入,以正确设置参数。具体方法是使用内联 JavaScript 返回以待设置字段为主键的字典。此处设定了 source (源)字段,以指示工作流中要充当其键值的输入。

steps:

  build_hisat2_index:
    run: ../Tools/Hisat2-Index.cwl
    in:
      InputFiles:
        source: FastaFiles
        valueFrom : |
          ${return {"fasta": self};}

      IndexName: IndexName

    out: [indexes]

4.12. How can I set Booleans?#

可使用 default(默认)字段设置

input:
  default: true

4.13. What should I do when concatenating strings in inputs?#

为此必须使用 valueFrom 而非 default 字段。

input:
  valueFrom: |
     My String: $(input.stringvalue)

4.14. I get cwltool errors due to filenames with space characters inside. What should I do?#

默认情况下,cwltool不允许某些字符出现在文件名中。

例如,文件名 a space is here.txt包含三个空格字符。

ERROR Workflow error, try again with --debug for more information:

Invalid filename: 'a space is here.txt' contains illegal characters

如果不能避开这些危险的字符,您可以为 cwltool 传递 --relax-path-checks 选项。

4.15. What should I do when I get CWL Parameter Reference error due to hyphen in an input identifier?#

cwltool --validate 返回 valid(验证通过)

$ cwltool --validate cwl/qiime.cwl
INFO /usr/local/bin/cwltool 1.0.20190831161204
INFO Resolved 'cwl/qiime.cwl' to 'file:///workspace/cwl/qiime.cwl'
cwl/qiime.cwl is valid CWL.

但执行时导致如下错误:

$ cwltool cwl/qiime.cwl --sample-input metadata.tsv
INFO /usr/local/bin/cwltool 1.0.20190831161204
INFO Resolved 'cwl/qiime.cwl' to 'file:///workspace/cwl/qiime.cwl'
ERROR Workflow error, try again with --debug for more information:
cwl/qiime.cwl:14:5: Expression evaluation error:
                    Syntax error in parameter reference '(inputs.sample-input)'. This could be due
                    to using Javascript code without specifying InlineJavascriptRequirement.

该文件如下

cwlVersion: v1.0
class: CommandLineTool
baseCommand: [qiime, metadata, tabulate]
arguments:
  - prefix: --m-input-file
    valueFrom: $(inputs.sample-input)
inputs:
  sample-input: File
outputs: []

问题由 -(连字符)引发。

valueFrom: $(inputs.sample-input)
                        # ^ this is problem
...

inputs:
  sample-input: File
      # ^ this is problem

To fix this error, change - (hyphen) to _ (underscore):

valueFrom: $(inputs.sample_input)
                        # ^ changed here

...

inputs:
  sample_input: File
      # ^ changed here

如果不能改动输入标识符,您可使用另一种 CWL 参数引用句法:

valueFrom: $(inputs["sample-input"])

4.16. How do I use CWL and cwltool with Singularity?#

CWL 标准是依照 Docker 容器格式建立的,其参考运行程序和另外几种 CWL 实现均支持适应 Singularity 引擎运行 Docker 格式容器。不过,直接指定 Singularity 格式容器不在 CWL 标准之内。

4.17. How do I debug the JavaScript in my CWL tool?#

您可使用 cwltool–js-console 选项,也可以考虑为您的代码创建 JavaScript 或 TypeScript 项目后使用 expressionLib 加载, 比如: https://github.com/common-workflow-language/common-workflow-language/blob/master/v1.0/v1.0/template-tool.cwl#L6-L8