Skip to content

Commit 949a999

Browse files
authored
Scandeps should not recurse on "listing" field because it is copied e… (#198)
* Scandeps handles file and directory literals. Deduplicate path mapper inputs so that subdirectories don't accidentally get mapped to a different location than their parent directories. Scandeps does not recurse on "listing" or "secondaryFiles" fields because they are copied explicitly.
1 parent cf241cd commit 949a999

File tree

3 files changed

+102
-13
lines changed

3 files changed

+102
-13
lines changed

cwltool/pathmapper.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,27 @@ def abspath(src, basedir): # type: (Text, Text) -> Text
7676
ab = src if os.path.isabs(src) else os.path.join(basedir, src)
7777
return ab
7878

79+
def dedup(listing): # type: (List[Any]) -> List[Any]
80+
marksub = set()
81+
82+
def mark(d):
83+
marksub.add(d["location"])
84+
85+
for l in listing:
86+
if l["class"] == "Directory":
87+
for e in l.get("listing", []):
88+
adjustFileObjs(e, mark)
89+
adjustDirObjs(e, mark)
90+
91+
dd = []
92+
markdup = set() # type: Set[Text]
93+
for r in listing:
94+
if r["location"] not in marksub and r["location"] not in markdup:
95+
dd.append(r)
96+
markdup.add(r["location"])
97+
98+
return dd
99+
79100

80101
class PathMapper(object):
81102

@@ -117,7 +138,7 @@ def __init__(self, referenced_files, basedir, stagedir, separateDirs=True):
117138
self._pathmap = {} # type: Dict[Text, MapperEnt]
118139
self.stagedir = stagedir
119140
self.separateDirs = separateDirs
120-
self.setup(referenced_files, basedir)
141+
self.setup(dedup(referenced_files), basedir)
121142

122143
def visitlisting(self, listing, stagedir, basedir):
123144
# type: (List[Dict[Text, Any]], Text, Text) -> None

cwltool/process.py

+13-5
Original file line numberDiff line numberDiff line change
@@ -647,15 +647,22 @@ def scandeps(base, doc, reffields, urlfields, loadref):
647647

648648
if doc.get("class") in ("File", "Directory") and "location" in urlfields:
649649
u = doc.get("location", doc.get("path"))
650-
if u:
650+
if u and not u.startswith("_:"):
651651
deps = {
652652
"class": doc["class"],
653653
"location": urlparse.urljoin(base, u)
654654
}
655655
if doc["class"] == "Directory" and "listing" in doc:
656656
deps["listing"] = doc["listing"]
657+
if doc["class"] == "File" and "secondaryFiles" in doc:
658+
deps["secondaryFiles"] = doc["secondaryFiles"]
657659
deps = nestdir(base, deps)
658660
r.append(deps)
661+
else:
662+
if doc["class"] == "Directory" and "listing" in doc:
663+
r.extend(scandeps(base, doc["listing"], reffields, urlfields, loadref))
664+
elif doc["class"] == "File" and "secondaryFiles" in doc:
665+
r.extend(scandeps(base, doc["secondaryFiles"], reffields, urlfields, loadref))
659666

660667
for k, v in doc.iteritems():
661668
if k in reffields:
@@ -674,20 +681,21 @@ def scandeps(base, doc, reffields, urlfields, loadref):
674681
deps["secondaryFiles"] = sf
675682
deps = nestdir(base, deps)
676683
r.append(deps)
677-
elif k in urlfields:
684+
elif k in urlfields and k != "location":
678685
for u in aslist(v):
679686
deps = {
680687
"class": "File",
681688
"location": urlparse.urljoin(base, u)
682689
}
683690
deps = nestdir(base, deps)
684691
r.append(deps)
685-
else:
692+
elif k not in ("listing", "secondaryFiles"):
686693
r.extend(scandeps(base, v, reffields, urlfields, loadref))
687694
elif isinstance(doc, list):
688695
for d in doc:
689696
r.extend(scandeps(base, d, reffields, urlfields, loadref))
690697

691-
normalizeFilesDirs(r)
692-
r = mergedirs(r)
698+
if r:
699+
normalizeFilesDirs(r)
700+
r = mergedirs(r)
693701
return r

tests/test_examples.py

+67-7
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import cwltool.expression as expr
55
import cwltool.factory
66
import cwltool.process
7+
import cwltool.pathmapper
78
import cwltool.workflow
89

910
class TestParamMatching(unittest.TestCase):
@@ -134,9 +135,28 @@ def test_scandeps(self):
134135
"location": "file:///example/data2",
135136
"listing": [{
136137
"class": "File",
137-
"location": "file:///example/data3.txt"
138+
"location": "file:///example/data3.txt",
139+
"secondaryFiles": [{
140+
"class": "File",
141+
"location": "file:///example/data5.txt"
142+
}]
143+
}]
144+
},
145+
}, {
146+
"id": "file:///example/bar.cwl#input3",
147+
"default": {
148+
"class": "Directory",
149+
"listing": [{
150+
"class": "File",
151+
"location": "file:///example/data4.txt"
138152
}]
139153
}
154+
}, {
155+
"id": "file:///example/bar.cwl#input4",
156+
"default": {
157+
"class": "File",
158+
"contents": "file literal"
159+
}
140160
}]
141161
}
142162
}
@@ -173,13 +193,17 @@ def loadref(base, p):
173193
"listing": [{
174194
"basename": "data3.txt",
175195
"class": "File",
176-
"location": "file:///example/data3.txt"
196+
"location": "file:///example/data3.txt",
197+
"secondaryFiles": [{
198+
"class": "File",
199+
"basename": "data5.txt",
200+
"location": "file:///example/data5.txt"
201+
}]
177202
}]
178-
},
179-
{
180-
"basename": "data3.txt",
181-
"class": "File",
182-
"location": "file:///example/data3.txt"
203+
}, {
204+
"basename": "data4.txt",
205+
"class": "File",
206+
"location": "file:///example/data4.txt"
183207
}], sc)
184208

185209
sc = cwltool.process.scandeps(obj["id"], obj,
@@ -194,6 +218,42 @@ def loadref(base, p):
194218
"location": "file:///example/bar.cwl"
195219
}], sc)
196220

221+
class TestDedup(unittest.TestCase):
222+
def test_dedup(self):
223+
ex = [{
224+
"class": "File",
225+
"location": "file:///example/a"
226+
},
227+
{
228+
"class": "File",
229+
"location": "file:///example/a"
230+
},
231+
{
232+
"class": "File",
233+
"location": "file:///example/d"
234+
},
235+
{
236+
"class": "Directory",
237+
"location": "file:///example/c",
238+
"listing": [{
239+
"class": "File",
240+
"location": "file:///example/d"
241+
}]
242+
}]
243+
244+
self.assertEquals([{
245+
"class": "File",
246+
"location": "file:///example/a"
247+
},
248+
{
249+
"class": "Directory",
250+
"location": "file:///example/c",
251+
"listing": [{
252+
"class": "File",
253+
"location": "file:///example/d"
254+
}]
255+
}], cwltool.pathmapper.dedup(ex))
256+
197257

198258
class TestTypeCompare(unittest.TestCase):
199259
def test_typecompare(self):

0 commit comments

Comments
 (0)