Mercurial > repos > bcclaywell > argo_navis
comparison venv/lib/python2.7/site-packages/planemo/galaxy_config.py @ 0:d67268158946 draft
planemo upload commit a3f181f5f126803c654b3a66dd4e83a48f7e203b
author | bcclaywell |
---|---|
date | Mon, 12 Oct 2015 17:43:33 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:d67268158946 |
---|---|
1 from __future__ import absolute_import | |
2 from __future__ import print_function | |
3 | |
4 import contextlib | |
5 import os | |
6 import random | |
7 import shutil | |
8 import time | |
9 from six.moves.urllib.request import urlopen | |
10 from six import iteritems | |
11 from string import Template | |
12 from tempfile import mkdtemp | |
13 from six.moves.urllib.request import urlretrieve | |
14 | |
15 import click | |
16 | |
17 from planemo import galaxy_run | |
18 from planemo.io import warn | |
19 from planemo.io import shell | |
20 from planemo.io import write_file | |
21 from planemo.io import kill_pid_file | |
22 from planemo import git | |
23 from planemo.shed import tool_shed_url | |
24 from planemo.bioblend import ( | |
25 galaxy, | |
26 ensure_module, | |
27 ) | |
28 | |
29 | |
30 NO_TEST_DATA_MESSAGE = ( | |
31 "planemo couldn't find a target test-data directory, you should likely " | |
32 "create a test-data directory or pass an explicit path using --test_data." | |
33 ) | |
34 | |
35 WEB_SERVER_CONFIG_TEMPLATE = """ | |
36 [server:${server_name}] | |
37 use = egg:Paste#http | |
38 port = ${port} | |
39 host = ${host} | |
40 use_threadpool = True | |
41 threadpool_kill_thread_limit = 10800 | |
42 [app:main] | |
43 paste.app_factory = galaxy.web.buildapp:app_factory | |
44 """ | |
45 | |
46 TOOL_CONF_TEMPLATE = """<toolbox> | |
47 <tool file="data_source/upload.xml" /> | |
48 ${tool_definition} | |
49 </toolbox> | |
50 """ | |
51 | |
52 SHED_TOOL_CONF_TEMPLATE = """<?xml version="1.0"?> | |
53 <toolbox tool_path="${shed_tools_path}"> | |
54 </toolbox> | |
55 """ | |
56 | |
57 | |
58 EMPTY_JOB_METRICS_TEMPLATE = """<?xml version="1.0"?> | |
59 <job_metrics> | |
60 </job_metrics> | |
61 """ | |
62 | |
63 | |
64 BREW_DEPENDENCY_RESOLUTION_CONF = """<dependency_resolvers> | |
65 <homebrew /> | |
66 <!-- | |
67 <homebrew versionless="true" /> | |
68 --> | |
69 </dependency_resolvers> | |
70 """ | |
71 | |
72 SHED_DEPENDENCY_RESOLUTION_CONF = """<dependency_resolvers> | |
73 <tool_shed_tap /> | |
74 </dependency_resolvers> | |
75 """ | |
76 | |
77 TOOL_SHEDS_CONF = """<tool_sheds> | |
78 <tool_shed name="Target Shed" url="${shed_target_url}" /> | |
79 </tool_sheds> | |
80 """ | |
81 | |
82 # Provide some shortcuts for simple/common dependency resolutions strategies. | |
83 STOCK_DEPENDENCY_RESOLUTION_STRATEGIES = { | |
84 "brew_dependency_resolution": BREW_DEPENDENCY_RESOLUTION_CONF, | |
85 "shed_dependency_resolution": SHED_DEPENDENCY_RESOLUTION_CONF, | |
86 } | |
87 | |
88 EMPTY_TOOL_CONF_TEMPLATE = """<toolbox></toolbox>""" | |
89 | |
90 DOWNLOADS_URL = ("https://raw.githubusercontent.com/" | |
91 "jmchilton/galaxy-downloads/master/") | |
92 DOWNLOADABLE_MIGRATION_VERSIONS = [127, 120, 117] | |
93 LATEST_URL = DOWNLOADS_URL + "latest.sqlite" | |
94 | |
95 FAILED_TO_FIND_GALAXY_EXCEPTION = ( | |
96 "Failed to find Galaxy root directory - please explicitly specify one " | |
97 "with --galaxy_root." | |
98 ) | |
99 | |
100 | |
101 @contextlib.contextmanager | |
102 def galaxy_config(ctx, tool_paths, for_tests=False, **kwds): | |
103 test_data_dir = _find_test_data(tool_paths, **kwds) | |
104 tool_data_table = _find_tool_data_table( | |
105 tool_paths, | |
106 test_data_dir=test_data_dir, | |
107 **kwds | |
108 ) | |
109 galaxy_root = _check_galaxy(ctx, **kwds) | |
110 install_galaxy = galaxy_root is None | |
111 config_directory = kwds.get("config_directory", None) | |
112 | |
113 def config_join(*args): | |
114 return os.path.join(config_directory, *args) | |
115 | |
116 created_config_directory = False | |
117 if not config_directory: | |
118 created_config_directory = True | |
119 config_directory = mkdtemp() | |
120 try: | |
121 latest_galaxy = False | |
122 if install_galaxy: | |
123 _install_galaxy(ctx, config_directory, kwds) | |
124 latest_galaxy = True | |
125 galaxy_root = config_join("galaxy-dev") | |
126 | |
127 _handle_dependency_resolution(config_directory, kwds) | |
128 _handle_job_metrics(config_directory, kwds) | |
129 tool_definition = _tool_conf_entry_for(tool_paths) | |
130 empty_tool_conf = config_join("empty_tool_conf.xml") | |
131 shed_tool_conf = _shed_tool_conf(install_galaxy, config_directory) | |
132 tool_conf = config_join("tool_conf.xml") | |
133 database_location = config_join("galaxy.sqlite") | |
134 shed_tools_path = config_join("shed_tools") | |
135 sheds_config_path = _configure_sheds_config_file( | |
136 ctx, config_directory, **kwds | |
137 ) | |
138 preseeded_database = True | |
139 master_api_key = kwds.get("master_api_key", "test_key") | |
140 dependency_dir = os.path.join(config_directory, "deps") | |
141 | |
142 try: | |
143 _download_database_template( | |
144 galaxy_root, | |
145 database_location, | |
146 latest=latest_galaxy | |
147 ) | |
148 except Exception as e: | |
149 print(e) | |
150 # No network access - just roll forward from null. | |
151 preseeded_database = False | |
152 | |
153 os.makedirs(shed_tools_path) | |
154 server_name = "planemo%d" % random.randint(0, 100000) | |
155 port = kwds.get("port", 9090) | |
156 template_args = dict( | |
157 port=port, | |
158 host=kwds.get("host", "127.0.0.1"), | |
159 server_name=server_name, | |
160 temp_directory=config_directory, | |
161 shed_tools_path=shed_tools_path, | |
162 database_location=database_location, | |
163 tool_definition=tool_definition, | |
164 tool_conf=tool_conf, | |
165 debug=kwds.get("debug", "true"), | |
166 master_api_key=master_api_key, | |
167 id_secret=kwds.get("id_secret", "test_secret"), | |
168 log_level=kwds.get("log_level", "DEBUG"), | |
169 ) | |
170 tool_config_file = "%s,%s" % (tool_conf, shed_tool_conf) | |
171 properties = dict( | |
172 tool_dependency_dir=dependency_dir, | |
173 file_path="${temp_directory}/files", | |
174 new_file_path="${temp_directory}/tmp", | |
175 tool_config_file=tool_config_file, | |
176 tool_sheds_config_file=sheds_config_path, | |
177 check_migrate_tools="False", | |
178 manage_dependency_relationships="False", | |
179 job_working_directory="${temp_directory}/job_working_directory", | |
180 template_cache_path="${temp_directory}/compiled_templates", | |
181 citation_cache_type="file", | |
182 citation_cache_data_dir="${temp_directory}/citations/data", | |
183 citation_cache_lock_dir="${temp_directory}/citations/lock", | |
184 collect_outputs_from="job_working_directory", | |
185 database_auto_migrate="True", | |
186 cleanup_job="never", | |
187 master_api_key="${master_api_key}", | |
188 id_secret="${id_secret}", | |
189 log_level="${log_level}", | |
190 debug="${debug}", | |
191 watch_tools="auto", | |
192 tool_data_table_config_path=tool_data_table, | |
193 integrated_tool_panel_config=("${temp_directory}/" | |
194 "integrated_tool_panel_conf.xml"), | |
195 # Use in-memory database for kombu to avoid database contention | |
196 # during tests. | |
197 amqp_internal_connection="sqlalchemy+sqlite://", | |
198 migrated_tools_config=empty_tool_conf, | |
199 test_data_dir=test_data_dir, # TODO: make gx respect this | |
200 ) | |
201 if not for_tests: | |
202 properties["database_connection"] = \ | |
203 "sqlite:///${database_location}?isolation_level=IMMEDIATE" | |
204 | |
205 _handle_kwd_overrides(properties, kwds) | |
206 | |
207 # TODO: consider following property | |
208 # watch_tool = False | |
209 # datatypes_config_file = config/datatypes_conf.xml | |
210 # welcome_url = /static/welcome.html | |
211 # logo_url = / | |
212 # sanitize_all_html = True | |
213 # serve_xss_vulnerable_mimetypes = False | |
214 # track_jobs_in_database = None | |
215 # outputs_to_working_directory = False | |
216 # retry_job_output_collection = 0 | |
217 | |
218 env = _build_env_for_galaxy(properties, template_args) | |
219 if install_galaxy: | |
220 _build_eggs_cache(ctx, env, kwds) | |
221 _build_test_env(properties, env) | |
222 env['GALAXY_TEST_SHED_TOOL_CONF'] = shed_tool_conf | |
223 | |
224 # No need to download twice - would GALAXY_TEST_DATABASE_CONNECTION | |
225 # work? | |
226 if preseeded_database: | |
227 env["GALAXY_TEST_DB_TEMPLATE"] = os.path.abspath(database_location) | |
228 env["GALAXY_TEST_UPLOAD_ASYNC"] = "false" | |
229 env["GALAXY_DEVELOPMENT_ENVIRONMENT"] = "1" | |
230 web_config = _sub(WEB_SERVER_CONFIG_TEMPLATE, template_args) | |
231 write_file(config_join("galaxy.ini"), web_config) | |
232 tool_conf_contents = _sub(TOOL_CONF_TEMPLATE, template_args) | |
233 write_file(tool_conf, tool_conf_contents) | |
234 write_file(empty_tool_conf, EMPTY_TOOL_CONF_TEMPLATE) | |
235 | |
236 shed_tool_conf_contents = _sub(SHED_TOOL_CONF_TEMPLATE, template_args) | |
237 write_file(shed_tool_conf, shed_tool_conf_contents) | |
238 | |
239 yield GalaxyConfig( | |
240 galaxy_root, | |
241 config_directory, | |
242 env, | |
243 test_data_dir, | |
244 port, | |
245 server_name, | |
246 master_api_key, | |
247 ) | |
248 finally: | |
249 cleanup = not kwds.get("no_cleanup", False) | |
250 if created_config_directory and cleanup: | |
251 shutil.rmtree(config_directory) | |
252 | |
253 | |
254 class GalaxyConfig(object): | |
255 | |
256 def __init__( | |
257 self, | |
258 galaxy_root, | |
259 config_directory, | |
260 env, | |
261 test_data_dir, | |
262 port, | |
263 server_name, | |
264 master_api_key, | |
265 ): | |
266 self.galaxy_root = galaxy_root | |
267 self.config_directory = config_directory | |
268 self.env = env | |
269 self.test_data_dir = test_data_dir | |
270 # Runtime server configuration stuff not used if testing... | |
271 # better design might be GalaxyRootConfig and GalaxyServerConfig | |
272 # as two separate objects. | |
273 self.port = port | |
274 self.server_name = server_name | |
275 self.master_api_key = master_api_key | |
276 | |
277 def kill(self): | |
278 kill_pid_file(self.pid_file) | |
279 | |
280 @property | |
281 def pid_file(self): | |
282 return os.path.join(self.galaxy_root, "%s.pid" % self.server_name) | |
283 | |
284 @property | |
285 def gi(self): | |
286 ensure_module(galaxy) | |
287 return galaxy.GalaxyInstance( | |
288 url="http://localhost:%d" % self.port, | |
289 key=self.master_api_key | |
290 ) | |
291 | |
292 def install_repo(self, *args, **kwds): | |
293 self.tool_shed_client.install_repository_revision( | |
294 *args, **kwds | |
295 ) | |
296 | |
297 @property | |
298 def tool_shed_client(self): | |
299 return self.gi.toolShed | |
300 | |
301 def wait_for_all_installed(self): | |
302 def status_ready(repo): | |
303 status = repo["status"] | |
304 if status in ["Installing", "New"]: | |
305 return False | |
306 if status == "Installed": | |
307 return True | |
308 raise Exception("Error installing repo status is %s" % status) | |
309 | |
310 def not_ready(): | |
311 repos = self.tool_shed_client.get_repositories() | |
312 return not all(map(status_ready, repos)) | |
313 | |
314 self._wait_for(not_ready) | |
315 | |
316 # Taken from Galaxy's twilltestcase. | |
317 def _wait_for(self, func, **kwd): | |
318 sleep_amount = 0.2 | |
319 slept = 0 | |
320 walltime_exceeded = 1086400 | |
321 while slept <= walltime_exceeded: | |
322 result = func() | |
323 if result: | |
324 time.sleep(sleep_amount) | |
325 slept += sleep_amount | |
326 sleep_amount *= 1.25 | |
327 if slept + sleep_amount > walltime_exceeded: | |
328 sleep_amount = walltime_exceeded - slept | |
329 else: | |
330 break | |
331 assert slept < walltime_exceeded, "Action taking too long." | |
332 | |
333 def cleanup(self): | |
334 shutil.rmtree(self.config_directory) | |
335 | |
336 | |
337 def _download_database_template(galaxy_root, database_location, latest=False): | |
338 if latest: | |
339 template_url = DOWNLOADS_URL + urlopen(LATEST_URL).read() | |
340 urlretrieve(template_url, database_location) | |
341 return True | |
342 | |
343 newest_migration = _newest_migration_version(galaxy_root) | |
344 download_migration = None | |
345 for migration in DOWNLOADABLE_MIGRATION_VERSIONS: | |
346 if newest_migration > migration: | |
347 download_migration = migration | |
348 break | |
349 | |
350 if download_migration: | |
351 download_name = "db_gx_rev_0%d.sqlite" % download_migration | |
352 download_url = DOWNLOADS_URL + download_name | |
353 urlretrieve(download_url, database_location) | |
354 return True | |
355 else: | |
356 return False | |
357 | |
358 | |
359 def _newest_migration_version(galaxy_root): | |
360 versions = os.path.join(galaxy_root, "lib/galaxy/model/migrate/versions") | |
361 version = max(map(_file_name_to_migration_version, os.listdir(versions))) | |
362 return version | |
363 | |
364 | |
365 def _file_name_to_migration_version(name): | |
366 try: | |
367 return int(name[0:4]) | |
368 except ValueError: | |
369 return -1 | |
370 | |
371 | |
372 def _check_galaxy(ctx, **kwds): | |
373 """ Find Galaxy root, return None to indicate it should be | |
374 installed automatically. | |
375 """ | |
376 install_galaxy = kwds.get("install_galaxy", None) | |
377 galaxy_root = None | |
378 if not install_galaxy: | |
379 galaxy_root = _find_galaxy_root(ctx, **kwds) | |
380 return galaxy_root | |
381 | |
382 | |
383 def _find_galaxy_root(ctx, **kwds): | |
384 galaxy_root = kwds.get("galaxy_root", None) | |
385 if galaxy_root: | |
386 return galaxy_root | |
387 elif ctx.global_config.get("galaxy_root", None): | |
388 return ctx.global_config["galaxy_root"] | |
389 else: | |
390 par_dir = os.getcwd() | |
391 while True: | |
392 run = os.path.join(par_dir, "run.sh") | |
393 config = os.path.join(par_dir, "config") | |
394 if os.path.isfile(run) and os.path.isdir(config): | |
395 return par_dir | |
396 new_par_dir = os.path.dirname(par_dir) | |
397 if new_par_dir == par_dir: | |
398 break | |
399 par_dir = new_par_dir | |
400 return None | |
401 | |
402 | |
403 def _find_test_data(tool_paths, **kwds): | |
404 path = "." | |
405 if len(tool_paths) > 0: | |
406 path = tool_paths[0] | |
407 | |
408 # Find test data directory associated with path. | |
409 test_data = kwds.get("test_data", None) | |
410 if test_data: | |
411 return os.path.abspath(test_data) | |
412 else: | |
413 test_data = _search_tool_path_for(path, "test-data") | |
414 if test_data: | |
415 return test_data | |
416 warn(NO_TEST_DATA_MESSAGE) | |
417 return None | |
418 | |
419 | |
420 def _find_tool_data_table(tool_paths, test_data_dir, **kwds): | |
421 path = "." | |
422 if len(tool_paths) > 0: | |
423 path = tool_paths[0] | |
424 | |
425 tool_data_table = kwds.get("tool_data_table", None) | |
426 if tool_data_table: | |
427 return os.path.abspath(tool_data_table) | |
428 else: | |
429 extra_paths = [test_data_dir] if test_data_dir else [] | |
430 return _search_tool_path_for( | |
431 path, | |
432 "tool_data_table_conf.xml.test", | |
433 extra_paths, | |
434 ) or _search_tool_path_for( # if all else fails just use sample | |
435 path, | |
436 "tool_data_table_conf.xml.sample" | |
437 ) | |
438 | |
439 | |
440 def _search_tool_path_for(path, target, extra_paths=[]): | |
441 if not os.path.isdir(path): | |
442 tool_dir = os.path.dirname(path) | |
443 else: | |
444 tool_dir = path | |
445 possible_dirs = [tool_dir, "."] + extra_paths | |
446 for possible_dir in possible_dirs: | |
447 possible_path = os.path.join(possible_dir, target) | |
448 if os.path.exists(possible_path): | |
449 return os.path.abspath(possible_path) | |
450 return None | |
451 | |
452 | |
453 def _configure_sheds_config_file(ctx, config_directory, **kwds): | |
454 if "shed_target" not in kwds: | |
455 kwds = kwds.copy() | |
456 kwds["shed_target"] = "toolshed" | |
457 shed_target_url = tool_shed_url(ctx, **kwds) | |
458 contents = _sub(TOOL_SHEDS_CONF, {"shed_target_url": shed_target_url}) | |
459 tool_sheds_conf = os.path.join(config_directory, "tool_sheds_conf.xml") | |
460 write_file(tool_sheds_conf, contents) | |
461 return tool_sheds_conf | |
462 | |
463 | |
464 def _tool_conf_entry_for(tool_paths): | |
465 tool_definitions = "" | |
466 for tool_path in tool_paths: | |
467 if os.path.isdir(tool_path): | |
468 tool_definitions += '''<tool_dir dir="%s" />''' % tool_path | |
469 else: | |
470 tool_definitions += '''<tool file="%s" />''' % tool_path | |
471 return tool_definitions | |
472 | |
473 | |
474 def _shed_tool_conf(install_galaxy, config_directory): | |
475 # TODO: There is probably a reason this is split up like this but I have | |
476 # no clue why I did it and not documented on the commit message. | |
477 if install_galaxy: | |
478 config_dir = os.path.join(config_directory, "galaxy-dev", "config") | |
479 else: | |
480 config_dir = config_directory | |
481 return os.path.join(config_dir, "shed_tool_conf.xml") | |
482 | |
483 | |
484 def _install_galaxy(ctx, config_directory, kwds): | |
485 if not kwds.get("no_cache_galaxy", False): | |
486 _install_galaxy_via_git(ctx, config_directory, kwds) | |
487 else: | |
488 _install_galaxy_via_download(config_directory, kwds) | |
489 | |
490 | |
491 def _install_galaxy_via_download(config_directory, kwds): | |
492 command = galaxy_run.DOWNLOAD_GALAXY + "; tar -zxvf dev | tail" | |
493 _install_with_command(config_directory, command) | |
494 | |
495 | |
496 def _install_galaxy_via_git(ctx, config_directory, kwds): | |
497 _ensure_galaxy_repository_available(ctx) | |
498 workspace = ctx.workspace | |
499 gx_repo = os.path.join(workspace, "gx_repo") | |
500 command = git.command_clone(ctx, gx_repo, "galaxy-dev") | |
501 _install_with_command(config_directory, command) | |
502 | |
503 | |
504 def _build_eggs_cache(ctx, env, kwds): | |
505 if kwds.get("no_cache_galaxy", False): | |
506 return None | |
507 workspace = ctx.workspace | |
508 eggs_path = os.path.join(workspace, "gx_eggs") | |
509 if not os.path.exists(eggs_path): | |
510 os.makedirs(eggs_path) | |
511 env["GALAXY_EGGS_PATH"] = eggs_path | |
512 | |
513 | |
514 def _install_with_command(config_directory, command): | |
515 install_cmds = [ | |
516 "cd %s" % config_directory, | |
517 command, | |
518 "cd galaxy-dev", | |
519 "type virtualenv >/dev/null 2>&1 && virtualenv .venv", | |
520 galaxy_run.ACTIVATE_COMMAND, | |
521 ] | |
522 shell(";".join(install_cmds)) | |
523 | |
524 | |
525 def _ensure_galaxy_repository_available(ctx): | |
526 workspace = ctx.workspace | |
527 gx_repo = os.path.join(workspace, "gx_repo") | |
528 if os.path.exists(gx_repo): | |
529 # Attempt fetch - but don't fail if not interweb, etc... | |
530 shell("git --git-dir %s fetch >/dev/null 2>&1" % gx_repo) | |
531 else: | |
532 remote_repo = "https://github.com/galaxyproject/galaxy" | |
533 command = git.command_clone(ctx, remote_repo, gx_repo, bare=True) | |
534 shell(command) | |
535 | |
536 | |
537 def _build_env_for_galaxy(properties, template_args): | |
538 env = {} | |
539 for key, value in iteritems(properties): | |
540 var = "GALAXY_CONFIG_OVERRIDE_%s" % key.upper() | |
541 value = _sub(value, template_args) | |
542 env[var] = value | |
543 return env | |
544 | |
545 | |
546 def _build_test_env(properties, env): | |
547 # Keeping these environment variables around for a little while but they | |
548 # many are probably not needed as of the following commit. | |
549 # https://bitbucket.org/galaxy/galaxy-central/commits/d7dd1f9 | |
550 test_property_variants = { | |
551 'GALAXY_TEST_MIGRATED_TOOL_CONF': 'migrated_tools_config', | |
552 'GALAXY_TEST_TOOL_CONF': 'tool_config_file', | |
553 'GALAXY_TEST_FILE_DIR': 'test_data_dir', | |
554 'GALAXY_TOOL_DEPENDENCY_DIR': 'tool_dependency_dir', | |
555 # Next line would be required for tool shed tests. | |
556 # 'GALAXY_TEST_TOOL_DEPENDENCY_DIR': 'tool_dependency_dir', | |
557 } | |
558 for test_key, gx_key in test_property_variants.items(): | |
559 value = properties.get(gx_key, None) | |
560 if value is not None: | |
561 env[test_key] = value | |
562 | |
563 | |
564 def _handle_dependency_resolution(config_directory, kwds): | |
565 resolutions_strategies = [ | |
566 "brew_dependency_resolution", | |
567 "dependency_resolvers_config_file", | |
568 "shed_dependency_resolution", | |
569 ] | |
570 | |
571 selected_strategies = 0 | |
572 for key in resolutions_strategies: | |
573 if kwds.get(key): | |
574 selected_strategies += 1 | |
575 | |
576 if selected_strategies > 1: | |
577 message = "At most one option from [%s] may be specified" | |
578 raise click.UsageError(message % resolutions_strategies) | |
579 | |
580 for key in STOCK_DEPENDENCY_RESOLUTION_STRATEGIES: | |
581 if kwds.get(key): | |
582 resolvers_conf = os.path.join( | |
583 config_directory, | |
584 "resolvers_conf.xml" | |
585 ) | |
586 conf_contents = STOCK_DEPENDENCY_RESOLUTION_STRATEGIES[key] | |
587 open(resolvers_conf, "w").write(conf_contents) | |
588 kwds["dependency_resolvers_config_file"] = resolvers_conf | |
589 | |
590 | |
591 def _handle_job_metrics(config_directory, kwds): | |
592 metrics_conf = os.path.join(config_directory, "job_metrics_conf.xml") | |
593 open(metrics_conf, "w").write(EMPTY_JOB_METRICS_TEMPLATE) | |
594 kwds["job_metrics_config_file"] = metrics_conf | |
595 | |
596 | |
597 def _handle_kwd_overrides(properties, kwds): | |
598 kwds_gx_properties = [ | |
599 'job_config_file', | |
600 'job_metrics_config_file', | |
601 'dependency_resolvers_config_file', | |
602 'tool_dependency_dir', | |
603 ] | |
604 for prop in kwds_gx_properties: | |
605 val = kwds.get(prop, None) | |
606 if val: | |
607 properties[prop] = val | |
608 | |
609 | |
610 def _sub(template, args): | |
611 if template is None: | |
612 return '' | |
613 return Template(template).safe_substitute(args) | |
614 | |
615 __all__ = ["galaxy_config"] |