35
35
ACCEPTLIST_EN_RELAXED_RE = re .compile (r".*" ) # Accept anything
36
36
ACCEPTLIST_RE = ACCEPTLIST_EN_STRICT_RE
37
37
DEFAULT_CONTAINER_MSG = """We are on Microsoft Windows and not all components of this CWL description have a
38
- container specified. This means that these steps will be executed in the default container,
38
+ container specified. This means that these steps will be executed in the default container,
39
39
which is %s.
40
40
41
41
Note, this could affect portability if this CWL description relies on non-POSIX features
@@ -116,17 +116,26 @@ def revmap_file(builder, outdir, f):
116
116
if not split .scheme :
117
117
outdir = file_uri (str (outdir ))
118
118
119
+ # builder.outdir is the inner (container/compute node) output directory
120
+ # outdir is the outer (host/storage system) output directory
121
+
119
122
if "location" in f :
120
123
if f ["location" ].startswith ("file://" ):
121
124
path = convert_pathsep_to_unix (uri_file_path (f ["location" ]))
122
125
revmap_f = builder .pathmapper .reversemap (path )
126
+
123
127
if revmap_f and not builder .pathmapper .mapper (revmap_f [0 ]).type .startswith ("Writable" ):
124
128
f ["basename" ] = os .path .basename (path )
125
- f ["location" ] = revmap_f [0 ]
129
+ f ["location" ] = revmap_f [1 ]
126
130
elif path == builder .outdir :
127
131
f ["location" ] = outdir
128
132
elif path .startswith (builder .outdir ):
129
133
f ["location" ] = builder .fs_access .join (outdir , path [len (builder .outdir ) + 1 :])
134
+ elif f ["location" ].startswith (outdir ):
135
+ revmap_f = builder .pathmapper .reversemap (builder .fs_access .join (builder .outdir , f ["location" ][len (outdir ) + 1 :]))
136
+ if revmap_f and not builder .pathmapper .mapper (revmap_f [0 ]).type .startswith ("Writable" ):
137
+ f ["basename" ] = os .path .basename (path )
138
+ f ["location" ] = revmap_f [1 ]
130
139
return f
131
140
132
141
if "path" in f :
@@ -190,7 +199,7 @@ def __init__(self, toolpath_object, **kwargs):
190
199
super (CommandLineTool , self ).__init__ (toolpath_object , ** kwargs )
191
200
self .find_default_container = kwargs .get ("find_default_container" , None )
192
201
193
- def makeJobRunner (self , use_container = True ): # type: (Optional[bool]) -> JobBase
202
+ def makeJobRunner (self , use_container = True , ** kwargs ): # type: (Optional[bool], **Any ) -> JobBase
194
203
dockerReq , _ = self .get_requirement ("DockerRequirement" )
195
204
if not dockerReq and use_container :
196
205
if self .find_default_container :
@@ -216,7 +225,8 @@ def makeJobRunner(self, use_container=True): # type: (Optional[bool]) -> JobBas
216
225
217
226
def makePathMapper (self , reffiles , stagedir , ** kwargs ):
218
227
# type: (List[Any], Text, **Any) -> PathMapper
219
- return PathMapper (reffiles , kwargs ["basedir" ], stagedir )
228
+ return PathMapper (reffiles , kwargs ["basedir" ], stagedir ,
229
+ separateDirs = kwargs .get ("separateDirs" , True ))
220
230
221
231
def updatePathmap (self , outdir , pathmap , fn ):
222
232
# type: (Text, PathMapper, Dict) -> None
@@ -325,9 +335,10 @@ def rm_pending_output_callback(output_callbacks, jobcachepending,
325
335
326
336
reffiles = copy .deepcopy (builder .files )
327
337
328
- j = self .makeJobRunner (kwargs . get ( "use_container" ) )
338
+ j = self .makeJobRunner (** kwargs )
329
339
j .builder = builder
330
340
j .joborder = builder .job
341
+ j .make_pathmapper = self .makePathMapper
331
342
j .stdin = None
332
343
j .stderr = None
333
344
j .stdout = None
@@ -350,6 +361,7 @@ def rm_pending_output_callback(output_callbacks, jobcachepending,
350
361
if "stagedir" in make_path_mapper_kwargs :
351
362
make_path_mapper_kwargs = make_path_mapper_kwargs .copy ()
352
363
del make_path_mapper_kwargs ["stagedir" ]
364
+
353
365
builder .pathmapper = self .makePathMapper (reffiles , builder .stagedir , ** make_path_mapper_kwargs )
354
366
builder .requirements = j .requirements
355
367
@@ -566,7 +578,12 @@ def collect_output(self, schema, builder, outdir, fs_access, compute_checksum=Tr
566
578
elif gb .startswith ("/" ):
567
579
raise WorkflowException ("glob patterns must not start with '/'" )
568
580
try :
581
+ prefix = fs_access .glob (outdir )
569
582
r .extend ([{"location" : g ,
583
+ "path" : fs_access .join (builder .outdir , g [len (prefix [0 ])+ 1 :]),
584
+ "basename" : os .path .basename (g ),
585
+ "nameroot" : os .path .splitext (os .path .basename (g ))[0 ],
586
+ "nameext" : os .path .splitext (os .path .basename (g ))[1 ],
570
587
"class" : "File" if fs_access .isfile (g ) else "Directory" }
571
588
for g in fs_access .glob (fs_access .join (outdir , gb ))])
572
589
except (OSError , IOError ) as e :
@@ -576,12 +593,14 @@ def collect_output(self, schema, builder, outdir, fs_access, compute_checksum=Tr
576
593
raise
577
594
578
595
for files in r :
596
+ rfile = files .copy ()
597
+ revmap (rfile )
579
598
if files ["class" ] == "Directory" :
580
599
ll = builder .loadListing or (binding and binding .get ("loadListing" ))
581
600
if ll and ll != "no_listing" :
582
601
get_listing (fs_access , files , (ll == "deep_listing" ))
583
602
else :
584
- with fs_access .open (files ["location" ], "rb" ) as f :
603
+ with fs_access .open (rfile ["location" ], "rb" ) as f :
585
604
contents = b""
586
605
if binding .get ("loadContents" ) or compute_checksum :
587
606
contents = f .read (CONTENT_LIMIT )
@@ -625,28 +644,39 @@ def collect_output(self, schema, builder, outdir, fs_access, compute_checksum=Tr
625
644
else :
626
645
r = r [0 ]
627
646
628
- # Ensure files point to local references outside of the run environment
629
- adjustFileObjs (r , cast ( # known bug in mypy
630
- # https://github.com/python/mypy/issues/797
631
- Callable [[Any ], Any ], revmap ))
632
-
633
647
if "secondaryFiles" in schema :
634
648
with SourceLine (schema , "secondaryFiles" , WorkflowException ):
635
649
for primary in aslist (r ):
636
650
if isinstance (primary , dict ):
637
- primary ["secondaryFiles" ] = []
651
+ primary .setdefault ("secondaryFiles" , [])
652
+ pathprefix = primary ["path" ][0 :primary ["path" ].rindex ("/" )+ 1 ]
638
653
for sf in aslist (schema ["secondaryFiles" ]):
639
654
if isinstance (sf , dict ) or "$(" in sf or "${" in sf :
640
655
sfpath = builder .do_eval (sf , context = primary )
641
- if isinstance (sfpath , string_types ):
642
- sfpath = revmap ({"location" : sfpath , "class" : "File" })
656
+ subst = False
643
657
else :
644
- sfpath = { "location" : substitute ( primary [ "location" ], sf ), "class" : "File" }
645
-
658
+ sfpath = sf
659
+ subst = True
646
660
for sfitem in aslist (sfpath ):
647
- if fs_access .exists (sfitem ["location" ]):
661
+ if isinstance (sfitem , string_types ):
662
+ if subst :
663
+ sfitem = {"path" : substitute (primary ["path" ], sfitem )}
664
+ else :
665
+ sfitem = {"path" : pathprefix + sfitem }
666
+ if "path" in sfitem and "location" not in sfitem :
667
+ revmap (sfitem )
668
+ if fs_access .isfile (sfitem ["location" ]):
669
+ sfitem ["class" ] = "File"
670
+ primary ["secondaryFiles" ].append (sfitem )
671
+ elif fs_access .isdir (sfitem ["location" ]):
672
+ sfitem ["class" ] = "Directory"
648
673
primary ["secondaryFiles" ].append (sfitem )
649
674
675
+ # Ensure files point to local references outside of the run environment
676
+ adjustFileObjs (r , cast ( # known bug in mypy
677
+ # https://github.com/python/mypy/issues/797
678
+ Callable [[Any ], Any ], revmap ))
679
+
650
680
if not r and optional :
651
681
r = None
652
682
0 commit comments