Mercurial > repos > shellac > sam_consensus_v3
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4f3585e2f14b |
---|---|
1 """ | |
2 This file contains the outline of an implementation to load environment modules | |
3 (http://modules.sourceforge.net/). | |
4 | |
5 This is a community contributed feature and the core Galaxy team does utilize | |
6 it, hence support for it will be minimal. The Galaxy team eagerly welcomes | |
7 community contribution and maintenance however. | |
8 """ | |
9 import logging | |
10 from io import StringIO | |
11 from os import ( | |
12 environ, | |
13 pathsep | |
14 ) | |
15 from os.path import ( | |
16 exists, | |
17 isdir, | |
18 join | |
19 ) | |
20 from subprocess import ( | |
21 PIPE, | |
22 Popen | |
23 ) | |
24 | |
25 from . import ( | |
26 Dependency, | |
27 DependencyResolver, | |
28 MappableDependencyResolver, | |
29 NullDependency, | |
30 ) | |
31 | |
32 log = logging.getLogger(__name__) | |
33 | |
34 DEFAULT_MODULECMD_PATH = "modulecmd" # Just check path | |
35 DEFAULT_MODULE_PATH = '/usr/share/modules/modulefiles' | |
36 DEFAULT_INDICATOR = '(default)' | |
37 DEFAULT_MODULE_PREFETCH = "true" | |
38 DEFAULT_MAPPING_FILE = 'config/environment_modules_mapping.yml' | |
39 UNKNOWN_FIND_BY_MESSAGE = "ModuleDependencyResolver does not know how to find modules by [%s], find_by should be one of %s" | |
40 | |
41 | |
42 class ModuleDependencyResolver(DependencyResolver, MappableDependencyResolver): | |
43 dict_collection_visible_keys = DependencyResolver.dict_collection_visible_keys + ['base_path', 'modulepath', 'modulecmd', 'prefetch', 'default_indicator', 'find_by'] | |
44 resolver_type = "modules" | |
45 | |
46 def __init__(self, dependency_manager, **kwds): | |
47 # Mapping file management | |
48 self._set_default_mapping_file(kwds) | |
49 self._setup_mapping(dependency_manager, **kwds) | |
50 self.versionless = _string_as_bool(kwds.get('versionless', 'false')) | |
51 find_by = kwds.get('find_by', 'avail') | |
52 self.find_by = find_by | |
53 prefetch = _string_as_bool(kwds.get('prefetch', DEFAULT_MODULE_PREFETCH)) | |
54 self.modulecmd = kwds.get('modulecmd', DEFAULT_MODULECMD_PATH) | |
55 self.modulepath = kwds.get('modulepath', self.__default_modulespath()) | |
56 self.default_indicator = kwds.get('default_indicator', DEFAULT_INDICATOR) | |
57 if find_by == 'directory': | |
58 self.module_checker = DirectoryModuleChecker(self, self.modulepath, prefetch) | |
59 elif find_by == 'avail': | |
60 self.module_checker = AvailModuleChecker(self, self.modulepath, prefetch, self.default_indicator) | |
61 else: | |
62 raise Exception(UNKNOWN_FIND_BY_MESSAGE % (find_by, ["avail", "directory"])) | |
63 | |
64 def __default_modulespath(self): | |
65 if 'MODULEPATH' in environ: | |
66 module_path = environ['MODULEPATH'] | |
67 elif 'MODULESHOME' in environ: | |
68 module_path = join(environ['MODULESHOME'], 'modulefiles') | |
69 else: | |
70 module_path = DEFAULT_MODULE_PATH | |
71 return module_path | |
72 | |
73 def _set_default_mapping_file(self, resolver_attributes): | |
74 if 'mapping_files' not in resolver_attributes: | |
75 if exists(DEFAULT_MAPPING_FILE): | |
76 resolver_attributes['mapping_files'] = DEFAULT_MAPPING_FILE | |
77 | |
78 def resolve(self, requirement, **kwds): | |
79 requirement = self._expand_mappings(requirement) | |
80 name, version, type = requirement.name, requirement.version, requirement.type | |
81 | |
82 if type != "package": | |
83 return NullDependency(version=version, name=name) | |
84 | |
85 if self.__has_module(name, version): | |
86 return ModuleDependency(self, name, version, exact=True, dependency_resolver=self) | |
87 elif self.versionless and self.__has_module(name, None): | |
88 return ModuleDependency(self, name, None, exact=False, dependency_resolver=self) | |
89 | |
90 return NullDependency(version=version, name=name) | |
91 | |
92 def __has_module(self, name, version): | |
93 return self.module_checker.has_module(name, version) | |
94 | |
95 | |
96 class DirectoryModuleChecker: | |
97 """Finds module by path. | |
98 | |
99 Searches the paths listed in modulepath to for a file or directory matching the module name. | |
100 If the version=True, searches for files named module/version.""" | |
101 | |
102 def __init__(self, module_dependency_resolver, modulepath, prefetch): | |
103 self.module_dependency_resolver = module_dependency_resolver | |
104 self.directories = modulepath.split(pathsep) | |
105 if prefetch: | |
106 log.warning("Created module dependency resolver with prefetch enabled, but directory module checker does not support this.") | |
107 | |
108 def has_module(self, module, version): | |
109 has_module = False | |
110 for directory in self.directories: | |
111 module_directory = join(directory, module) | |
112 has_module_directory = isdir(module_directory) | |
113 if not version: | |
114 has_module = has_module_directory or exists(module_directory) # could be a bare modulefile | |
115 else: | |
116 modulefile = join(module_directory, version) | |
117 has_modulefile = exists(modulefile) | |
118 has_module = has_module_directory and has_modulefile | |
119 if has_module: | |
120 break | |
121 return has_module | |
122 | |
123 | |
124 class AvailModuleChecker: | |
125 """Finds modules by searching output of 'module avail'. | |
126 | |
127 Parses the Environment Modules 'module avail' output, splitting | |
128 module names into module and version on '/' and discarding a postfix matching default_indicator | |
129 (by default '(default)'. Matching is done using the module and | |
130 (if version=True) the module version.""" | |
131 | |
132 def __init__(self, module_dependency_resolver, modulepath, prefetch, default_indicator=DEFAULT_INDICATOR): | |
133 self.module_dependency_resolver = module_dependency_resolver | |
134 self.modulepath = modulepath | |
135 self.default_indicator = default_indicator | |
136 if prefetch: | |
137 prefetched_modules = [] | |
138 for module in self.__modules(): | |
139 prefetched_modules.append(module) | |
140 else: | |
141 prefetched_modules = None | |
142 self.prefetched_modules = prefetched_modules | |
143 | |
144 def has_module(self, module, version): | |
145 module_generator = self.prefetched_modules | |
146 if module_generator is None: | |
147 module_generator = self.__modules() | |
148 | |
149 for module_name, module_version in module_generator: | |
150 names_match = module == module_name | |
151 module_match = names_match and (version is None or module_version == version) | |
152 if module_match: | |
153 return True | |
154 return False | |
155 | |
156 def __modules(self): | |
157 raw_output = self.__module_avail_output().decode("utf-8") | |
158 for line in StringIO(raw_output): | |
159 line = line and line.strip() | |
160 if not line or line.startswith("-"): | |
161 continue | |
162 | |
163 line_modules = line.split() | |
164 for module in line_modules: | |
165 if module.endswith(self.default_indicator): | |
166 module = module[0:-len(self.default_indicator)].strip() | |
167 module_parts = module.split('/') | |
168 module_version = None | |
169 if len(module_parts) == 2: | |
170 module_version = module_parts[1] | |
171 module_name = module_parts[0] | |
172 yield module_name, module_version | |
173 | |
174 def __module_avail_output(self): | |
175 avail_command = [self.module_dependency_resolver.modulecmd, 'sh', 'avail'] | |
176 return Popen(avail_command, stderr=PIPE, env={'MODULEPATH': self.modulepath}).communicate()[1] | |
177 | |
178 | |
179 class ModuleDependency(Dependency): | |
180 """Converts module dependencies into shell expressions using modulecmd. | |
181 | |
182 Using Environment Modules' 'modulecmd' (specifically 'modulecmd sh load') to | |
183 convert module specifications into shell expressions for inclusion in | |
184 the script used to run a tool in Galaxy.""" | |
185 dict_collection_visible_keys = Dependency.dict_collection_visible_keys + ['module_name', 'module_version', 'dependency_resolver'] | |
186 dependency_type = 'module' | |
187 | |
188 def __init__(self, module_dependency_resolver, module_name, module_version=None, exact=True, dependency_resolver=None): | |
189 self.module_dependency_resolver = module_dependency_resolver | |
190 self.module_name = module_name | |
191 self.module_version = module_version | |
192 self._exact = exact | |
193 self.dependency_resolver = dependency_resolver | |
194 | |
195 @property | |
196 def name(self): | |
197 return self.module_name | |
198 | |
199 @property | |
200 def version(self): | |
201 return self.module_version | |
202 | |
203 @property | |
204 def exact(self): | |
205 return self._exact | |
206 | |
207 def shell_commands(self): | |
208 module_to_load = self.module_name | |
209 if self.module_version: | |
210 module_to_load = f'{self.module_name}/{self.module_version}' | |
211 command = 'MODULEPATH={}; export MODULEPATH; eval `{} sh load {}`'.format(self.module_dependency_resolver.modulepath, | |
212 self.module_dependency_resolver.modulecmd, | |
213 module_to_load) | |
214 return command | |
215 | |
216 | |
217 def _string_as_bool(value): | |
218 return str(value).lower() == "true" | |
219 | |
220 | |
221 __all__ = ('ModuleDependencyResolver', ) |