Repository: common-workflow-language/cwltool

Issue:
valueFrom with array input fails
With a modified file from the conformance tests:
```
class: CommandLineTool
cwlVersion: v1.0

requirements:
  - class: InlineJavascriptRequirement

hints:
  - class: DockerRequirement
    dockerPull: python:2-slim

inputs:
  - id: array_input
    type:
      - type: array
        items: File
    inputBinding:
      valueFrom: replacementValue

  - id: args.py
    type: File
    default:
      class: File
      location: args.py
    inputBinding:
      position: -1

outputs:
  - id: args
    type: string[]

baseCommand: python
```

inputs:
```
array_input:
  - class: File
    path: ./hello.txt

```
fails as below:
```
/usr/local/bin/cwltool 1.0.20180310141537
Resolved 'valueFrom-constant.cwl' to 'file:///Users/th10/checkouts/common-workflow-language/v1.0/v1.0/valueFrom-constant.cwl'
Got workflow error
Traceback (most recent call last):
  File "/Users/th10/checkouts/cwltool/cwltool/executors.py", line 98, in run_jobs
    for r in jobiter:
  File "/Users/th10/checkouts/cwltool/cwltool/command_line_tool.py", line 379, in job
    visit_class([builder.files, builder.bindings], ("File", "Directory"), _check_adjust)
  File "/Users/th10/checkouts/cwltool/cwltool/pathmapper.py", line 51, in visit_class
    visit_class(d, cls, op)
  File "/Users/th10/checkouts/cwltool/cwltool/pathmapper.py", line 51, in visit_class
    visit_class(d, cls, op)
  File "/Users/th10/checkouts/cwltool/cwltool/pathmapper.py", line 48, in visit_class
    visit_class(rec[d], cls, op)
  File "/Users/th10/checkouts/cwltool/cwltool/pathmapper.py", line 51, in visit_class
    visit_class(d, cls, op)
  File "/Users/th10/checkouts/cwltool/cwltool/pathmapper.py", line 46, in visit_class
    op(rec)
  File "/Users/th10/checkouts/cwltool/cwltool/command_line_tool.py", line 181, in check_adjust
    f["path"] = docker_windows_path_adjust(builder.pathmapper.mapper(f["location"])[1])
  File "/Users/th10/checkouts/cwltool/cwltool/pathmapper.py", line 290, in mapper
    return self._pathmap[src]
KeyError: 'file:///Users/th10/checkouts/common-workflow-language/v1.0/v1.0/hello.txt'
Workflow error, try again with --debug for more information:
'file:///Users/th10/checkouts/common-workflow-language/v1.0/v1.0/hello.txt'
```


Discussion:

Resolving patch:
diff --git a/cwltool/builder.py b/cwltool/builder.py
--- a/cwltool/builder.py
+++ b/cwltool/builder.py
@@ -93,27 +93,34 @@ def bind_input(self, schema, datum, lead_pos=None, tail_pos=None):
 
         # Handle union types
         if isinstance(schema["type"], list):
-            if not value_from_expression:
-                for t in schema["type"]:
-                    if isinstance(t, (str, Text)) and self.names.has_name(t, ""):
-                        avsc = self.names.get_name(t, "")
-                    elif isinstance(t, dict) and "name" in t and self.names.has_name(t["name"], ""):
-                        avsc = self.names.get_name(t["name"], "")
-                    else:
-                        avsc = AvroSchemaFromJSONData(t, self.names)
-                    if validate.validate(avsc, datum):
-                        schema = copy.deepcopy(schema)
-                        schema["type"] = t
+            bound_input = False
+            for t in schema["type"]:
+                if isinstance(t, (str, Text)) and self.names.has_name(t, ""):
+                    avsc = self.names.get_name(t, "")
+                elif isinstance(t, dict) and "name" in t and self.names.has_name(t["name"], ""):
+                    avsc = self.names.get_name(t["name"], "")
+                else:
+                    avsc = AvroSchemaFromJSONData(t, self.names)
+                if validate.validate(avsc, datum):
+                    schema = copy.deepcopy(schema)
+                    schema["type"] = t
+                    if not value_from_expression:
                         return self.bind_input(schema, datum, lead_pos=lead_pos, tail_pos=tail_pos)
+                    else:
+                        self.bind_input(schema, datum, lead_pos=lead_pos, tail_pos=tail_pos)
+                        bound_input = True
+            if not bound_input:
                 raise validate.ValidationException(u"'%s' is not a valid union %s" % (datum, schema["type"]))
         elif isinstance(schema["type"], dict):
-            if not value_from_expression:
-                st = copy.deepcopy(schema["type"])
-                if binding and "inputBinding" not in st and st["type"] == "array" and "itemSeparator" not in binding:
-                    st["inputBinding"] = {}
-                for k in ("secondaryFiles", "format", "streamable"):
-                    if k in schema:
-                        st[k] = schema[k]
+            st = copy.deepcopy(schema["type"])
+            if binding and "inputBinding" not in st and st["type"] == "array" and "itemSeparator" not in binding:
+                st["inputBinding"] = {}
+            for k in ("secondaryFiles", "format", "streamable"):
+                if k in schema:
+                    st[k] = schema[k]
+            if value_from_expression:
+                self.bind_input(st, datum, lead_pos=lead_pos, tail_pos=tail_pos)
+            else:
                 bindings.extend(self.bind_input(st, datum, lead_pos=lead_pos, tail_pos=tail_pos))
         else:
             if schema["type"] in self.schemaDefs:


Test patch: