Skip to content

Commit dd383e9

Browse files
committed
better handle multi-version upgrades
1 parent fee2c96 commit dd383e9

File tree

8 files changed

+222
-5
lines changed

8 files changed

+222
-5
lines changed

cwlupgrader/main.py

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,12 @@ def write_cwl_document(document: Any, name: str, dirname: str) -> None:
199199
path = Path(dirname) / name
200200
with open(path, "w") as handle:
201201
if "cwlVersion" in document:
202-
handle.write("#!/usr/bin/env cwl-runner\n")
202+
if not (
203+
document.ca
204+
and document.ca.comment
205+
and "cwl-runner" in document.ca.comment[1][0].value
206+
):
207+
handle.write("#!/usr/bin/env cwl-runner\n")
203208
yaml.dump(document, stream=handle)
204209
if "cwlVersion" in document:
205210
path.chmod(path.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
@@ -249,12 +254,13 @@ def v1_0_to_v1_1(document: CommentedMap, outdir: str) -> CommentedMap:
249254
def v1_0_to_v1_2(document: CommentedMap, outdir: str) -> CommentedMap:
250255
"""CWL v1.0.x to v1.2 transformation."""
251256
document = v1_0_to_v1_1(document, outdir)
252-
document["cwlVersion"] = "v1.2"
257+
document = v1_1_to_v1_2(document, outdir)
253258
return document
254259

255260

256261
def v1_1_to_v1_2(document: CommentedMap, outdir: str) -> CommentedMap:
257262
"""CWL v1.1 to v1.2 transformation."""
263+
document = _v1_1_to_v1_2(document, outdir)
258264
document["cwlVersion"] = "v1.2"
259265
return document
260266

@@ -350,6 +356,10 @@ def _v1_0_to_v1_1(document: CommentedMap, outdir: str) -> CommentedMap:
350356
_v1_0_to_v1_1(process, outdir)
351357
if "cwlVersion" in process:
352358
del process["cwlVersion"]
359+
elif isinstance(entry["run"], str) and "#" not in entry["run"]:
360+
path = Path(document.lc.filename).parent / entry["run"]
361+
process = v1_0_to_v1_1(load_cwl_document(str(path)), outdir)
362+
write_cwl_document(process, path.name, outdir)
353363
elif isinstance(steps, MutableMapping):
354364
for step_name in steps:
355365
with SourceLine(steps, step_name, Exception):
@@ -413,10 +423,62 @@ def _v1_0_to_v1_1(document: CommentedMap, outdir: str) -> CommentedMap:
413423

414424

415425
def _v1_0_to_v1_2(document: CommentedMap, outdir: str) -> CommentedMap:
416-
return _v1_0_to_v1_1(document, outdir) # nothing needs doing for v1.2
426+
document = _v1_0_to_v1_1(document, outdir)
427+
return _v1_1_to_v1_2(document, outdir)
417428

418429

419430
def _v1_1_to_v1_2(document: CommentedMap, outdir: str) -> CommentedMap:
431+
if "class" in document:
432+
if document["class"] == "Workflow":
433+
steps = document["steps"]
434+
if isinstance(steps, MutableSequence):
435+
for index, entry in enumerate(steps):
436+
with SourceLine(steps, index, Exception):
437+
if "run" in entry and isinstance(entry["run"], CommentedMap):
438+
process = entry["run"]
439+
_v1_1_to_v1_2(process, outdir)
440+
if "cwlVersion" in process:
441+
del process["cwlVersion"]
442+
443+
elif isinstance(entry["run"], str) and "#" not in entry["run"]:
444+
if hasattr(document.lc, "filename"):
445+
dirname = Path(document.lc.filename).parent
446+
else:
447+
dirname = Path(outdir)
448+
path = dirname / entry["run"]
449+
process = v1_1_to_v1_2(load_cwl_document(str(path)), outdir)
450+
write_cwl_document(process, path.name, outdir)
451+
elif isinstance(steps, MutableMapping):
452+
for step_name in steps:
453+
with SourceLine(steps, step_name, Exception):
454+
entry = steps[step_name]
455+
if "run" in entry:
456+
if isinstance(entry["run"], CommentedMap):
457+
process = entry["run"]
458+
_v1_1_to_v1_2(process, outdir)
459+
if "cwlVersion" in process:
460+
del process["cwlVersion"]
461+
elif (
462+
isinstance(entry["run"], str)
463+
and "#" not in entry["run"]
464+
):
465+
if hasattr(document.lc, "filename"):
466+
dirname = Path(document.lc.filename).parent
467+
else:
468+
dirname = Path(outdir)
469+
path = dirname / entry["run"]
470+
process = v1_1_to_v1_2(
471+
load_cwl_document(str(path)), outdir
472+
)
473+
write_cwl_document(process, path.name, outdir)
474+
elif isinstance(entry["run"], str) and "#" in entry["run"]:
475+
pass # reference to $graph entry
476+
else:
477+
raise Exception(
478+
"'run' entry was neither a CWL Process nor "
479+
"a path to one: %s.",
480+
entry["run"],
481+
)
420482
return document
421483

422484

@@ -445,10 +507,10 @@ def cleanup(inp: Dict[str, Any]) -> None:
445507

446508

447509
def move_up_loadcontents(document: Dict[str, Any]) -> None:
448-
"""'loadContents' is promoted up a level in CWL v1.1."""
510+
"""Promote 'loadContents' up a level for CWL v1.1."""
449511

450512
def cleanup(inp: Dict[str, Any]) -> None:
451-
"""Move loadContents to the preferred location"""
513+
"""Move loadContents to the preferred location."""
452514
if "inputBinding" in inp:
453515
bindings = inp["inputBinding"]
454516
for field in list(bindings.keys()):

testdata/v1.0/1st-workflow.cwl

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/usr/bin/env cwl-runner
2+
3+
cwlVersion: v1.0
4+
class: Workflow
5+
inputs:
6+
tarball: File
7+
name_of_file_to_extract: string
8+
9+
outputs:
10+
compiled_class:
11+
type: File
12+
outputSource: compile/classfile
13+
14+
steps:
15+
untar:
16+
run: tar-param.cwl
17+
in:
18+
tarfile: tarball
19+
extractfile: name_of_file_to_extract
20+
out: [extracted_file]
21+
22+
compile:
23+
run: arguments.cwl
24+
in:
25+
src: untar/extracted_file
26+
out: [classfile]

testdata/v1.0/arguments.cwl

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env cwl-runner
2+
3+
cwlVersion: v1.0
4+
class: CommandLineTool
5+
label: Example trivial wrapper for Java 9 compiler
6+
hints:
7+
DockerRequirement:
8+
dockerPull: openjdk:9.0.1-11-slim
9+
baseCommand: javac
10+
arguments: ["-d", $(runtime.outdir)]
11+
inputs:
12+
src:
13+
type: File
14+
inputBinding:
15+
position: 1
16+
outputs:
17+
classfile:
18+
type: File
19+
outputBinding:
20+
glob: "*.class"
21+

testdata/v1.0/tar-param.cwl

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env cwl-runner
2+
3+
cwlVersion: v1.0
4+
class: CommandLineTool
5+
baseCommand: [tar, --extract]
6+
inputs:
7+
tarfile:
8+
type: File
9+
inputBinding:
10+
prefix: --file
11+
extractfile:
12+
type: string
13+
inputBinding:
14+
position: 1
15+
outputs:
16+
extracted_file:
17+
type: File
18+
outputBinding:
19+
glob: $(inputs.extractfile)

testdata/v1.2/1st-workflow.cwl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env cwl-runner
2+
cwlVersion: v1.2
3+
class: Workflow
4+
inputs:
5+
tarball: File
6+
name_of_file_to_extract: string
7+
8+
steps:
9+
untar:
10+
run: tar-param.cwl
11+
in:
12+
tarfile: tarball
13+
extractfile: name_of_file_to_extract
14+
out: [extracted_file]
15+
16+
compile:
17+
run: arguments.cwl
18+
in:
19+
src: untar/extracted_file
20+
out: [classfile]
21+
outputs:
22+
compiled_class:
23+
type: File
24+
outputSource: compile/classfile
25+

testdata/v1.2/arguments.cwl

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env cwl-runner
2+
cwlVersion: v1.2
3+
class: CommandLineTool
4+
label: Example trivial wrapper for Java 9 compiler
5+
requirements:
6+
NetworkAccess:
7+
networkAccess: true
8+
LoadListingRequirement:
9+
loadListing: deep_listing
10+
hints:
11+
DockerRequirement:
12+
dockerPull: openjdk:9.0.1-11-slim
13+
inputs:
14+
src:
15+
type: File
16+
inputBinding:
17+
position: 1
18+
baseCommand: javac
19+
arguments: ["-d", $(runtime.outdir)]
20+
outputs:
21+
classfile:
22+
type: File
23+
outputBinding:
24+
glob: "*.class"
25+

testdata/v1.2/tar-param.cwl

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/usr/bin/env cwl-runner
2+
cwlVersion: v1.2
3+
class: CommandLineTool
4+
requirements:
5+
NetworkAccess:
6+
networkAccess: true
7+
LoadListingRequirement:
8+
loadListing: deep_listing
9+
inputs:
10+
tarfile:
11+
type: File
12+
inputBinding:
13+
prefix: --file
14+
extractfile:
15+
type: string
16+
inputBinding:
17+
position: 1
18+
baseCommand: [tar, --extract]
19+
outputs:
20+
extracted_file:
21+
type: File
22+
outputBinding:
23+
glob: $(inputs.extractfile)

tests/test_complete.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,3 +99,19 @@ def test_packed_graph(tmp_path: Path) -> None:
9999
tmp_path / "conflict-wf.cwl",
100100
shallow=False,
101101
)
102+
103+
def test_multi_version_upgrade_external_steps(tmp_path: Path) -> None:
104+
"""Test 1.0 to 1.2 upgrade of Workflow with external steps."""
105+
main(
106+
[f"--dir={tmp_path}", get_data("testdata/v1.0/1st-workflow.cwl")]
107+
)
108+
assert filecmp.cmp(
109+
get_data("testdata/v1.2/arguments.cwl"),
110+
tmp_path / "arguments.cwl",
111+
shallow=False,
112+
)
113+
assert filecmp.cmp(
114+
get_data("testdata/v1.2/tar-param.cwl"),
115+
tmp_path / "tar-param.cwl",
116+
shallow=False,
117+
)

0 commit comments

Comments
 (0)