Skip to content

Commit feb1326

Browse files
authored
Merge pull request #224 from common-workflow-language/local-resolver
Local resolver
2 parents bb968d3 + 42b465a commit feb1326

File tree

4 files changed

+79
-12
lines changed

4 files changed

+79
-12
lines changed

README.rst

+31-5
Original file line numberDiff line numberDiff line change
@@ -14,29 +14,43 @@ The reference implementation consists of two packages. The "cwltool" package
1414
is the primary Python module containing the reference implementation in the
1515
"cwltool" module and console executable by the same name.
1616

17-
The "cwl-runner" package is optional and provides an additional entry point
17+
The "cwlref-runner" package is optional and provides an additional entry point
1818
under the alias "cwl-runner", which is the implementation-agnostic name for the
1919
default CWL interpreter installed on a host.
2020

2121
Install
2222
-------
2323

24-
Installing the official package from PyPi (will install "cwltool" package as well)::
24+
Installing the official package from PyPi (will install "cwltool" package as
25+
well)::
2526

2627
pip install cwlref-runner
2728

28-
Or from source::
29+
If installling alongside another CWL implementation then::
30+
31+
pip instal cwltool
32+
33+
To install from source::
2934

3035
git clone https://github.com/common-workflow-language/cwltool.git
3136
cd cwltool && python setup.py install
32-
cd cwlref-runner && python setup.py install
37+
cd cwlref-runner && python setup.py install # co-installing? skip this
38+
39+
Remember, if co-installing multiple CWL implementations then you need to
40+
maintain which implementation ``cwl-runner`` points to via a symbolic file
41+
system link or [another facility](https://wiki.debian.org/DebianAlternatives).
3342

3443
Run on the command line
3544
-----------------------
3645

3746
Simple command::
3847

39-
cwl-runner [tool] [job]
48+
cwl-runner [tool-or-workflow-description] [input-job-settings]
49+
50+
Or if you have multiple CWL implementations installed and you want to override
51+
the default cwl-runner use::
52+
53+
cwltool [tool-or-workflow-description] [input-job-settings]
4054

4155
Import as a module
4256
----------------
@@ -60,3 +74,15 @@ and ``--tmp-outdir-prefix`` to somewhere under ``/Users``::
6074

6175
.. |Build Status| image:: https://ci.commonwl.org/buildStatus/icon?job=cwltool-conformance
6276
:target: https://ci.commonwl.org/job/cwltool-conformance/
77+
78+
Tool or workflow loading from remote or local locations
79+
-------------------------------------------------------
80+
81+
``cwltool`` can run tool and workflow descriptions on both local and remote
82+
systems via its support for HTTP[S] URLs.
83+
84+
Input job files and Workflow steps (via the `run` directive) can reference CWL
85+
documents using absolute or relative local filesytem paths. If a relative path
86+
is referenced and that document isn't found in the current directory then the
87+
following locations will be searched:
88+
http://www.commonwl.org/v1.0/CommandLineTool.html#Discovering_CWL_documents_on_a_local_filesystem

cwltool/load_tool.py

+16-6
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@
1919

2020
_logger = logging.getLogger("cwltool")
2121

22-
def fetch_document(argsworkflow):
23-
# type: (Union[Text, Text, dict[Text, Any]]) -> Tuple[Loader, Dict[Text, Any], Text]
22+
def fetch_document(argsworkflow, resolver=None):
23+
# type: (Union[Text, dict[Text, Any]], Any) -> Tuple[Loader, Dict[Text, Any], Text]
2424
"""Retrieve a CWL document."""
2525
document_loader = Loader({"cwl": "https://w3id.org/cwl/cwl#", "id": "@id"})
2626

@@ -30,8 +30,17 @@ def fetch_document(argsworkflow):
3030
split = urlparse.urlsplit(argsworkflow)
3131
if split.scheme:
3232
uri = argsworkflow
33-
else:
33+
elif os.path.exists(os.path.abspath(argsworkflow)):
3434
uri = "file://" + os.path.abspath(argsworkflow)
35+
elif resolver:
36+
uri = resolver(document_loader, argsworkflow)
37+
38+
if uri is None:
39+
raise ValidationException("Not found: '%s'" % argsworkflow)
40+
41+
if argsworkflow != uri:
42+
_logger.info("Resolved '%s' to '%s'", argsworkflow, uri)
43+
3544
fileuri = urlparse.urldefrag(uri)[0]
3645
workflowobj = document_loader.fetch(fileuri)
3746
elif isinstance(argsworkflow, dict):
@@ -193,9 +202,10 @@ def make_tool(document_loader, avsc_names, metadata, uri, makeTool, kwargs):
193202

194203
def load_tool(argsworkflow, makeTool, kwargs=None,
195204
enable_dev=False,
196-
strict=True):
197-
# type: (Union[Text, dict[Text,Any]], Callable[...,Process], Dict[AnyStr, Any], bool, bool) -> Any
198-
document_loader, workflowobj, uri = fetch_document(argsworkflow)
205+
strict=True,
206+
resolver=None):
207+
# type: (Union[Text, dict[Text, Any]], Callable[...,Process], Dict[AnyStr, Any], bool, bool, Any) -> Any
208+
document_loader, workflowobj, uri = fetch_document(argsworkflow, resolver=resolver)
199209
document_loader, avsc_names, processobj, metadata, uri = validate_document(
200210
document_loader, workflowobj, uri, enable_dev=enable_dev,
201211
strict=strict)

cwltool/main.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from .process import shortname, Process, getListing, relocateOutputs, cleanIntermediate, scandeps, normalizeFilesDirs
2929
from .load_tool import fetch_document, validate_document, make_tool
3030
from . import draft2tool
31+
from .resolver import tool_resolver
3132
from .builder import adjustFileObjs, adjustDirObjs
3233
from .stdfsaccess import StdFsAccess
3334
from .pack import pack
@@ -617,7 +618,7 @@ def main(argsl=None,
617618
return 1
618619

619620
try:
620-
document_loader, workflowobj, uri = fetch_document(args.workflow)
621+
document_loader, workflowobj, uri = fetch_document(args.workflow, resolver=tool_resolver)
621622

622623
if args.print_deps:
623624
printdeps(workflowobj, document_loader, stdout, args.relative_deps, uri)

cwltool/resolver.py

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import os
2+
import logging
3+
import urllib
4+
import urlparse
5+
6+
_logger = logging.getLogger("cwltool")
7+
8+
def resolve_local(document_loader, uri):
9+
if uri.startswith("/"):
10+
return None
11+
shares = [os.environ.get("XDG_DATA_HOME", os.path.join(os.environ["HOME"], ".local", "share"))]
12+
shares.extend(os.environ.get("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/").split(":"))
13+
shares = [os.path.join(s, "commonwl", uri) for s in shares]
14+
shares.insert(0, os.path.join(os.getcwd(), uri))
15+
16+
_logger.debug("Search path is %s", shares)
17+
18+
for s in shares:
19+
if os.path.exists(s):
20+
return ("file://%s" % s)
21+
if os.path.exists("%s.cwl" % s):
22+
return ("file://%s.cwl" % s)
23+
return None
24+
25+
def tool_resolver(document_loader, uri):
26+
for r in [resolve_local]:
27+
ret = r(document_loader, uri)
28+
if ret is not None:
29+
return ret
30+
return "file://" + os.path.abspath(uri)

0 commit comments

Comments
 (0)