Skip to content

Commit 14c06b3

Browse files
authored
Merge branch 'master' into badge-for-jenkins
2 parents e5fe9d9 + 7bfd771 commit 14c06b3

File tree

12 files changed

+228
-16
lines changed

12 files changed

+228
-16
lines changed

MANIFEST.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ include tests/wf/*
99
include tests/override/*
1010
include tests/checker_wf/*
1111
include tests/subgraph/*
12+
include tests/trs/*
1213
include cwltool/schemas/v1.0/*.yml
1314
include cwltool/schemas/v1.0/*.yml
1415
include cwltool/schemas/v1.0/*.md

README.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,7 @@ Running tests locally
498498

499499
- Running basic tests ``(/tests)``:
500500

501-
To run the basis tests after installing `cwltool` execute the following:
501+
To run the basic tests after installing `cwltool` execute the following:
502502

503503
.. code:: bash
504504

cwltool/docker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ def add_writable_directory_volume(self,
259259
self.append_volume(runtime, new_dir, volume.target,
260260
writable=True)
261261
elif not os.path.exists(host_outdir_tgt):
262-
os.makedirs(host_outdir_tgt, 0o0755)
262+
os.makedirs(host_outdir_tgt)
263263
else:
264264
if self.inplace_update:
265265
self.append_volume(runtime, volume.resolved, volume.target,

cwltool/job.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ def create_file_and_add_volume(self,
533533
contents = volume.resolved
534534
dirname = os.path.dirname(host_outdir_tgt or new_file)
535535
if not os.path.exists(dirname):
536-
os.makedirs(dirname, 0o0755)
536+
os.makedirs(dirname)
537537
with open(host_outdir_tgt or new_file, "wb") as file_literal:
538538
file_literal.write(contents.encode("utf-8"))
539539
if not host_outdir_tgt:

cwltool/process.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ def stage_files(pathmapper, # type: PathMapper
225225
if not entry.staged:
226226
continue
227227
if not os.path.exists(os.path.dirname(entry.target)):
228-
os.makedirs(os.path.dirname(entry.target), 0o0755)
228+
os.makedirs(os.path.dirname(entry.target))
229229
if entry.type in ("File", "Directory") and os.path.exists(entry.resolved):
230230
if symlink: # Use symlink func if allowed
231231
if onWindows():
@@ -242,13 +242,13 @@ def stage_files(pathmapper, # type: PathMapper
242242
stage_func(entry.resolved, entry.target)
243243
elif entry.type == "Directory" and not os.path.exists(entry.target) \
244244
and entry.resolved.startswith("_:"):
245-
os.makedirs(entry.target, 0o0755)
245+
os.makedirs(entry.target)
246246
elif entry.type == "WritableFile" and not ignore_writable:
247247
shutil.copy(entry.resolved, entry.target)
248248
ensure_writable(entry.target)
249249
elif entry.type == "WritableDirectory" and not ignore_writable:
250250
if entry.resolved.startswith("_:"):
251-
os.makedirs(entry.target, 0o0755)
251+
os.makedirs(entry.target)
252252
else:
253253
shutil.copytree(entry.resolved, entry.target)
254254
ensure_writable(entry.target)

cwltool/resolver.py

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,17 @@
1313
else:
1414
from pathlib import Path
1515

16+
if not getattr(__builtins__, "WindowsError", None):
17+
class WindowsError(OSError): pass
1618

1719
def resolve_local(document_loader, uri):
1820
pathpart, frag = urllib.parse.urldefrag(uri)
19-
pathobj = Path(pathpart).resolve()
21+
22+
try:
23+
pathobj = Path(pathpart).resolve()
24+
except (WindowsError, OSError):
25+
_logger.debug("local resolver could not resolve %s", uri)
26+
return None
2027

2128
if pathobj.is_file():
2229
if frag:
@@ -48,19 +55,35 @@ def tool_resolver(document_loader, uri):
4855

4956

5057
ga4gh_tool_registries = ["https://dockstore.org/api"]
51-
GA4GH_TRS = "{0}/api/ga4gh/v2/tools/{1}/versions/{2}/plain-CWL/descriptor"
58+
# in the TRS registry, a primary descriptor can be reached at {0}/api/ga4gh/v2/tools/{1}/versions/{2}/plain-CWL/descriptor
59+
# The primary descriptor is a CommandLineTool in the case that the files endpoint only describes one file
60+
# When the primary descriptor is a Workflow, files need to be imported without stripping off "descriptor", looking at the files endpoint is a workaround
61+
# tested with TRS version 2.0.0-beta.2
62+
# TODO not stripping off "descriptor" when looking for local imports would also work https://github.com/ga4gh/tool-registry-service-schemas/blob/2.0.0-beta.2/src/main/resources/swagger/ga4gh-tool-discovery.yaml#L273
63+
GA4GH_TRS_FILES = "{0}/api/ga4gh/v2/tools/{1}/versions/{2}/CWL/files"
64+
GA4GH_TRS_PRIMARY_DESCRIPTOR = "{0}/api/ga4gh/v2/tools/{1}/versions/{2}/plain-CWL/descriptor/{3}"
65+
5266

5367
def resolve_ga4gh_tool(document_loader, uri):
5468
path, version = uri.partition(":")[::2]
5569
if not version:
5670
version = "latest"
5771
for reg in ga4gh_tool_registries:
58-
ds = GA4GH_TRS.format(reg, urllib.parse.quote(path, ""),
59-
urllib.parse.quote(version, ""))
72+
ds = GA4GH_TRS_FILES.format(reg, urllib.parse.quote(path, ""), urllib.parse.quote(version, ""))
6073
try:
74+
_logger.debug("Head path is %s", ds)
6175
resp = document_loader.session.head(ds)
6276
resp.raise_for_status()
63-
return ds
77+
78+
_logger.debug("Passed head path of %s", ds)
79+
80+
resp = document_loader.session.get(ds)
81+
for file_listing in resp.json():
82+
if file_listing.get('file_type') == 'PRIMARY_DESCRIPTOR':
83+
primary_path = file_listing.get('path')
84+
ds2 = GA4GH_TRS_PRIMARY_DESCRIPTOR.format(reg, urllib.parse.quote(path, ""), urllib.parse.quote(version, ""), urllib.parse.quote(primary_path, ""))
85+
_logger.debug("Resolved %s", ds2)
86+
return ds2
6487
except Exception:
6588
pass
6689
return None

cwltool/singularity.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ def add_writable_directory_volume(self,
226226
new_dir = os.path.join(
227227
tempfile.mkdtemp(prefix=tmp_prefix, dir=tmp_dir),
228228
os.path.basename(volume.resolved))
229-
os.makedirs(new_dir, 0o0755)
229+
os.makedirs(new_dir)
230230
else:
231231
if host_outdir_tgt is not None:
232232
# workaround for lack of overlapping mounts in Singularity

tests/test_examples.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import json
22
import logging
33
import os
4+
import stat
45
import sys
56
from io import BytesIO, StringIO
67
import pytest
@@ -792,10 +793,15 @@ class TestSecondaryFiles():
792793
def test_secondary_files(self):
793794
test_file = "secondary-files.cwl"
794795
test_job_file = "secondary-files-job.yml"
795-
error_code, _, stderr = get_main_output(
796-
["--enable-dev",
797-
get_data(os.path.join("tests", test_file)),
798-
get_data(os.path.join("tests", test_job_file))])
796+
try:
797+
old_umask = os.umask(stat.S_IWOTH) # test run with umask 002
798+
error_code, _, stderr = get_main_output(
799+
["--enable-dev",
800+
get_data(os.path.join("tests", test_file)),
801+
get_data(os.path.join("tests", test_job_file))])
802+
finally:
803+
assert stat.S_IMODE(os.stat('lsout').st_mode) == 436 # 664 in octal, '-rw-rw-r--'
804+
os.umask(old_umask) # revert back to original umask
799805
assert "completed success" in stderr
800806
assert error_code == 0
801807

tests/test_trs.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
from __future__ import absolute_import
2+
3+
import mock
4+
5+
from cwltool.main import main
6+
from .util import get_data
7+
8+
def mocked_requests_head(*args):
9+
10+
class MockResponse:
11+
def __init__(self, json_data, status_code, raise_for_status=None):
12+
self.json_data = json_data
13+
self.status_code = status_code
14+
self.raise_for_status = mock.Mock()
15+
self.raise_for_status.side_effect = raise_for_status
16+
17+
def json(self):
18+
return self.json_data
19+
20+
return MockResponse(None, 200)
21+
22+
23+
def mocked_requests_get(*args):
24+
25+
class MockResponse:
26+
def __init__(self, json_data, status_code, raise_for_status=None):
27+
self.json_data = json_data
28+
self.text = json_data
29+
self.status_code = status_code
30+
self.raise_for_status = mock.Mock()
31+
self.raise_for_status.side_effect = raise_for_status
32+
33+
def json(self):
34+
return self.json_data
35+
36+
if args[0] == 'https://dockstore.org/api/api/ga4gh/v2/tools/quay.io%2Fbriandoconnor%2Fdockstore-tool-md5sum/versions/1.0.4/CWL/files':
37+
return MockResponse(
38+
[{"file_type": "CONTAINERFILE", "path": "Dockerfile"}, {"file_type": "PRIMARY_DESCRIPTOR", "path": "Dockstore.cwl"},
39+
{"file_type": "TEST_FILE", "path": "test.json"}], 200)
40+
elif args[0] == 'https://dockstore.org/api/api/ga4gh/v2/tools/quay.io%2Fbriandoconnor%2Fdockstore-tool-md5sum/versions/1.0.4/plain-CWL/descriptor/Dockstore.cwl':
41+
string = open(get_data("tests/trs/Dockstore.cwl"), "r").read()
42+
return MockResponse(string, 200)
43+
elif args[0] == 'https://dockstore.org/api/api/ga4gh/v2/tools/%23workflow%2Fgithub.com%2Fdockstore-testing%2Fmd5sum-checker/versions/develop/plain-CWL/descriptor/md5sum-tool.cwl':
44+
string = open(get_data("tests/trs/md5sum-tool.cwl"), "r").read()
45+
return MockResponse(string, 200)
46+
elif args[0] == 'https://dockstore.org/api/api/ga4gh/v2/tools/%23workflow%2Fgithub.com%2Fdockstore-testing%2Fmd5sum-checker/versions/develop/plain-CWL/descriptor/md5sum-workflow.cwl':
47+
string = open(get_data("tests/trs/md5sum-workflow.cwl"), "r").read()
48+
return MockResponse(string, 200)
49+
elif args[
50+
0] == 'https://dockstore.org/api/api/ga4gh/v2/tools/%23workflow%2Fgithub.com%2Fdockstore-testing%2Fmd5sum-checker/versions/develop/CWL/files':
51+
return MockResponse(
52+
[{"file_type": "TEST_FILE", "path": "md5sum-input-cwl.json"}, {"file_type": "SECONDARY_DESCRIPTOR", "path": "md5sum-tool.cwl"},
53+
{"file_type": "PRIMARY_DESCRIPTOR", "path": "md5sum-workflow.cwl"}], 200)
54+
55+
print ("A mocked call to TRS missed, target was %s", args[0])
56+
return MockResponse(None, 404)
57+
58+
59+
@mock.patch('requests.Session.head', side_effect=mocked_requests_head)
60+
@mock.patch('requests.Session.get', side_effect=mocked_requests_get)
61+
def test_tool_trs_template(mock_head, mock_get):
62+
params = ["--make-template", r"quay.io/briandoconnor/dockstore-tool-md5sum:1.0.4"]
63+
return_value = main(params)
64+
mock_head.assert_called()
65+
mock_get.assert_called()
66+
assert return_value == 0
67+
68+
69+
@mock.patch('requests.Session.head', side_effect=mocked_requests_head)
70+
@mock.patch('requests.Session.get', side_effect=mocked_requests_get)
71+
def test_workflow_trs_template(mock_head, mock_get):
72+
params = ["--make-template", r"#workflow/github.com/dockstore-testing/md5sum-checker:develop"]
73+
return_value = main(params)
74+
mock_head.assert_called()
75+
mock_get.assert_called()
76+
assert return_value == 0

tests/trs/Dockstore.cwl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env cwl-runner
2+
3+
class: CommandLineTool
4+
id: Md5sum
5+
label: Simple md5sum tool
6+
cwlVersion: v1.0
7+
8+
$namespaces:
9+
dct: http://purl.org/dc/terms/
10+
foaf: http://xmlns.com/foaf/0.1/
11+
12+
doc: |
13+
[![Docker Repository on Quay.io](https://quay.io/repository/briandoconnor/dockstore-tool-md5sum/status "Docker Repository on Quay.io")](https://quay.io/repository/briandoconnor/dockstore-tool-md5sum)
14+
[![Build Status](https://travis-ci.org/briandoconnor/dockstore-tool-md5sum.svg)](https://travis-ci.org/briandoconnor/dockstore-tool-md5sum)
15+
A very, very simple Docker container for the md5sum command. See the [README](https://github.com/briandoconnor/dockstore-tool-md5sum/blob/master/README.md) for more information.
16+
17+
18+
#dct:creator:
19+
# '@id': http://orcid.org/0000-0002-7681-6415
20+
# foaf:name: Brian O'Connor
21+
# foaf:mbox: [email protected]
22+
23+
requirements:
24+
- class: DockerRequirement
25+
dockerPull: quay.io/briandoconnor/dockstore-tool-md5sum:1.0.4
26+
- class: InlineJavascriptRequirement
27+
28+
hints:
29+
- class: ResourceRequirement
30+
# The command really requires very little resources.
31+
coresMin: 1
32+
ramMin: 1024
33+
outdirMin: 1024
34+
35+
inputs:
36+
input_file:
37+
type: File
38+
inputBinding:
39+
position: 1
40+
doc: The file that will have its md5sum calculated.
41+
42+
outputs:
43+
output_file:
44+
type: File
45+
format: http://edamontology.org/data_3671
46+
outputBinding:
47+
glob: md5sum.txt
48+
doc: A text file that contains a single line that is the md5sum of the input file.
49+
50+
baseCommand: [/bin/my_md5sum]

0 commit comments

Comments
 (0)