@@ -31,7 +31,9 @@ def parse_args(args: List[str]) -> argparse.Namespace:
3131 """Argument parser."""
3232 parser = argparse .ArgumentParser (
3333 description = "Tool to upgrade CWL documents from one version to another. "
34- "Supports upgrading 'draft-3', 'v1.0', and 'v1.1' to 'v1.2'" ,
34+ "Supports upgrading 'draft-3', 'v1.0', and 'v1.1' to 'v1.2'. For workflows "
35+ 'that include "$import" or "run:" reference that refer to parent '
36+ "directories, start cwl-upgrader from the topmost directory of your project." ,
3537 formatter_class = argparse .ArgumentDefaultsHelpFormatter ,
3638 )
3739 parser .add_argument (
@@ -40,11 +42,11 @@ def parse_args(args: List[str]) -> argparse.Namespace:
4042 parser .add_argument (
4143 "--v1.1-only" ,
4244 dest = "v1_1_only" ,
43- help = "Don't upgrade past cwlVersion: v1.1" ,
45+ help = "Don't upgrade past cwlVersion: v1.1. " ,
4446 action = "store_true" ,
4547 )
4648 parser .add_argument (
47- "--dir" , help = "Directory in which to save converted files" , default = Path .cwd ()
49+ "--dir" , help = "Directory in which to save converted files. " , default = Path .cwd ()
4850 )
4951 parser .add_argument (
5052 "inputs" ,
@@ -64,10 +66,21 @@ def main(args: Optional[List[str]] = None) -> int:
6466def run (args : argparse .Namespace ) -> int :
6567 """Main function."""
6668 imports : Set [str ] = set ()
67- if args .dir and not os .path .exists (args .dir ):
68- os .makedirs (args .dir )
69- for path in args .inputs :
69+ if args .dir :
70+ out_dir = Path (args .dir )
71+ out_dir .mkdir (parents = True , exist_ok = True )
72+ else :
73+ out_dir = Path .cwd ()
74+ for p in args .inputs :
75+ path = Path (os .path .normpath (p ))
7076 _logger .info ("Processing %s" , path )
77+ if not p .startswith ("../" ) and path .resolve () != path :
78+ #common_path = os.path.commonpath([out_dir.resolve(), path.resolve()])
79+ #current_out_dir = out_dir / os.path.relpath(path, start=common_path)
80+ current_out_dir = out_dir / path .parent
81+ current_out_dir .mkdir (parents = True , exist_ok = True )
82+ else :
83+ current_out_dir = out_dir
7184 document = load_cwl_document (path )
7285 if "cwlVersion" not in document :
7386 _logger .warn ("No cwlVersion found in %s, skipping it." , path )
@@ -89,17 +102,17 @@ def run(args: argparse.Namespace) -> int:
89102 target_version = "latest"
90103 upgraded_document = upgrade_document (
91104 document ,
92- args . dir ,
105+ current_out_dir ,
93106 target_version = target_version ,
94107 imports = imports ,
95108 )
96- write_cwl_document (upgraded_document , Path (path ) .name , args . dir )
109+ write_cwl_document (upgraded_document , current_out_dir / (path .name ) )
97110 return 0
98111
99112
100113def upgrade_document (
101114 document : Any ,
102- output_dir : str ,
115+ output_dir : Path ,
103116 target_version : Optional [str ] = "latest" ,
104117 imports : Optional [Set [str ]] = None ,
105118) -> Any :
@@ -158,7 +171,7 @@ def upgrade_document(
158171 return main_updater (document , output_dir )
159172
160173
161- def load_cwl_document (path : str ) -> Any :
174+ def load_cwl_document (path : Union [ str , Path ] ) -> Any :
162175 """
163176 Load the given path using the Ruamel YAML round-trip loader.
164177
@@ -171,15 +184,14 @@ def load_cwl_document(path: str) -> Any:
171184 return document
172185
173186
174- def write_cwl_document (document : Any , name : str , dirname : str ) -> None :
187+ def write_cwl_document (document : Any , path : Path ) -> None :
175188 """
176189 Serialize the document using the Ruamel YAML round trip dumper.
177190
178191 Will also prepend "#!/usr/bin/env cwl-runner\n " and
179192 set the executable bit if it is a CWL document.
180193 """
181194 ruamel .yaml .scalarstring .walk_tree (document )
182- path = Path (dirname ) / name
183195 with open (path , "w" ) as handle :
184196 if "cwlVersion" in document :
185197 handle .write ("#!/usr/bin/env cwl-runner\n " )
@@ -189,7 +201,7 @@ def write_cwl_document(document: Any, name: str, dirname: str) -> None:
189201
190202
191203def process_imports (
192- document : Any , imports : Set [str ], updater : Callable [[Any , str ], Any ], outdir : str
204+ document : Any , imports : Set [str ], updater : Callable [[Any , Path ], Any ], outdir : Path
193205) -> None :
194206 """Find any '$import's and process them."""
195207 if isinstance (document , CommentedMap ):
@@ -200,14 +212,9 @@ def process_imports(
200212 import_doc = load_cwl_document (
201213 Path (document .lc .filename ).parent / value
202214 )
203- write_cwl_document (
204- updater (
205- import_doc ,
206- outdir ,
207- ),
208- Path (value ).name ,
209- outdir ,
210- )
215+ new_path = (outdir / value ).resolve ()
216+ new_path .parent .mkdir (parents = True , exist_ok = True )
217+ write_cwl_document (updater (import_doc , outdir ), new_path )
211218 imports .add (value )
212219 else :
213220 process_imports (value , imports , updater , outdir )
@@ -216,7 +223,7 @@ def process_imports(
216223 process_imports (entry , imports , updater , outdir )
217224
218225
219- def v1_0_to_v1_1 (document : CommentedMap , outdir : str ) -> CommentedMap :
226+ def v1_0_to_v1_1 (document : CommentedMap , outdir : Path ) -> CommentedMap :
220227 """CWL v1.0.x to v1.1 transformation loop."""
221228 _v1_0_to_v1_1 (document , outdir )
222229 for key , value in document .items ():
@@ -231,20 +238,20 @@ def v1_0_to_v1_1(document: CommentedMap, outdir: str) -> CommentedMap:
231238 return sort_v1_0 (document )
232239
233240
234- def v1_0_to_v1_2 (document : CommentedMap , outdir : str ) -> CommentedMap :
241+ def v1_0_to_v1_2 (document : CommentedMap , outdir : Path ) -> CommentedMap :
235242 """CWL v1.0.x to v1.2 transformation."""
236243 document = v1_0_to_v1_1 (document , outdir )
237244 document ["cwlVersion" ] = "v1.2"
238245 return document
239246
240247
241- def v1_1_to_v1_2 (document : CommentedMap , outdir : str ) -> CommentedMap :
248+ def v1_1_to_v1_2 (document : CommentedMap , outdir : Path ) -> CommentedMap :
242249 """CWL v1.1 to v1.2 transformation."""
243250 document ["cwlVersion" ] = "v1.2"
244251 return document
245252
246253
247- def draft3_to_v1_0 (document : CommentedMap , outdir : str ) -> CommentedMap :
254+ def draft3_to_v1_0 (document : CommentedMap , outdir : Path ) -> CommentedMap :
248255 """Transformation loop."""
249256 _draft3_to_v1_0 (document , outdir )
250257 if isinstance (document , MutableMapping ):
@@ -260,17 +267,17 @@ def draft3_to_v1_0(document: CommentedMap, outdir: str) -> CommentedMap:
260267 return sort_v1_0 (document )
261268
262269
263- def draft3_to_v1_1 (document : CommentedMap , outdir : str ) -> CommentedMap :
270+ def draft3_to_v1_1 (document : CommentedMap , outdir : Path ) -> CommentedMap :
264271 """transformation loop."""
265272 return v1_0_to_v1_1 (draft3_to_v1_0 (document , outdir ), outdir )
266273
267274
268- def draft3_to_v1_2 (document : CommentedMap , outdir : str ) -> CommentedMap :
275+ def draft3_to_v1_2 (document : CommentedMap , outdir : Path ) -> CommentedMap :
269276 """transformation loop."""
270277 return v1_1_to_v1_2 (v1_0_to_v1_1 (draft3_to_v1_0 (document , outdir ), outdir ), outdir )
271278
272279
273- def _draft3_to_v1_0 (document : CommentedMap , outdir : str ) -> CommentedMap :
280+ def _draft3_to_v1_0 (document : CommentedMap , outdir : Path ) -> CommentedMap :
274281 """Inner loop for transforming draft-3 to v1.0."""
275282 if "class" in document :
276283 if document ["class" ] == "Workflow" :
@@ -295,11 +302,11 @@ def _draft3_to_v1_0(document: CommentedMap, outdir: str) -> CommentedMap:
295302 return document
296303
297304
298- def _draft3_to_v1_1 (document : CommentedMap , outdir : str ) -> CommentedMap :
305+ def _draft3_to_v1_1 (document : CommentedMap , outdir : Path ) -> CommentedMap :
299306 return v1_0_to_v1_1 (_draft3_to_v1_0 (document , outdir ), outdir )
300307
301308
302- def _draft3_to_v1_2 (document : CommentedMap , outdir : str ) -> CommentedMap :
309+ def _draft3_to_v1_2 (document : CommentedMap , outdir : Path ) -> CommentedMap :
303310 return _draft3_to_v1_1 (document , outdir ) # nothing needs doing for 1.2
304311
305312
@@ -318,7 +325,7 @@ def _draft3_to_v1_2(document: CommentedMap, outdir: str) -> CommentedMap:
318325}
319326
320327
321- def _v1_0_to_v1_1 (document : CommentedMap , outdir : str ) -> CommentedMap :
328+ def _v1_0_to_v1_1 (document : CommentedMap , outdir : Path ) -> CommentedMap :
322329 """Inner loop for transforming draft-3 to v1.0."""
323330 if "class" in document :
324331 if document ["class" ] == "Workflow" :
@@ -350,11 +357,13 @@ def _v1_0_to_v1_1(document: CommentedMap, outdir: str) -> CommentedMap:
350357 isinstance (entry ["run" ], str )
351358 and "#" not in entry ["run" ]
352359 ):
353- path = Path (document .lc .filename ).parent / entry ["run" ]
354- process = v1_0_to_v1_1 (
355- load_cwl_document (str (path )), outdir
356- )
357- write_cwl_document (process , path .name , outdir )
360+ path = (
361+ Path (document .lc .filename ).parent / entry ["run" ]
362+ ).resolve ()
363+ process = v1_0_to_v1_1 (load_cwl_document (path ), outdir )
364+ new_path = (outdir / entry ["run" ]).resolve ()
365+ new_path .parent .mkdir (parents = True , exist_ok = True )
366+ write_cwl_document (process , new_path )
358367 elif isinstance (entry ["run" ], str ) and "#" in entry ["run" ]:
359368 pass # reference to $graph entry
360369 else :
@@ -397,11 +406,11 @@ def _v1_0_to_v1_1(document: CommentedMap, outdir: str) -> CommentedMap:
397406 return document
398407
399408
400- def _v1_0_to_v1_2 (document : CommentedMap , outdir : str ) -> CommentedMap :
409+ def _v1_0_to_v1_2 (document : CommentedMap , outdir : Path ) -> CommentedMap :
401410 return _v1_0_to_v1_1 (document , outdir ) # nothing needs doing for v1.2
402411
403412
404- def _v1_1_to_v1_2 (document : CommentedMap , outdir : str ) -> CommentedMap :
413+ def _v1_1_to_v1_2 (document : CommentedMap , outdir : Path ) -> CommentedMap :
405414 return document
406415
407416
0 commit comments