11#!/usr/bin/env python3
2+ """CWL Expression refactoring tool for CWL v1.0 ."""
23import argparse
34import copy
45import hashlib
4243def parse_args (args : List [str ]) -> argparse .Namespace :
4344 """Argument parser."""
4445 parser = argparse .ArgumentParser (
45- description = "Tool to upgrade refactor CWL documents so that any CWL expression "
46- "are separate steps as either ExpressionTools or CommandLineTools."
46+ description = "Tool to refactor CWL v1.0 documents so that any CWL expression "
47+ "are separate steps as either ExpressionTools or CommandLineTools. Exit code 7 "
48+ "means a single CWL document was provided but it did not need modification."
4749 )
4850 parser .add_argument (
4951 "--etools" ,
@@ -83,11 +85,14 @@ def run(args: argparse.Namespace) -> int:
8385 top = cwl .load_document (document )
8486 output = Path (args .dir ) / Path (document ).name
8587 result , modified = traverse (
86- top , not args .etools , args .skip_some1 , args .skip_some2
88+ top , not args .etools , False , args .skip_some1 , args .skip_some2
8789 )
8890 if not modified :
89- shutil .copyfile (document , output )
90- continue
91+ if len (args .inputs ) > 1 :
92+ shutil .copyfile (document , output )
93+ continue
94+ else :
95+ return 7
9196 if not isinstance (result , MutableSequence ):
9297 result_json = cwl .save (
9398 result ,
@@ -242,15 +247,18 @@ def etool_to_cltool(
242247process.stdout.write(JSON.stringify(ret));"""
243248 )
244249 contents = escape_expression_field (contents )
245- listing = [cwl .Dirent ("expression.js" , contents , writable = None )]
250+ listing = [cwl .Dirent (entryname = "expression.js" , entry = contents , writable = None )]
246251 iwdr = cwl .InitialWorkDirRequirement (listing )
247252 containerReq = cwl .DockerRequirement (dockerPull = "node:slim" )
253+ softwareHint = cwl .SoftwareRequirement (
254+ packages = [cwl .SoftwarePackage (package = "nodejs" )]
255+ )
248256 return cwl .CommandLineTool (
249257 inputs = inputs ,
250258 outputs = outputs ,
251259 id = etool .id ,
252260 requirements = [iwdr ],
253- hints = [containerReq ],
261+ hints = [containerReq , softwareHint ],
254262 label = etool .label ,
255263 doc = etool .doc ,
256264 cwlVersion = etool .cwlVersion ,
@@ -263,10 +271,10 @@ def etool_to_cltool(
263271
264272def traverse (
265273 process : Union [cwl .CommandLineTool , cwl .ExpressionTool , cwl .Workflow ],
266- replace_etool : bool = False ,
267- inside : bool = False ,
268- skip_command_line1 : bool = False ,
269- skip_command_line2 : bool = False ,
274+ replace_etool : bool ,
275+ inside : bool ,
276+ skip_command_line1 : bool ,
277+ skip_command_line2 : bool ,
270278) -> Tuple [Union [cwl .CommandLineTool , cwl .ExpressionTool , cwl .Workflow ], bool ]:
271279 """Convert the given process and any subprocesess."""
272280 if not inside and isinstance (process , cwl .CommandLineTool ):
@@ -348,9 +356,9 @@ def traverse(
348356
349357def load_step (
350358 step : cwl .WorkflowStep ,
351- replace_etool : bool = False ,
352- skip_command_line1 : bool = False ,
353- skip_command_line2 : bool = False ,
359+ replace_etool : bool ,
360+ skip_command_line1 : bool ,
361+ skip_command_line2 : bool ,
354362) -> bool :
355363 """If the step's Process is not inline, load and process it."""
356364 modified = False
@@ -700,7 +708,7 @@ def process_workflow_inputs_and_outputs(
700708
701709
702710def process_workflow_reqs_and_hints (
703- workflow : cwl .Workflow , replace_etool : bool = False
711+ workflow : cwl .Workflow , replace_etool : bool
704712) -> bool :
705713 """
706714 Convert any expressions in a workflow's reqs and hints.
@@ -1029,9 +1037,9 @@ def process_level_reqs(
10291037 process : cwl .CommandLineTool ,
10301038 step : cwl .WorkflowStep ,
10311039 parent : cwl .Workflow ,
1032- replace_etool : bool = False ,
1033- skip_command_line1 : bool = False ,
1034- skip_command_line2 : bool = False ,
1040+ replace_etool : bool ,
1041+ skip_command_line1 : bool ,
1042+ skip_command_line2 : bool ,
10351043) -> bool :
10361044 """Convert expressions inside a process into new adjacent steps."""
10371045 # This is for reqs inside a Process (CommandLineTool, ExpressionTool)
@@ -1301,9 +1309,9 @@ def traverse_CommandLineTool(
13011309 clt : cwl .CommandLineTool ,
13021310 parent : cwl .Workflow ,
13031311 step : cwl .WorkflowStep ,
1304- replace_etool : bool = False ,
1305- skip_command_line1 : bool = False ,
1306- skip_command_line2 : bool = False ,
1312+ replace_etool : bool ,
1313+ skip_command_line1 : bool ,
1314+ skip_command_line2 : bool ,
13071315) -> bool :
13081316 """Extract any CWL Expressions within the given CommandLineTool into sibling steps."""
13091317 modified = False
@@ -1592,7 +1600,7 @@ def simplify_step_id(uri: str) -> str:
15921600
15931601def remove_JSReq (
15941602 process : Union [cwl .CommandLineTool , cwl .WorkflowStep , cwl .Workflow ],
1595- skip_command_line1 : bool = False ,
1603+ skip_command_line1 : bool ,
15961604) -> None :
15971605 """Since the InlineJavascriptRequiment is longer needed, remove it."""
15981606 if skip_command_line1 and isinstance (process , cwl .CommandLineTool ):
@@ -1621,7 +1629,7 @@ def replace_step_clt_expr_with_etool(
16211629 workflow : cwl .Workflow ,
16221630 target : cwl .InputParameter ,
16231631 step : cwl .WorkflowStep ,
1624- replace_etool : bool = False ,
1632+ replace_etool : bool ,
16251633 self_name : Optional [str ] = None ,
16261634) -> None :
16271635 """Convert a step level CWL Expression to a sibling expression step."""
@@ -1656,7 +1664,7 @@ def replace_clt_hintreq_expr_with_etool(
16561664 workflow : cwl .Workflow ,
16571665 target : cwl .InputParameter ,
16581666 step : cwl .WorkflowStep ,
1659- replace_etool : bool = False ,
1667+ replace_etool : bool ,
16601668 self_name : Optional [str ] = None ,
16611669) -> Union [cwl .CommandLineTool , cwl .ExpressionTool ]:
16621670 """Factor out an expression inside a CommandLineTool req or hint into a sibling step."""
@@ -1815,9 +1823,9 @@ def generate_etool_from_expr2(
18151823def traverse_step (
18161824 step : cwl .WorkflowStep ,
18171825 parent : cwl .Workflow ,
1818- replace_etool : bool = False ,
1819- skip_command_line1 : bool = False ,
1820- skip_command_line2 : bool = False ,
1826+ replace_etool : bool ,
1827+ skip_command_line1 : bool ,
1828+ skip_command_line2 : bool ,
18211829) -> bool :
18221830 """Process the given WorkflowStep."""
18231831 modified = False
@@ -1915,7 +1923,12 @@ def traverse_step(
19151923 inp .source = "{}/result" .format (etool_id )
19161924 # TODO: skip or special process for sub workflows?
19171925 process_modified = process_level_reqs (
1918- original_process , step , parent , replace_etool , skip_command_line1
1926+ original_process ,
1927+ step ,
1928+ parent ,
1929+ replace_etool ,
1930+ skip_command_line1 ,
1931+ skip_command_line2 ,
19191932 )
19201933 if process_modified :
19211934 modified = True
@@ -1958,7 +1971,7 @@ def replace_step_valueFrom_expr_with_etool(
19581971 original_process : Union [cwl .CommandLineTool , cwl .ExpressionTool ],
19591972 original_step_ins : List [cwl .WorkflowStepInput ],
19601973 source : Union [str , List [Any ]],
1961- replace_etool : bool = False ,
1974+ replace_etool : bool ,
19621975 source_type : Optional [Union [cwl .InputParameter , cwl .CommandInputParameter ]] = None ,
19631976) -> None :
19641977 """Replace a WorkflowStep level 'valueFrom' expression with a sibling ExpressionTool step."""
@@ -2030,9 +2043,9 @@ def replace_step_valueFrom_expr_with_etool(
20302043
20312044def traverse_workflow (
20322045 workflow : cwl .Workflow ,
2033- replace_etool : bool = False ,
2034- skip_command_line1 : bool = False ,
2035- skip_command_line2 : bool = False ,
2046+ replace_etool : bool ,
2047+ skip_command_line1 : bool ,
2048+ skip_command_line2 : bool ,
20362049) -> Tuple [cwl .Workflow , bool ]:
20372050 """Traverse a workflow, processing each step."""
20382051 modified = False
@@ -2049,7 +2062,7 @@ def traverse_workflow(
20492062 for step in workflow .steps :
20502063 if not step .id .startswith ("_expression" ):
20512064 step_modified = traverse_step (
2052- step , workflow , skip_command_line1 , skip_command_line2
2065+ step , workflow , replace_etool , skip_command_line1 , skip_command_line2
20532066 )
20542067 if step_modified :
20552068 modified = True
0 commit comments