3
$\begingroup$

I am trying to run an R script as a task in WDL in a docker image. Since this is my first time working with these, I am stuck in something very simple (and in the initial stage) and am hoping somebody here can point me in the right direction. Here is my dockerfile.

FROM rocker/r-base:latest
RUN Rscript ...r-docker/install_packages.R

Here is my WDL script

version 1.0

workflow Rpipe {
   input {
     String name
   }
  call PrintNameR{
        input:
        name = name
}
  output {
     File outfile = PrintNameR.output_R
  }
}

task PrintNameR {
      input {
           String name
}

command<<<
    R --no-save --args name <<Rscript
    args <- commandArgs(trailingOnly = TRUE)
    for (i in args){
    print(i)}
    Rscript
  >>>

runtime {
            docker: "firsttrydocker"
       }
output {
     File output_R = stdout()
  }
}

I validated, generated an input json file - edited it to include the string I want "Smith", and ran it.

java -jar ../cromwell/womtool-77.jar validate rtry1.wdl 
java -jar ..cromwell/womtool-77.jar inputs rtry1.wdl > rtry1.json 
java -jar ..cromwell/cromwell-77.jar run rtry1.wdl --inputs rtry1.json

I get an output:

> args <- commandArgs(trailingOnly = TRUE)
> for (i in args){
+ print(i)}
[1] "name"

I get "name", I wanted to get "Smith" because that's what my input is.

What am I doing wrong? Clearly, it seems that I am not passing the WDL task input to the WDL task command -in the Rscript. What is the proper way to do it?

$\endgroup$

2 Answers 2

2
$\begingroup$

In order to reference a WDL input within a command block you need to use an expression placeholder. Expression placeholders have the form ~{*wdl expression*}, where the inner part can be an valid WDL expression (ie reference to an input declaration)

When an engine sees a String or a command block, it first looks to see if there are any of these expression placeholders within it. If there are, it will evaluate the inner expression, and replace the entire placeholder ~{...} with the resulting value.

You can see how this can be applied below

String first_name = "John"
String last_name = "Smith"
Int age = 45


String full_name = "~{first_name} ~{last_name} # equals "John Smith"
String name_and_age = "John is ~{age}" # equals "John is 45

# Any valid WDL expression can go within an expression placeholder
String complex = "~{first_name + last_name + age}" # equals "JohnSmith45"

A key thing to note is that WDL command templating and expression evaluation is completely separate from the actual execution of the command. An execution engine will evaluate the command template, swap the expression placeholders with their evaluated values, and THEN, execute the script.

This is relevant for your use case since you are using heredoc to directly define the rscript you are runnning. If we briefly look at a python example, you can see what I mean:

task hello_world {
  input {
   String name = "john"
  }

  command <<<
   python <<CODE
     # this is valid, because once the placeholder evaluates
     # this command becomes name = "john", which is valid python syntax
     # We did not have to pass ~{name} as an arg to the python command
     name = "~{name}"
     print(name)
   CODE
  >>>
}

Now getting to your problem specifically. You are trying to reference the name input value without using any sort of expression placeholder. To the execution engine, the name value looks like any other string. To swap the name in the command for the value passed into the task, you simply need to wrap the variable name in an expression placeholder: ~{name}.

task PrintNameR {
  input {
    String name
  }

  command<<<
    # I would wrap this in quotes to prevent any side effects of 
    # shell expansion
    R --no-save --args '~{name}' <<Rscript
    args <- commandArgs(trailingOnly = TRUE)
    for (i in args){
    print(i)}
    Rscript
  >>>

  runtime {
            docker: "firsttrydocker"
  }
  
  output {
     File output_R = stdout()
  }
}
```
$\endgroup$
4
$\begingroup$

I figured I had to pass ~{sep=" " name} as an argument

command<<<
R --no-save --args ~{sep=" " name} <<Rscript
args <- commandArgs(trailingOnly = TRUE)
for (i in args){
print(i)}
Rscript
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.