Skip to content

Commit

Permalink
Merge pull request #1473 from jmchilton/job_shell
Browse files Browse the repository at this point in the history
[16.01] Allow override of job shell (for conda resolver).
  • Loading branch information
bgruening committed Jan 14, 2016
2 parents 1dac5f3 + 602dc7f commit be4ddb2
Show file tree
Hide file tree
Showing 11 changed files with 33 additions and 10 deletions.
8 changes: 8 additions & 0 deletions config/galaxy.ini.sample
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,14 @@ paste.app_factory = galaxy.web.buildapp:app_factory
#check_job_script_integrity_sleep = .25


# Set the default shell used by jobs Galaxy-wide. This defaults to
# sh and can be overidden at the destination level for
# heterogenous clusters. conda job resolution requires bash or zsh
# so if this is not switched to /bin/bash for instance - conda resolution
# should be disabled. (16.01 will likely be the last release with a
# default of /bin/sh instead of /bin/bash).
#default_job_shell = /bin/sh

# Citation related caching. Tool citations information maybe fetched from
# external sources such as http://dx.doi.org/ by Galaxy - the following
# parameters can be used to control the caching used to store this information.
Expand Down
1 change: 1 addition & 0 deletions lib/galaxy/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ def __init__( self, **kwargs ):
self.job_queue_cleanup_interval = int( kwargs.get("job_queue_cleanup_interval", "5") )
self.cluster_files_directory = os.path.abspath( kwargs.get( "cluster_files_directory", "database/pbs" ) )
self.job_working_directory = resolve_path( kwargs.get( "job_working_directory", "database/job_working_directory" ), self.root )
self.default_job_shell = kwargs.get( "default_job_shell", "/bin/sh" )
self.cleanup_job = kwargs.get( "cleanup_job", "always" )
self.container_image_cache_path = self.resolve_path( kwargs.get( "container_image_cache_path", "database/container_images" ) )
self.outputs_to_working_directory = string_as_bool( kwargs.get( 'outputs_to_working_directory', False ) )
Expand Down
8 changes: 8 additions & 0 deletions lib/galaxy/jobs/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
# and should eventually become API'd
TOOL_PROVIDED_JOB_METADATA_FILE = 'galaxy.json'

# Override with config.default_job_shell.
DEFAULT_JOB_SHELL = '/bin/sh'


