Repository: common-workflow-language/cwltool

Issue:
Parameter with a valueFrom field, type array and no prefix doesn't lead to execution of the expected command
If you use the valueFrom field with an argument of array type and no prefix field, the executed command is the evaluated valueFrom field followed by the array arguments, not just the  evaluated valueFrom field. This is not what I would expect from the cwl specification and behaviour of cwltool.

## Expected Behaviour

From http://www.commonwl.org/v1.0/CommandLineTool.html#CommandLineBinding:
> If valueFrom is a constant string value, use this as the value and apply the binding rules above.

It is not specified in the specification what the binding rules should be if no prefix is defined, but in cwltool if no `prefix` field is present, then cwltool doesn't evaulate the anything for that argument e.g.:
```yaml
cwlVersion: v1.0
inputs:
  - id: parameter
    type:
      - type: array
        items: string
outputs: []
class: CommandLineTool
baseCommand: echo
```
```yaml
parameter:
  - "item1"
  - "item2"
```

Outputs:
```
/usr/local/bin/cwltool 1.0.20171107133715
Resolved 'test.cwl' to '...'
[job test.cwl] /private/var/folders/5p/p6z8hhy174q_ctt3pn7mx5_c000h1t/T/tmp1mivk5pg$ echo

[job test.cwl] completed success
{}
Final process status is success
```
I would therefore infer that using the workflow and inputs below should execute ` 'echo' 'replacementValue'`, but cwltool executes: `'echo' 'replacementValue' 'item1' 'item2'`.
## Actual Behaviour
Using the workflow and inputs below, cwltool outputs as specified below:

## Workflow Code
### Workflow
```yaml
cwlVersion: v1.0
requirements:
- class: ShellCommandRequirement
- class: InlineJavascriptRequirement
inputs:
  - id: parameter
    type:
      - type: array
        items: string
    inputBinding:
      valueFrom: replacementValue
outputs: []
class: CommandLineTool
baseCommand: echo
```
### Inputs
```yaml
parameter:
  - "item1"
  - "item2"
```

## Full Traceback
```pytb
/usr/local/bin/cwltool 1.0.20171107133715
Resolved 'test.cwl' to '...'
[job test.cwl] /private/var/folders/5p/p6z8hhy174q_ctt3pn7mx5_c000h1t/T/tmp_jdgzuc4$ /bin/sh \
    -c \
    'echo' 'replacementValue' 'item1' 'item2'
replacementValue item1 item2
[job intervals_test.cwl] completed success
{}
Final process status is success
```

## Your Environment
* cwltool version: 1.0.20171107133715



Discussion:

Resolving patch:
diff --git a/cwltool/builder.py b/cwltool/builder.py
--- a/cwltool/builder.py
+++ b/cwltool/builder.py
@@ -78,6 +78,7 @@ def bind_input(self, schema, datum, lead_pos=None, tail_pos=None):
             lead_pos = []
         bindings = []  # type: List[Dict[Text,Text]]
         binding = None  # type: Dict[Text,Any]
+        value_from_expression = False
         if "inputBinding" in schema and isinstance(schema["inputBinding"], dict):
             binding = copy.copy(schema["inputBinding"])
 
@@ -87,29 +88,33 @@ def bind_input(self, schema, datum, lead_pos=None, tail_pos=None):
                 binding["position"] = aslist(lead_pos) + [0] + aslist(tail_pos)
 
             binding["datum"] = datum
+            if "valueFrom" in binding:
+                value_from_expression = True
 
         # Handle union types
         if isinstance(schema["type"], list):
-            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
-                    return self.bind_input(schema, datum, lead_pos=lead_pos, tail_pos=tail_pos)
-            raise validate.ValidationException(u"'%s' is not a valid union %s" % (datum, schema["type"]))
+            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
+                        return self.bind_input(schema, datum, lead_pos=lead_pos, tail_pos=tail_pos)
+                raise validate.ValidationException(u"'%s' is not a valid union %s" % (datum, schema["type"]))
         elif isinstance(schema["type"], dict):
-            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]
-            bindings.extend(self.bind_input(st, datum, lead_pos=lead_pos, tail_pos=tail_pos))
+            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]
+                bindings.extend(self.bind_input(st, datum, lead_pos=lead_pos, tail_pos=tail_pos))
         else:
             if schema["type"] in self.schemaDefs:
                 schema = self.schemaDefs[schema["type"]]


Test patch: