def test_env_file_builder(): install_dir = "/opt/galaxy/dependencies/foo/" env_file_builder = EnvFileBuilder(install_dir) added_lines = [] mock_return = dict(value=0) def mock_file_append(text, file_path, **kwds): added_lines.append(text) return mock_return["value"] with __mock_env_file_builder_method(env_file_builder, "file_append", mock_file_append): env_file_builder.append_line(name="PATH", action="prepend_to", value="/usr/bin/local/R") assert added_lines == ["PATH=/usr/bin/local/R:$PATH; export PATH"] assert env_file_builder.return_code == 0 # Reset mock lines del added_lines[:] # Next time file_append will fail mock_return["value"] = 1 env_file_builder.append_line(action="source", value="/usr/bin/local/R/env.sh") assert added_lines == [ "if [ -f /usr/bin/local/R/env.sh ] ; then . /usr/bin/local/R/env.sh ; fi" ] # Check failure assert env_file_builder.return_code == 1 mock_return["value"] = 0 env_file_builder.append_line(name="LD_LIBRARY_PATH", action="append_to", value="/usr/bin/local/R/lib") # Verify even though last append succeeded, previous failure still recorded. assert env_file_builder.return_code == 1
def set_environment(self, elem, tool_shed_repository, attr_tups_of_dependencies_for_install): """ Create a ToolDependency to set an environment variable. This is different from the process used to set an environment variable that is associated with a package. An example entry in a tool_dependencies.xml file is:: <set_environment version="1.0"> <environment_variable name="R_SCRIPT_PATH" action="set_to">$REPOSITORY_INSTALL_DIR</environment_variable> </set_environment> This method must also handle the sub-element tag:: <environment_variable name="R_SCRIPT_PATH" action="set_to">$REPOSITORY_INSTALL_DIR</environment_variable> """ # TODO: Add support for a repository dependency definition within this tool dependency type's tag set. This should look something like # the following. See the implementation of support for this in the tool dependency package type's method above. # This function is only called for set environment actions as defined below, not within an <install version="1.0"> tool # dependency type. Here is an example of the tag set this function does handle: # <action type="set_environment"> # <environment_variable name="PATH" action="prepend_to">$INSTALL_DIR</environment_variable> # </action> # Here is an example of the tag set this function does not handle: # <set_environment version="1.0"> # <repository toolshed="<tool shed>" name="<repository name>" owner="<repository owner>" changeset_revision="<changeset revision>" /> # </set_environment> env_manager = EnvManager(self.app) tool_dependencies = [] env_var_version = elem.get('version', '1.0') tool_shed_repository_install_dir = os.path.abspath( tool_shed_repository.repo_files_directory(self.app)) if elem.tag == 'environment_variable': # <environment_variable name="R_SCRIPT_PATH" action="set_to">$REPOSITORY_INSTALL_DIR</environment_variable> elems = [elem] else: # <set_environment version="1.0"> # <environment_variable name="R_SCRIPT_PATH" action="set_to">$REPOSITORY_INSTALL_DIR</environment_variable> # </set_environment> elems = [env_var_elem for env_var_elem in elem] for env_var_elem in elems: env_var_name = env_var_elem.get('name') if not env_var_name: raise Exception( 'The <environment_variable> tag must have a name attribute' ) # The value of env_var_name must match the text value of at least 1 <requirement> tag in the # tool config's <requirements> tag set whose "type" attribute is "set_environment" (e.g., # <requirement type="set_environment">R_SCRIPT_PATH</requirement>). env_var_action = env_var_elem.get('action') if not env_var_action: raise Exception( 'The <environment_variable> tag must have an action attribute' ) # Tool dependencies of type "set_environment" always have the version attribute set to None. attr_tup = (env_var_name, None, 'set_environment') if attr_tup in attr_tups_of_dependencies_for_install: install_dir = \ tool_dependency_util.get_tool_dependency_install_dir(app=self.app, repository_name=tool_shed_repository.name, repository_owner=tool_shed_repository.owner, repository_changeset_revision=tool_shed_repository.installed_changeset_revision, tool_dependency_type='set_environment', tool_dependency_name=env_var_name, tool_dependency_version=None) install_environment = InstallEnvironment( app=self.app, tool_shed_repository_install_dir= tool_shed_repository_install_dir, install_dir=install_dir) env_var_dict = env_manager.create_env_var_dict( elem=env_var_elem, install_environment=install_environment) if not os.path.exists(install_dir): os.makedirs(install_dir) status = self.app.install_model.ToolDependency.installation_status.INSTALLING tool_dependency = \ tool_dependency_util.create_or_update_tool_dependency(app=self.app, tool_shed_repository=tool_shed_repository, name=env_var_name, version=None, type='set_environment', status=status, set_status=True) if env_var_version == '1.0': # Create this tool dependency's env.sh file. env_file_builder = EnvFileBuilder(install_dir) return_code = env_file_builder.append_line( make_executable=True, **env_var_dict) if return_code: error_message = 'Error creating env.sh file for tool dependency %s, return_code: %s' % \ (str(tool_dependency.name), str(return_code)) log.debug(error_message) status = self.app.install_model.ToolDependency.installation_status.ERROR tool_dependency = \ tool_dependency_util.set_tool_dependency_attributes(self.app, tool_dependency=tool_dependency, status=status, error_message=error_message) else: if tool_dependency.status not in [ self.app.install_model.ToolDependency. installation_status.ERROR, self.app.install_model.ToolDependency. installation_status.INSTALLED ]: status = self.app.install_model.ToolDependency.installation_status.INSTALLED tool_dependency = \ tool_dependency_util.set_tool_dependency_attributes(self.app, tool_dependency=tool_dependency, status=status) log.debug( 'Environment variable %s set in %s for tool dependency %s.' % (str(env_var_name), str(install_dir), str(tool_dependency.name))) else: error_message = 'Only set_environment version 1.0 is currently supported (i.e., change your tag to be <set_environment version="1.0">).' status = self.app.install_model.ToolDependency.installation_status.ERROR tool_dependency = \ tool_dependency_util.set_tool_dependency_attributes(self.app, tool_dependency=tool_dependency, status=status, error_message=error_message) tool_dependencies.append(tool_dependency) return tool_dependencies
def create_tool_dependency_with_initialized_env_sh_file( self, dependent_install_dir, tool_shed_repository, required_repository, package_name, package_version, tool_dependencies_config): """ Create or get a tool_dependency record that is defined by the received package_name and package_version. An env.sh file will be created for the tool_dependency in the received dependent_install_dir. """ # The received required_repository refers to a tool_shed_repository record that is defined as a complex # repository dependency for this tool_dependency. The required_repository may or may not be currently # installed (it doesn't matter). If it is installed, it is associated with a tool_dependency that has # an env.sh file that this new tool_dependency must be able to locate and "source". If it is not installed, # we can still determine where that env.sh file will be, so we'll initialize this new tool_dependency's env.sh # file in either case. If the required repository ends up with an installation error, this new tool # dependency will still be fine because its containing repository will be defined as missing dependencies. tool_dependencies = [] if not os.path.exists(dependent_install_dir): os.makedirs(dependent_install_dir) required_tool_dependency_env_file_path = None if tool_dependencies_config: required_td_tree, error_message = parse_xml( tool_dependencies_config) if required_td_tree: required_td_root = required_td_tree.getroot() for required_td_elem in required_td_root: # Find the appropriate package name and version. if required_td_elem.tag == 'package': # <package name="bwa" version="0.5.9"> required_td_package_name = required_td_elem.get( 'name', None) required_td_package_version = required_td_elem.get( 'version', None) # Check the database to see if we have a record for the required tool dependency (we may not which is ok). If we # find a record, we need to see if it is in an error state and if so handle it appropriately. required_tool_dependency = \ tool_dependency_util.get_tool_dependency_by_name_version_type_repository(self.app, required_repository, required_td_package_name, required_td_package_version, 'package') if required_td_package_name == package_name and required_td_package_version == package_version: # Get or create a database tool_dependency record with which the installed package on disk will be associated. tool_dependency = \ tool_dependency_util.create_or_update_tool_dependency(app=self.app, tool_shed_repository=tool_shed_repository, name=package_name, version=package_version, type='package', status=self.app.install_model.ToolDependency.installation_status.NEVER_INSTALLED, set_status=True) # Create an env.sh file for the tool_dependency whose first line will source the env.sh file located in # the path defined by required_tool_dependency_env_file_path. It doesn't matter if the required env.sh # file currently exists.. required_tool_dependency_env_file_path = \ self.get_required_repository_package_env_sh_path(package_name, package_version, required_repository) env_file_builder = EnvFileBuilder( tool_dependency.installation_directory( self.app)) env_file_builder.append_line( action="source", value=required_tool_dependency_env_file_path) return_code = env_file_builder.return_code if return_code: error_message = 'Error defining env.sh file for package %s, return_code: %s' % \ (str(package_name), str(return_code)) tool_dependency = \ tool_dependency_util.set_tool_dependency_attributes(self.app, tool_dependency=tool_dependency, status=self.app.install_model.ToolDependency.installation_status.ERROR, error_message=error_message) elif required_tool_dependency is not None and required_tool_dependency.in_error_state: error_message = "This tool dependency's required tool dependency %s version %s has status %s." % \ (str(required_tool_dependency.name), str(required_tool_dependency.version), str(required_tool_dependency.status)) tool_dependency = \ tool_dependency_util.set_tool_dependency_attributes(self.app, tool_dependency=tool_dependency, status=self.app.install_model.ToolDependency.installation_status.ERROR, error_message=error_message) else: tool_dependency = \ tool_dependency_util.set_tool_dependency_attributes(self.app, tool_dependency=tool_dependency, status=self.app.install_model.ToolDependency.installation_status.INSTALLED) tool_dependencies.append(tool_dependency) return tool_dependencies