class JobDestination( Bunch ):
"""
Expand All @@ -55,6 +58,7 @@ def __init__(self, **kwds):
self['runner'] = None
self['legacy'] = False
self['converted'] = False
self['shell'] = None
self['env'] = []
self['resubmit'] = []
# dict is appropriate (rather than a bunch) since keys may not be valid as attributes
Expand Down Expand Up @@ -785,6 +789,10 @@ def get_job_runner_url( self ):
def get_parallelism(self):
return self.tool.parallelism

@property
def shell(self):
return self.job_destination.shell or getattr(self.app.config, 'default_job_shell', DEFAULT_JOB_SHELL)

@property
def commands_in_new_shell(self):
return self.app.config.commands_in_new_shell
Expand Down
12 changes: 6 additions & 6 deletions lib/galaxy/jobs/command_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

CAPTURE_RETURN_CODE = "return_code=$?"
YIELD_CAPTURED_CODE = 'sh -c "exit $return_code"'
DEFAULT_SHELL = "/bin/sh"


def build_command(
Expand All @@ -23,7 +22,7 @@ def build_command(
container=None,
include_metadata=False,
include_work_dir_outputs=True,
remote_command_params={}
remote_command_params={},
):
"""
Compose the sequence of commands necessary to execute a job. This will
Expand All @@ -34,6 +33,7 @@ def build_command(
- command line taken from job wrapper
- commands to set metadata (if include_metadata is True)
"""
shell = job_wrapper.shell
base_command_line = job_wrapper.get_command_line()
# job_id = job_wrapper.job_id
# log.debug( 'Tool evaluation for job (%s) produced command-line: %s' % ( job_id, base_command_line ) )
Expand All @@ -56,7 +56,7 @@ def build_command(
__handle_dependency_resolution(commands_builder, job_wrapper, remote_command_params)

if container or job_wrapper.commands_in_new_shell:
externalized_commands = __externalize_commands(job_wrapper, commands_builder, remote_command_params)
externalized_commands = __externalize_commands(job_wrapper, shell, commands_builder, remote_command_params)
if container:
# Stop now and build command before handling metadata and copying
# working directory files back. These should always happen outside
Expand All @@ -80,18 +80,18 @@ def build_command(
return commands_builder.build()


def __externalize_commands(job_wrapper, commands_builder, remote_command_params, script_name="tool_script.sh"):
def __externalize_commands(job_wrapper, shell, commands_builder, remote_command_params, script_name="tool_script.sh"):
local_container_script = join( job_wrapper.working_directory, script_name )
tool_commands = commands_builder.build()
config = job_wrapper.app.config
integrity_injection = ""
if check_script_integrity(config):
integrity_injection = INTEGRITY_INJECTION
script_contents = u"#!%s\n%s%s" % (DEFAULT_SHELL, integrity_injection, tool_commands)
script_contents = u"#!%s\n%s%s" % (shell, integrity_injection, tool_commands)
write_script(local_container_script, script_contents, config)
commands = local_container_script
if 'working_directory' in remote_command_params:
commands = "%s %s" % (DEFAULT_SHELL, join(remote_command_params['working_directory'], script_name))
commands = "%s %s" % (shell, join(remote_command_params['working_directory'], script_name))
log.info("Built script [%s] for tool command[%s]" % (local_container_script, tool_commands))
return commands

Expand Down
3 changes: 2 additions & 1 deletion lib/galaxy/jobs/runners/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def prepare_job(self, job_wrapper, include_metadata=False, include_work_dir_outp
job_wrapper.runner_command_line = self.build_command_line(
job_wrapper,
include_metadata=include_metadata,
include_work_dir_outputs=include_work_dir_outputs
include_work_dir_outputs=include_work_dir_outputs,
)
except:
log.exception("(%s) Failure preparing job" % job_id)
Expand Down Expand Up @@ -298,6 +298,7 @@ def get_job_file(self, job_wrapper, **kwds):
env_setup_commands=env_setup_commands,
working_directory=os.path.abspath( job_wrapper.working_directory ),
command=command_line,
shell=job_wrapper.shell,
)
# Additional logging to enable if debugging from_work_dir handling, metadata
# commands, etc... (or just peak in the job script.)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
#!$shell

$integrity_injection
$headers
Expand Down
3 changes: 3 additions & 0 deletions lib/galaxy/jobs/runners/util/job_script/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from galaxy.util import unicodify

DEFAULT_SHELL = '/bin/sh'

DEFAULT_JOB_FILE_TEMPLATE = Template(
resource_string(__name__, 'DEFAULT_JOB_FILE_TEMPLATE.sh').decode('UTF-8')
)
Expand Down Expand Up @@ -40,6 +42,7 @@
'instrument_pre_commands': '',
'instrument_post_commands': '',
'integrity_injection': INTEGRITY_INJECTION,
'shell': DEFAULT_SHELL,
}


Expand Down
2 changes: 1 addition & 1 deletion lib/galaxy/tools/deps/resolvers/conda.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ def exact(self):
return self._exact

def shell_commands(self, requirement):
return """[ "$CONDA_DEFAULT_ENV" = "%s" ] || source %s '%s'""" % (
return """[ "$CONDA_DEFAULT_ENV" = "%s" ] || . %s '%s'""" % (
self.environment_path,
self.activate,
self.environment_path
Expand Down
2 changes: 1 addition & 1 deletion test/functional/tools/output_action_change_format.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<tool id="output_action_change_format" name="output_action_change_format" version="1.0.0">
<command>
echo "1\t2" > out1;
printf "1\t2\n" > out1;
</command>
<inputs>
<conditional name="input_cond">
Expand Down
1 change: 1 addition & 0 deletions test/unit/jobs/test_command_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ def __init__(self, job_dir):
check_job_script_integrity=False,
)
)
self.shell = "/bin/sh"

def get_command_line(self):
return self.command_line
Expand Down
1 change: 1 addition & 0 deletions test/unit/jobs/test_runner_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def __init__( self, app, test_directory, tool ):
self.mock_metadata_path = os.path.abspath( os.path.join( test_directory, "METADATA_SET" ) )
self.metadata_command = "touch %s" % self.mock_metadata_path
self.galaxy_virtual_env = None
self.shell = "/bin/bash"

# Cruft for setting metadata externally, axe at some point.
self.external_output_metadata = bunch.Bunch(
Expand Down

0 comments on commit be4ddb2

Please sign in to comment.