Mercurial > repos > shellac > sam_consensus_v3
diff env/lib/python3.9/site-packages/galaxy/tool_util/deps/resolvers/modules.py @ 0:4f3585e2f14b draft default tip
"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author | shellac |
---|---|
date | Mon, 22 Mar 2021 18:12:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/env/lib/python3.9/site-packages/galaxy/tool_util/deps/resolvers/modules.py Mon Mar 22 18:12:50 2021 +0000 @@ -0,0 +1,221 @@ +""" +This file contains the outline of an implementation to load environment modules +(http://modules.sourceforge.net/). + +This is a community contributed feature and the core Galaxy team does utilize +it, hence support for it will be minimal. The Galaxy team eagerly welcomes +community contribution and maintenance however. +""" +import logging +from io import StringIO +from os import ( + environ, + pathsep +) +from os.path import ( + exists, + isdir, + join +) +from subprocess import ( + PIPE, + Popen +) + +from . import ( + Dependency, + DependencyResolver, + MappableDependencyResolver, + NullDependency, +) + +log = logging.getLogger(__name__) + +DEFAULT_MODULECMD_PATH = "modulecmd" # Just check path +DEFAULT_MODULE_PATH = '/usr/share/modules/modulefiles' +DEFAULT_INDICATOR = '(default)' +DEFAULT_MODULE_PREFETCH = "true" +DEFAULT_MAPPING_FILE = 'config/environment_modules_mapping.yml' +UNKNOWN_FIND_BY_MESSAGE = "ModuleDependencyResolver does not know how to find modules by [%s], find_by should be one of %s" + + +class ModuleDependencyResolver(DependencyResolver, MappableDependencyResolver): + dict_collection_visible_keys = DependencyResolver.dict_collection_visible_keys + ['base_path', 'modulepath', 'modulecmd', 'prefetch', 'default_indicator', 'find_by'] + resolver_type = "modules" + + def __init__(self, dependency_manager, **kwds): + # Mapping file management + self._set_default_mapping_file(kwds) + self._setup_mapping(dependency_manager, **kwds) + self.versionless = _string_as_bool(kwds.get('versionless', 'false')) + find_by = kwds.get('find_by', 'avail') + self.find_by = find_by + prefetch = _string_as_bool(kwds.get('prefetch', DEFAULT_MODULE_PREFETCH)) + self.modulecmd = kwds.get('modulecmd', DEFAULT_MODULECMD_PATH) + self.modulepath = kwds.get('modulepath', self.__default_modulespath()) + self.default_indicator = kwds.get('default_indicator', DEFAULT_INDICATOR) + if find_by == 'directory': + self.module_checker = DirectoryModuleChecker(self, self.modulepath, prefetch) + elif find_by == 'avail': + self.module_checker = AvailModuleChecker(self, self.modulepath, prefetch, self.default_indicator) + else: + raise Exception(UNKNOWN_FIND_BY_MESSAGE % (find_by, ["avail", "directory"])) + + def __default_modulespath(self): + if 'MODULEPATH' in environ: + module_path = environ['MODULEPATH'] + elif 'MODULESHOME' in environ: + module_path = join(environ['MODULESHOME'], 'modulefiles') + else: + module_path = DEFAULT_MODULE_PATH + return module_path + + def _set_default_mapping_file(self, resolver_attributes): + if 'mapping_files' not in resolver_attributes: + if exists(DEFAULT_MAPPING_FILE): + resolver_attributes['mapping_files'] = DEFAULT_MAPPING_FILE + + def resolve(self, requirement, **kwds): + requirement = self._expand_mappings(requirement) + name, version, type = requirement.name, requirement.version, requirement.type + + if type != "package": + return NullDependency(version=version, name=name) + + if self.__has_module(name, version): + return ModuleDependency(self, name, version, exact=True, dependency_resolver=self) + elif self.versionless and self.__has_module(name, None): + return ModuleDependency(self, name, None, exact=False, dependency_resolver=self) + + return NullDependency(version=version, name=name) + + def __has_module(self, name, version): + return self.module_checker.has_module(name, version) + + +class DirectoryModuleChecker: + """Finds module by path. + + Searches the paths listed in modulepath to for a file or directory matching the module name. + If the version=True, searches for files named module/version.""" + + def __init__(self, module_dependency_resolver, modulepath, prefetch): + self.module_dependency_resolver = module_dependency_resolver + self.directories = modulepath.split(pathsep) + if prefetch: + log.warning("Created module dependency resolver with prefetch enabled, but directory module checker does not support this.") + + def has_module(self, module, version): + has_module = False + for directory in self.directories: + module_directory = join(directory, module) + has_module_directory = isdir(module_directory) + if not version: + has_module = has_module_directory or exists(module_directory) # could be a bare modulefile + else: + modulefile = join(module_directory, version) + has_modulefile = exists(modulefile) + has_module = has_module_directory and has_modulefile + if has_module: + break + return has_module + + +class AvailModuleChecker: + """Finds modules by searching output of 'module avail'. + + Parses the Environment Modules 'module avail' output, splitting + module names into module and version on '/' and discarding a postfix matching default_indicator + (by default '(default)'. Matching is done using the module and + (if version=True) the module version.""" + + def __init__(self, module_dependency_resolver, modulepath, prefetch, default_indicator=DEFAULT_INDICATOR): + self.module_dependency_resolver = module_dependency_resolver + self.modulepath = modulepath + self.default_indicator = default_indicator + if prefetch: + prefetched_modules = [] + for module in self.__modules(): + prefetched_modules.append(module) + else: + prefetched_modules = None + self.prefetched_modules = prefetched_modules + + def has_module(self, module, version): + module_generator = self.prefetched_modules + if module_generator is None: + module_generator = self.__modules() + + for module_name, module_version in module_generator: + names_match = module == module_name + module_match = names_match and (version is None or module_version == version) + if module_match: + return True + return False + + def __modules(self): + raw_output = self.__module_avail_output().decode("utf-8") + for line in StringIO(raw_output): + line = line and line.strip() + if not line or line.startswith("-"): + continue + + line_modules = line.split() + for module in line_modules: + if module.endswith(self.default_indicator): + module = module[0:-len(self.default_indicator)].strip() + module_parts = module.split('/') + module_version = None + if len(module_parts) == 2: + module_version = module_parts[1] + module_name = module_parts[0] + yield module_name, module_version + + def __module_avail_output(self): + avail_command = [self.module_dependency_resolver.modulecmd, 'sh', 'avail'] + return Popen(avail_command, stderr=PIPE, env={'MODULEPATH': self.modulepath}).communicate()[1] + + +class ModuleDependency(Dependency): + """Converts module dependencies into shell expressions using modulecmd. + + Using Environment Modules' 'modulecmd' (specifically 'modulecmd sh load') to + convert module specifications into shell expressions for inclusion in + the script used to run a tool in Galaxy.""" + dict_collection_visible_keys = Dependency.dict_collection_visible_keys + ['module_name', 'module_version', 'dependency_resolver'] + dependency_type = 'module' + + def __init__(self, module_dependency_resolver, module_name, module_version=None, exact=True, dependency_resolver=None): + self.module_dependency_resolver = module_dependency_resolver + self.module_name = module_name + self.module_version = module_version + self._exact = exact + self.dependency_resolver = dependency_resolver + + @property + def name(self): + return self.module_name + + @property + def version(self): + return self.module_version + + @property + def exact(self): + return self._exact + + def shell_commands(self): + module_to_load = self.module_name + if self.module_version: + module_to_load = f'{self.module_name}/{self.module_version}' + command = 'MODULEPATH={}; export MODULEPATH; eval `{} sh load {}`'.format(self.module_dependency_resolver.modulepath, + self.module_dependency_resolver.modulecmd, + module_to_load) + return command + + +def _string_as_bool(value): + return str(value).lower() == "true" + + +__all__ = ('ModuleDependencyResolver', )