Skip to content

Commit 4ab6082

Browse files
committed
Implement Dependency hint to describe tool dependencies.
1 parent c988bb6 commit 4ab6082

File tree

4 files changed

+78
-5
lines changed

4 files changed

+78
-5
lines changed

cwltool/draft2tool.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ def rm_pending_output_callback(output_callback, jobcachepending,
220220
reffiles = copy.deepcopy(builder.files)
221221

222222
j = self.makeJobRunner()
223+
j.tool_dependency_manager = self.tool_dependency_manager
223224
j.builder = builder
224225
j.joborder = builder.job
225226
j.stdin = None

cwltool/job.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,16 @@
2020
from typing import Union, Iterable, Callable, Any, Mapping, IO, cast, Tuple
2121
from .pathmapper import PathMapper
2222
import functools
23+
try:
24+
from galaxy.tools.deps.requirements import ToolRequirement
25+
except ImportError:
26+
ToolRequirement = None
2327

2428
_logger = logging.getLogger("cwltool")
2529

2630
needs_shell_quoting_re = re.compile(r"""(^$|[\s|&;()<>\'"$@])""")
2731

28-
FORCE_SHELLED_POPEN = os.getenv("CWLTOOL_FORCE_SHELL_POPEN", "1") == "1"
32+
FORCE_SHELLED_POPEN = os.getenv("CWLTOOL_FORCE_SHELL_POPEN", "0") == "1"
2933

3034

3135
def deref_links(outputs): # type: (Any) -> None
@@ -64,6 +68,7 @@ def __init__(self): # type: () -> None
6468
self.environment = None # type: Dict[str,str]
6569
self.generatefiles = None # type: Dict[unicode, Union[List[Dict[str, str]], Dict[str,str], str]]
6670
self.stagedir = None # type: unicode
71+
self.dependency_manager = None # type: DependencyManager
6772

6873
def run(self, dry_run=False, pull_image=True, rm_container=True,
6974
rm_tmpdir=True, move_outputs="move", **kwargs):
@@ -214,6 +219,17 @@ def linkoutdir(src, tgt):
214219
else:
215220
stdout_path = None
216221

222+
prefix = None
223+
job_dir = None
224+
if self.tool_dependency_manager is not None:
225+
dependencies = self._find_tool_dependencies()
226+
job_dir = tempfile.mkdtemp(prefix="cwltooljob")
227+
shell_commands = self.tool_dependency_manager.dependency_shell_commands(
228+
dependencies,
229+
job_directory=job_dir,
230+
)
231+
prefix = "\n".join(shell_commands)
232+
217233
rcode = shelled_popen(
218234
[unicode(x).encode('utf-8') for x in runtime + self.command_line],
219235
stdin_path=stdin_path,
@@ -281,6 +297,23 @@ def linkoutdir(src, tgt):
281297
_logger.debug(u"[job %s] Removing empty output directory %s", self.name, self.outdir)
282298
shutil.rmtree(self.outdir, True)
283299

300+
def _find_tool_dependencies(self):
301+
dependencies = []
302+
for hint in self.hints:
303+
hint_class = hint.get("class", "")
304+
if not hint_class:
305+
continue
306+
base_name = hint["class"].rsplit("/", 1)[-1]
307+
if base_name == "Dependency":
308+
requirement_desc = {}
309+
requirement_desc["type"] = "package"
310+
name = hint["name"].rsplit("#", 1)[-1]
311+
version = hint.get("version", "").rsplit("#", 1)[-1]
312+
requirement_desc["name"] = name
313+
requirement_desc["version"] = version or None
314+
dependencies.append(ToolRequirement.from_dict(requirement_desc))
315+
return dependencies
316+
284317

285318
SHELL_COMMAND_TEMPLATE = string.Template("""#!/bin/bash
286319
$prefix
@@ -347,6 +380,7 @@ def shelled_popen(commands,
347380
stderr_path,
348381
env,
349382
cwd,
383+
job_dir=None,
350384
prefix=None):
351385
if prefix is None and not FORCE_SHELLED_POPEN:
352386
if stdin_path is not None:
@@ -389,17 +423,19 @@ def shelled_popen(commands,
389423

390424
return rcode
391425
else:
426+
if job_dir is None:
427+
job_dir = tempfile.mkdtemp(prefix="cwltooljob")
428+
392429
template_kwds = dict(
393430
prefix=prefix or '',
394431
)
395432
job_script_contents = SHELL_COMMAND_TEMPLATE.substitute(
396433
**template_kwds
397434
)
398-
job_dir = tempfile.mkdtemp(prefix="cwltooljob")
399435
job_description = dict(
400436
commands=commands,
401437
cwd=cwd,
402-
env=env,
438+
env=env.copy(),
403439
stdout_path=stdout_path,
404440
stderr_path=stderr_path,
405441
stdin_path=stdin_path,

cwltool/main.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
import rdflib
1818
from typing import Union, Any, cast, Callable, Dict, Tuple, IO
19+
try:
20+
from galaxy.tools import deps
21+
except ImportError:
22+
deps = None
1923

2024
from schema_salad.ref_resolver import Loader
2125
import schema_salad.validate as validate
@@ -37,6 +41,9 @@
3741
_logger.addHandler(defaultStreamHandler)
3842
_logger.setLevel(logging.INFO)
3943

44+
if deps is not None:
45+
deps.log = _logger
46+
4047

4148
def arg_parser(): # type: () -> argparse.ArgumentParser
4249
parser = argparse.ArgumentParser(description='Reference executor for Common Workflow Language')
@@ -138,6 +145,11 @@ def arg_parser(): # type: () -> argparse.ArgumentParser
138145
exgroup.add_argument("--quiet", action="store_true", help="Only print warnings and errors.")
139146
exgroup.add_argument("--debug", action="store_true", help="Print even more logging")
140147

148+
# help="Dependency resolver configuration file describing how to adapt 'Dependency' hints to current system."
149+
parser.add_argument("--beta-dependency-resolvers-configuration", default=None, help=argparse.SUPPRESS)
150+
# help="Defaut root directory used by dependency resolvers configuration."
151+
parser.add_argument("--beta-dependencies-directory", default=None, help=argparse.SUPPRESS)
152+
141153
parser.add_argument("--tool-help", action="store_true", help="Print command line help for tool")
142154

143155
parser.add_argument("--relative-deps", choices=['primary', 'cwd'], default="primary",
@@ -601,6 +613,12 @@ def main(argsl=None,
601613
if not hasattr(args, k):
602614
setattr(args, k, v)
603615

616+
if deps is not None:
617+
tool_dependencies_configuartion = DependenciesConfigruation(args)
618+
tool_dependency_manager = deps.build_dependency_manager(tool_dependencies_configuartion)
619+
else:
620+
tool_dependency_manager = None
621+
604622
if args.quiet:
605623
_logger.setLevel(logging.WARN)
606624
if args.debug:
@@ -645,8 +663,11 @@ def main(argsl=None,
645663
printdot(uri, processobj, document_loader.ctx, stdout)
646664
return 0
647665

666+
make_tool_kwargs = {
667+
'tool_dependency_manager': tool_dependency_manager,
668+
}
648669
tool = make_tool(document_loader, avsc_names, metadata, uri,
649-
makeTool, {})
670+
makeTool, make_tool_kwargs)
650671
except (validate.ValidationException) as exc:
651672
_logger.error(u"Tool definition failed validation:\n%s", exc,
652673
exc_info=(exc if args.debug else False))
@@ -749,5 +770,20 @@ def locToPath(p):
749770
_logger.removeHandler(stderr_handler)
750771
_logger.addHandler(defaultStreamHandler)
751772

773+
774+
class DependenciesConfigruation(object):
775+
776+
def __init__(self, args):
777+
conf_file = getattr(args, "beta_dependency_resolvers_configuration", None)
778+
tool_dependency_dir = getattr(args, "beta_dependencies_directory", None)
779+
if conf_file is not None and os.path.exists(conf_file):
780+
self.use_tool_dependencies = True
781+
if not tool_dependency_dir:
782+
tool_dependency_dir = os.path.abspath(os.path.dirname(conf_file))
783+
self.tool_dependency_dir = tool_dependency_dir
784+
self.dependency_resolvers_config_file = conf_file
785+
else:
786+
self.use_tool_dependencies = False
787+
752788
if __name__ == "__main__":
753789
sys.exit(main(sys.argv[1:]))

cwltool/process.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ def __init__(self, toolpath_object, **kwargs):
389389
avro.schema.make_avsc_object(self.outputs_record_schema, self.names)
390390
except avro.schema.SchemaParseException as e:
391391
raise validate.ValidationException(u"Got error `%s` while prcoessing outputs of %s:\n%s" % (str(e), self.tool["id"], json.dumps(self.outputs_record_schema, indent=4)))
392-
392+
self.tool_dependency_manager = kwargs.get("tool_dependency_manager", None)
393393

394394
def _init_job(self, joborder, **kwargs):
395395
# type: (Dict[unicode, unicode], **Any) -> Builder

0 commit comments

Comments
 (0)