Mercurial > repos > shellac > guppy_basecaller
comparison env/lib/python3.7/site-packages/planemo/shed2tap/base.py @ 0:26e78fe6e8c4 draft
"planemo upload commit c699937486c35866861690329de38ec1a5d9f783"
| author | shellac |
|---|---|
| date | Sat, 02 May 2020 07:14:21 -0400 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:26e78fe6e8c4 |
|---|---|
| 1 from __future__ import print_function | |
| 2 | |
| 3 import os | |
| 4 import subprocess | |
| 5 import sys | |
| 6 import tarfile | |
| 7 import zipfile | |
| 8 from ftplib import all_errors as FTPErrors # tuple of exceptions | |
| 9 from xml.etree import ElementTree | |
| 10 | |
| 11 from galaxy.util import unicodify | |
| 12 from six import iteritems | |
| 13 from six import string_types | |
| 14 from six.moves import map as imap | |
| 15 from six.moves.urllib.error import URLError | |
| 16 from six.moves.urllib.request import urlretrieve | |
| 17 | |
| 18 | |
| 19 TOOLSHED_MAP = { | |
| 20 "toolshed": "https://toolshed.g2.bx.psu.edu", | |
| 21 "testtoolshed": "https://testtoolshed.g2.bx.psu.edu", | |
| 22 } | |
| 23 | |
| 24 | |
| 25 class Dependencies(object): | |
| 26 """ Base class for parsing Tool Shed dependency files. | |
| 27 """ | |
| 28 | |
| 29 def __init__( | |
| 30 self, | |
| 31 dependencies_file, | |
| 32 repo=None, | |
| 33 package_factory=None, | |
| 34 ): | |
| 35 if package_factory is None: | |
| 36 package_factory = BasePackage | |
| 37 self.repo = repo | |
| 38 self.root = ElementTree.parse(dependencies_file).getroot() | |
| 39 packages = [] | |
| 40 dependencies = [] | |
| 41 package_els = self.root.findall("package") | |
| 42 assert package_els is not None | |
| 43 for package_el in package_els: | |
| 44 install_els = package_el.findall("install") | |
| 45 readme_els = package_el.findall("readme") | |
| 46 if len(readme_els) > 0: | |
| 47 readme = readme_els[0].text | |
| 48 else: | |
| 49 readme = None | |
| 50 assert len(install_els) in (0, 1) | |
| 51 if len(install_els) == 1: | |
| 52 install_el = install_els[0] | |
| 53 package = package_factory( | |
| 54 self, | |
| 55 package_el, | |
| 56 install_el, | |
| 57 readme=readme | |
| 58 ) | |
| 59 packages.append(package) | |
| 60 else: | |
| 61 repository_el = package_el.find("repository") | |
| 62 if repository_el is None: | |
| 63 message = "no repository in package el for %s" % repo | |
| 64 raise AssertionError(message) | |
| 65 dependency = Dependency(self, package_el, repository_el) | |
| 66 dependencies.append(dependency) | |
| 67 | |
| 68 self.packages = packages | |
| 69 self.dependencies = dependencies | |
| 70 | |
| 71 def single_package(self): | |
| 72 return len(self.packages) == 1 | |
| 73 | |
| 74 def __repr__(self): | |
| 75 return "Dependencies[for_repo=%s]" % self.repo | |
| 76 | |
| 77 | |
| 78 class Repo(object): | |
| 79 | |
| 80 def __init__(self, **kwds): | |
| 81 for key, value in iteritems(kwds): | |
| 82 setattr(self, key, value) | |
| 83 | |
| 84 def recipe_base_name(self): | |
| 85 owner = self.owner.replace("-", "") | |
| 86 name = self.name | |
| 87 name = name.replace("_", "").replace("-", "") | |
| 88 base = "%s_%s" % (owner, name) | |
| 89 return base | |
| 90 | |
| 91 @staticmethod | |
| 92 def from_xml(elem): | |
| 93 tool_shed_url = elem.attrib.get("toolshed", None) | |
| 94 if tool_shed_url and ("testtoolshed" in tool_shed_url): | |
| 95 prefix = "testtoolshed" | |
| 96 else: | |
| 97 prefix = "toolshed" | |
| 98 prior = elem.attrib.get("prior_installation_required", False) | |
| 99 return Repo( | |
| 100 prefix=prefix, | |
| 101 name=elem.attrib["name"], | |
| 102 owner=elem.attrib["owner"], | |
| 103 tool_shed_url=tool_shed_url, | |
| 104 changeset_revision=elem.attrib.get("changeset_revision", None), | |
| 105 prior_installation_required=prior, | |
| 106 ) | |
| 107 | |
| 108 @staticmethod | |
| 109 def from_api(prefix, repo_json): | |
| 110 return Repo( | |
| 111 prefix=prefix, | |
| 112 name=repo_json["name"], | |
| 113 owner=repo_json["owner"], | |
| 114 tool_shed_url=TOOLSHED_MAP[prefix], | |
| 115 ) | |
| 116 | |
| 117 def get_file(self, path): | |
| 118 try: | |
| 119 url_template = "%s/repos/%s/%s/raw-file/tip/%s" | |
| 120 url = url_template % ( | |
| 121 self.tool_shed_url, | |
| 122 self.owner, | |
| 123 self.name, | |
| 124 path | |
| 125 ) | |
| 126 path, headers = urlretrieve(url) | |
| 127 return path | |
| 128 except Exception as e: | |
| 129 print(e) | |
| 130 return None | |
| 131 | |
| 132 def __repr__(self): | |
| 133 return "Repository[name=%s,owner=%s]" % (self.name, self.owner) | |
| 134 | |
| 135 | |
| 136 class Dependency(object): | |
| 137 | |
| 138 def __init__(self, dependencies, package_el, repository_el): | |
| 139 self.dependencies = dependencies | |
| 140 self.package_el = package_el | |
| 141 self.repository_el = repository_el | |
| 142 self.repo = Repo.from_xml(repository_el) | |
| 143 | |
| 144 def __repr__(self): | |
| 145 temp = "Dependency[package_name=%s,version=%s,dependent_package=%s]" | |
| 146 return temp % ( | |
| 147 self.package_el.attrib["name"], | |
| 148 self.package_el.attrib["version"], | |
| 149 self.repository_el.attrib["name"] | |
| 150 ) | |
| 151 | |
| 152 | |
| 153 class BasePackage(object): | |
| 154 | |
| 155 def __init__(self, dependencies, package_el, install_el, readme): | |
| 156 self.dependencies = dependencies | |
| 157 self.package_el = package_el | |
| 158 self.install_el = install_el | |
| 159 self.readme = readme | |
| 160 self.all_actions = self.get_all_actions() | |
| 161 self.no_arch_option = self.has_no_achitecture_install() | |
| 162 | |
| 163 def get_all_actions(self): | |
| 164 action_or_group = self.install_el[0] | |
| 165 parsed_actions = [] | |
| 166 if action_or_group.tag == "actions": | |
| 167 parsed_actions.append(self.parse_actions(action_or_group)) | |
| 168 elif action_or_group.tag == "actions_group": | |
| 169 actions_els = action_or_group.findall("actions") | |
| 170 assert actions_els is not None | |
| 171 for actions in actions_els: | |
| 172 parsed_actions.append(self.parse_actions(actions)) | |
| 173 action_els = action_or_group.findall("action") | |
| 174 assert action_els is not None | |
| 175 for action in action_els: | |
| 176 for parsed_a in parsed_actions: | |
| 177 parsed_a.actions.append(self.parse_action(action)) | |
| 178 return parsed_actions | |
| 179 | |
| 180 def has_no_achitecture_install(self): | |
| 181 all_actions = self.all_actions | |
| 182 if len(all_actions) < 2: | |
| 183 return False | |
| 184 else: | |
| 185 last_action = all_actions[-1] | |
| 186 return (not last_action.architecture) and (not last_action.os) | |
| 187 | |
| 188 def has_explicit_set_environments(self): | |
| 189 all_actions = self.all_actions | |
| 190 for actions in all_actions: | |
| 191 for action in actions.actions: | |
| 192 if action.explicit_variables: | |
| 193 return True | |
| 194 return False | |
| 195 | |
| 196 def has_multiple_set_environments(self): | |
| 197 all_actions = self.all_actions | |
| 198 for actions in all_actions: | |
| 199 count = 0 | |
| 200 for action in actions.actions: | |
| 201 if action.explicit_variables: | |
| 202 count += 1 | |
| 203 if count > 1: | |
| 204 return True | |
| 205 return False | |
| 206 | |
| 207 def parse_actions(self, actions): | |
| 208 os = actions.attrib.get("os", None) | |
| 209 architecture = actions.get("architecture", None) | |
| 210 action_els = actions.findall("action") | |
| 211 assert action_els is not None | |
| 212 parsed_actions = list(imap(self.parse_action, action_els)) | |
| 213 action_packages = [] | |
| 214 for package in actions.findall("package"): | |
| 215 action_packages.append(self.parse_action_package(package)) | |
| 216 return Actions(parsed_actions, os, architecture, action_packages) | |
| 217 | |
| 218 def parse_action_package(self, elem): | |
| 219 name = elem.attrib["name"] | |
| 220 version = elem.attrib["version"] | |
| 221 repo = Repo.from_xml(elem.find("repository")) | |
| 222 return ActionPackage(name, version, repo) | |
| 223 | |
| 224 def parse_action(self, action): | |
| 225 return BaseAction.from_elem(action, package=self) | |
| 226 | |
| 227 def __repr__(self): | |
| 228 actions = self.all_actions | |
| 229 parts = ( | |
| 230 self.package_el.attrib["name"], | |
| 231 self.package_el.attrib["version"], | |
| 232 self.dependencies, | |
| 233 actions | |
| 234 ) | |
| 235 template = "Install[name=%s,version=%s,dependencies=%s,actions=%s]" | |
| 236 return template % parts | |
| 237 | |
| 238 | |
| 239 class Actions(object): | |
| 240 | |
| 241 def __init__( | |
| 242 self, | |
| 243 actions, | |
| 244 os=None, | |
| 245 architecture=None, | |
| 246 action_packages=[] | |
| 247 ): | |
| 248 self.os = os | |
| 249 self.architecture = architecture | |
| 250 self.actions = actions or [] | |
| 251 self.action_packages = action_packages | |
| 252 | |
| 253 def first_download(self): | |
| 254 for action in self.actions: | |
| 255 if action.action_type in ["download_by_url", "download_file"]: | |
| 256 return action | |
| 257 return None | |
| 258 | |
| 259 def downloads(self): | |
| 260 actions = [] | |
| 261 for action in self.actions: | |
| 262 if action.action_type in ["download_by_url", "download_file"]: | |
| 263 actions.append(action) | |
| 264 return actions | |
| 265 | |
| 266 def __repr__(self): | |
| 267 platform = "" | |
| 268 if self.os or self.architecture: | |
| 269 platform = "os=%s,arch=%s," % (self.os, self.architecture) | |
| 270 return "Actions[%s%s]" % (platform, map(str, self.actions)) | |
| 271 | |
| 272 def _indent_extend(self, target, new_entries, indent=" "): | |
| 273 for line in new_entries: | |
| 274 target.append(indent + line) | |
| 275 | |
| 276 def to_bash(self): | |
| 277 # Use self.os.title() to match "Linux" or "Darwin" in bash where case matters: | |
| 278 if self.os and self.architecture: | |
| 279 condition = '("%s" == `uname`) && ("%s" == `arch`)' % (self.os.title(), self.architecture) | |
| 280 elif self.os: | |
| 281 condition = '"%s" == `uname`' % self.os.title() | |
| 282 elif self.architecture: | |
| 283 condition = '"%s" == `arch`' % self.architecture | |
| 284 else: | |
| 285 condition = None | |
| 286 | |
| 287 install_cmds = [] | |
| 288 env_cmds = [] | |
| 289 | |
| 290 if condition: | |
| 291 # Conditional actions block | |
| 292 install_cmds = [ | |
| 293 '#' + '-' * 60, | |
| 294 'if [[ $specifc_action_done == 0 && %s ]]' % condition, | |
| 295 'then', | |
| 296 ' echo "Platform-specific action for os=%s, arch=%s"' % (self.os, self.architecture)] | |
| 297 env_cmds = install_cmds[:] | |
| 298 # TODO - Refactor block indentation? | |
| 299 for action in self.actions: | |
| 300 i_cmds, e_cmds = action.to_bash() | |
| 301 self._indent_extend(install_cmds, i_cmds) | |
| 302 self._indent_extend(env_cmds, e_cmds) | |
| 303 # If we run the action, do not want to run any later actions! | |
| 304 install_cmds.extend([' specifc_action_done=1', 'fi']) | |
| 305 env_cmds.extend([' specifc_action_done=1', 'fi']) | |
| 306 else: | |
| 307 # Non-specific default action... | |
| 308 install_cmds = [ | |
| 309 '#' + '-' * 60, | |
| 310 'if [[ $specifc_action_done == 0 ]]', | |
| 311 'then', | |
| 312 ' echo "Non-platform-specific actions"'] | |
| 313 env_cmds = install_cmds[:] | |
| 314 for action in self.actions: | |
| 315 i_cmds, e_cmds = action.to_bash() | |
| 316 self._indent_extend(install_cmds, i_cmds) | |
| 317 self._indent_extend(env_cmds, e_cmds) | |
| 318 install_cmds.append('fi') | |
| 319 env_cmds.append('fi') | |
| 320 return install_cmds, env_cmds | |
| 321 | |
| 322 | |
| 323 class ActionPackage(object): | |
| 324 | |
| 325 def __init__(self, name, version, repo): | |
| 326 self.name = name | |
| 327 self.version = version | |
| 328 self.repo = repo | |
| 329 | |
| 330 | |
| 331 class BaseAction(object): | |
| 332 | |
| 333 def __repr__(self): | |
| 334 return "Action[type=%s]" % self.action_type | |
| 335 | |
| 336 def same_as(self, other): | |
| 337 if self._keys != other._keys: | |
| 338 return False | |
| 339 else: | |
| 340 for key in self._keys: | |
| 341 if getattr(self, key) != getattr(other, key): | |
| 342 return False | |
| 343 | |
| 344 return True | |
| 345 | |
| 346 def parse_action_repo(self, elem): | |
| 347 repo_elem = elem.find("repository") | |
| 348 repo = Repo.from_xml(repo_elem) | |
| 349 self.repo = repo | |
| 350 | |
| 351 def parse_package_elems(self, elem): | |
| 352 package_els = elem.findall("package") | |
| 353 packages = [] | |
| 354 assert package_els is not None | |
| 355 for package_el in package_els: | |
| 356 packages.append(package_el.text) | |
| 357 self.packages = packages | |
| 358 | |
| 359 @classmethod | |
| 360 def from_elem(cls, elem, package): | |
| 361 type = elem.attrib["type"] | |
| 362 action_class = actions_by_type[type] | |
| 363 return action_class(elem) | |
| 364 | |
| 365 def to_bash(self): | |
| 366 """Return lists of bash shell commands to execute this action. | |
| 367 | |
| 368 This method is be implemented by each sub-class, and will | |
| 369 return two list of strings (for ``dep_install.sh`` and | |
| 370 ``env.sh`` respectively). | |
| 371 """ | |
| 372 raise NotImplementedError("No to_bash defined for %r" % self) | |
| 373 | |
| 374 | |
| 375 def _tar_folders(filename): | |
| 376 with tarfile.open(filename, "r", errorlevel=0) as archive: | |
| 377 folders = set() | |
| 378 for i in archive.getmembers(): | |
| 379 if i.isdir(): | |
| 380 folders.add(i.name.rstrip("/")) | |
| 381 else: | |
| 382 folders.add(os.path.split(i.name)[0]) | |
| 383 return list(folders) | |
| 384 | |
| 385 | |
| 386 def _zip_folders(filename): | |
| 387 archive = zipfile.ZipFile(filename, "r") | |
| 388 return list(set(i.filename.rstrip("/") for i in archive.infolist() if i.filename.endswith("/"))) | |
| 389 | |
| 390 | |
| 391 def _common_prefix(folders): | |
| 392 common_prefix = "" | |
| 393 if len(folders) == 1: | |
| 394 common_prefix = list(folders)[0] | |
| 395 else: | |
| 396 common_prefix = os.path.commonprefix(folders) | |
| 397 assert not os.path.isabs(common_prefix), folders | |
| 398 return common_prefix | |
| 399 | |
| 400 | |
| 401 def _cache_download(url, filename, sha256sum=None): | |
| 402 """Returns local path to cached copy of URL using given filename.""" | |
| 403 cache = os.environ.get("DOWNLOAD_CACHE", "./download_cache/") | |
| 404 # TODO - expose this as a command line option | |
| 405 | |
| 406 if not os.path.isdir(cache): | |
| 407 os.mkdir(cache) | |
| 408 | |
| 409 local = os.path.join(cache, filename) | |
| 410 | |
| 411 if not os.path.isfile(local): | |
| 412 # Must download it... | |
| 413 try: | |
| 414 # TODO - log this nicely... | |
| 415 sys.stderr.write("Downloading %s to %r\n" % (url, local)) | |
| 416 urlretrieve(url, local) | |
| 417 except URLError: | |
| 418 # Most likely server is down, could be bad URL in XML action: | |
| 419 raise RuntimeError("Unable to download %s" % url) | |
| 420 except FTPErrors: | |
| 421 # Most likely server is down, could be bad URL in XML action: | |
| 422 raise RuntimeError("Unable to download %s" % url) | |
| 423 | |
| 424 # Verifying the checksum is slow, only do this on a fresh | |
| 425 # download. Assume locally cached files are already OK. | |
| 426 if sha256sum: | |
| 427 # TODO - log this nicely... | |
| 428 sys.stderr.write("Verifying checksum for %s\n" % filename) | |
| 429 filehash = subprocess.check_output(['shasum', '-a', '256', local])[0:64].strip() | |
| 430 filehash = unicodify(filehash) | |
| 431 if filehash != sha256sum: | |
| 432 raise RuntimeError("Checksum failure for %s, got %r but wanted %r" % (local, filehash, sha256sum)) | |
| 433 | |
| 434 return local | |
| 435 | |
| 436 | |
| 437 def _determine_compressed_file_folder(url, downloaded_filename, target_filename=None, sha256sum=None): | |
| 438 """Determine how to decompress the file & its directory structure. | |
| 439 | |
| 440 Returns a list of shell commands. Consider this example where the | |
| 441 folder to change to cannot be guessed from the tar-ball filename: | |
| 442 | |
| 443 $ curl -o "ncbi-blast-2.2.30+-ia32-linux.tar.gz" \ | |
| 444 "ftp://ftp.ncbi.nlm.nih.gov/blast/executables/blast+/2.2.30/ncbi-blast-2.2.30+-ia32-linux.tar.gz" | |
| 445 $ tar -zxvf ncbi-blast-2.2.30+-ia32-linux.tar.gz | |
| 446 $ cd ncbi-blast-2.2.30+ | |
| 447 | |
| 448 Here it would return: | |
| 449 | |
| 450 ['tar -zxvf ncbi-blast-2.2.30+-ia32-linux.tar.gz', 'cd ncbi-blast-2.2.30+'] | |
| 451 | |
| 452 If not cached, this function will download the file to the | |
| 453 $DOWNLOAD_CACHE folder, and then open it / decompress it in | |
| 454 order to find common folder prefix used. This will also verify | |
| 455 how to decompress the file, and the checksum if given. | |
| 456 """ | |
| 457 answer = [] | |
| 458 | |
| 459 local = _cache_download(url, downloaded_filename, sha256sum) | |
| 460 | |
| 461 if not target_filename: | |
| 462 target_filename = downloaded_filename | |
| 463 | |
| 464 if tarfile.is_tarfile(local): | |
| 465 folders = _tar_folders(local) | |
| 466 if target_filename.endswith((".tar.gz", ".tgz")): | |
| 467 answer.append('tar -zxvf %s' % target_filename) | |
| 468 elif target_filename.endswith(".tar.bz2"): | |
| 469 answer.append('tar -jxvf %s' % target_filename) | |
| 470 elif target_filename.endswith(".tar"): | |
| 471 answer.extend('tar -xvf %s' % target_filename) | |
| 472 else: | |
| 473 # Quite possibly this file doesn't need decompressing, | |
| 474 # but until we've tested lots of real world tool_dependencies.xml | |
| 475 # files I'd like to check these cases to confirm this. | |
| 476 raise NotImplementedError("How to decompress tar file %s?" % target_filename) | |
| 477 elif zipfile.is_zipfile(local): | |
| 478 if target_filename.endswith(".jar"): | |
| 479 # Do not decompress! | |
| 480 return answer | |
| 481 folders = _zip_folders(local) | |
| 482 answer.append('unzip %s' % target_filename) | |
| 483 elif target_filename.endswith(".dmg"): | |
| 484 # Do not decompress! | |
| 485 return answer | |
| 486 else: | |
| 487 # No compression? Leave as it is? | |
| 488 raise NotImplementedError("What kind of compression is %s using?" % local) | |
| 489 | |
| 490 common_prefix = _common_prefix(folders) | |
| 491 if common_prefix: | |
| 492 answer.append('cd "%s"' % common_prefix) | |
| 493 | |
| 494 return answer | |
| 495 | |
| 496 | |
| 497 def _commands_and_downloaded_file(url, target_filename=None, sha256sum=None): | |
| 498 # We preserve the filename from the URL in the cache. | |
| 499 # i.e. We do NOT use the target_filename in the cache. | |
| 500 # This because some Galaxy recipes normalise platform specific downloads | |
| 501 # to use a single target filename, which would therefore break checksums etc | |
| 502 # e.g. tests/data/repos/package_1/tool_dependencies.xml | |
| 503 downloaded_filename = os.path.split(url)[-1] | |
| 504 if "?" in downloaded_filename: | |
| 505 downloaded_filename = downloaded_filename[:downloaded_filename.index("?")] | |
| 506 if "#" in downloaded_filename: | |
| 507 downloaded_filename = downloaded_filename[:downloaded_filename.index("#")] | |
| 508 | |
| 509 if not target_filename: | |
| 510 target_filename = downloaded_filename | |
| 511 | |
| 512 # Curl is present on Mac OS X, can we assume it will be on Linux? | |
| 513 # Cannot assume that wget will be on Mac OS X. | |
| 514 answer = [ | |
| 515 'if [[ -f "%s" ]]' % target_filename, | |
| 516 'then', | |
| 517 ' echo "Reusing existing %s"' % target_filename, | |
| 518 'elif [[ -f "$DOWNLOAD_CACHE/%s" ]]' % downloaded_filename, | |
| 519 'then', | |
| 520 ' echo "Reusing cached %s"' % downloaded_filename, | |
| 521 ' cp "$DOWNLOAD_CACHE/%s" "%s"' % (downloaded_filename, target_filename), | |
| 522 'else', | |
| 523 ' echo "Downloading %s"' % downloaded_filename, | |
| 524 ' curl -L -o "$DOWNLOAD_CACHE/%s" "%s"' % (downloaded_filename, url), | |
| 525 ' cp "$DOWNLOAD_CACHE/%s" "%s"' % (downloaded_filename, target_filename), | |
| 526 ] | |
| 527 if sha256sum: | |
| 528 # This is inserted into the if-else for a fresh download only. | |
| 529 # Note double space between checksum and filename: | |
| 530 answer.append(' echo "%s %s" | shasum -a 256 -c -' % (sha256sum, target_filename)) | |
| 531 answer.append('fi') | |
| 532 | |
| 533 return answer, downloaded_filename | |
| 534 | |
| 535 | |
| 536 def _commands_to_download_and_extract(url, target_filename=None, sha256sum=None): | |
| 537 answer, downloaded_filename = _commands_and_downloaded_file(url, target_filename, sha256sum) | |
| 538 # Now should we unpack the tar-ball etc? | |
| 539 answer.extend(_determine_compressed_file_folder(url, downloaded_filename, target_filename, sha256sum)) | |
| 540 return answer, [] | |
| 541 | |
| 542 | |
| 543 class DownloadByUrlAction(BaseAction): | |
| 544 action_type = "download_by_url" | |
| 545 _keys = ["url"] | |
| 546 | |
| 547 def __init__(self, elem): | |
| 548 self.url = elem.text.strip() | |
| 549 assert self.url | |
| 550 self.sha256sum = elem.attrib.get("sha256sum", None) | |
| 551 self.target_filename = elem.attrib.get("target_filename", None) | |
| 552 | |
| 553 def to_bash(self): | |
| 554 # See class DownloadByUrl in Galaxy, | |
| 555 # lib/tool_shed/galaxy_install/tool_dependencies/recipe/step_handler.py | |
| 556 return _commands_to_download_and_extract(self.url, self.target_filename, self.sha256sum) | |
| 557 | |
| 558 | |
| 559 class DownloadFileAction(BaseAction): | |
| 560 action_type = "download_file" | |
| 561 _keys = ["url", "extract"] | |
| 562 | |
| 563 def __init__(self, elem): | |
| 564 self.url = elem.text.strip() | |
| 565 self.extract = asbool(elem.attrib.get("extract", False)) | |
| 566 self.sha256sum = elem.attrib.get("sha256sum", None) | |
| 567 self.target_filename = elem.attrib.get("target_filename", None) | |
| 568 | |
| 569 def to_bash(self): | |
| 570 if self.extract: | |
| 571 return _commands_to_download_and_extract(self.url, self.target_filename, self.sha256sum) | |
| 572 else: | |
| 573 commands, downloaded_file = _commands_and_downloaded_file(self.url, self.target_filename, self.sha256sum) | |
| 574 return commands, [] | |
| 575 | |
| 576 | |
| 577 class DownloadBinary(BaseAction): | |
| 578 action_type = "download_binary" | |
| 579 _keys = ["url_template", "target_directory"] | |
| 580 | |
| 581 def __init__(self, elem): | |
| 582 self.url_template = elem.text | |
| 583 assert self.url_template | |
| 584 self.target_directory = elem.get('target_directory', None) | |
| 585 | |
| 586 | |
| 587 class ShellCommandAction(BaseAction): | |
| 588 action_type = "shell_command" | |
| 589 _keys = ["command"] | |
| 590 | |
| 591 def __init__(self, elem): | |
| 592 self.command = elem.text | |
| 593 | |
| 594 def to_bash(self): | |
| 595 # Galaxy would run each action from the same temp | |
| 596 # working directory - possible that tool_dependencies.xml | |
| 597 # shell_command could change $PWD so reset this: | |
| 598 return ["pushd . > /dev/null", self.command, "popd > /dev/null"], [] | |
| 599 | |
| 600 | |
| 601 class TemplateShellCommandAction(BaseAction): | |
| 602 action_type = "template_command" | |
| 603 _keys = ["language", "command"] | |
| 604 | |
| 605 def __init__(self, elem): | |
| 606 self.command = elem.text | |
| 607 self.language = elem.get('language', 'cheetah').lower() | |
| 608 assert self.command | |
| 609 assert self.language == "cheetah" | |
| 610 | |
| 611 | |
| 612 class MoveFileAction(BaseAction): | |
| 613 action_type = "move_file" | |
| 614 _keys = ["move_file"] | |
| 615 | |
| 616 def __init__(self, elem): | |
| 617 self.source = elem.find("source").text | |
| 618 self.destination = elem.find("destination").text | |
| 619 | |
| 620 def to_bash(self): | |
| 621 return ["mv %s %s" % (self.source, self.destination)], [] | |
| 622 | |
| 623 | |
| 624 class MoveDirectoryFilesAction(BaseAction): | |
| 625 action_type = "move_directory_files" | |
| 626 _keys = ["source_directory", "destination_directory"] | |
| 627 | |
| 628 def __init__(self, elem): | |
| 629 source_directory = elem.find("source_directory").text | |
| 630 destination_directory = elem.find("destination_directory").text | |
| 631 self.source_directory = source_directory | |
| 632 self.destination_directory = destination_directory | |
| 633 | |
| 634 def to_bash(self): | |
| 635 return ["mv %s/* %s/" % (self.source_directory, self.destination_directory)], [] | |
| 636 | |
| 637 | |
| 638 class SetEnvironmentAction(BaseAction): | |
| 639 action_type = "set_environment" | |
| 640 _keys = ["variables"] | |
| 641 | |
| 642 def __init__(self, elem): | |
| 643 variables = [] | |
| 644 var_els = elem.findall("environment_variable") | |
| 645 assert var_els is not None | |
| 646 for ev_elem in var_els: | |
| 647 var = SetVariable(ev_elem) | |
| 648 variables.append(var) | |
| 649 self.variables = variables | |
| 650 assert self.variables | |
| 651 | |
| 652 def to_bash(self): | |
| 653 answer = [] | |
| 654 for var in self.variables: | |
| 655 # Expand $INSTALL_DIR here? | |
| 656 if var.action == "set_to": | |
| 657 answer.append('export %s=%s' % (var.name, var.raw_value)) | |
| 658 elif var.action == "prepend_to": | |
| 659 answer.append('export %s=%s:$%s' % (var.name, var.raw_value, var.name)) | |
| 660 elif var.action == "append_to": | |
| 661 answer.append('export %s=$%s:%s' % (var.name, var.name, var.raw_value)) | |
| 662 else: | |
| 663 raise ValueError("Undefined environment variable action %r" % var.action) | |
| 664 return answer, answer # Actions needed in env.sh here! | |
| 665 | |
| 666 | |
| 667 class ChmodAction(BaseAction): | |
| 668 action_type = "chmod" | |
| 669 _keys = ["mods"] | |
| 670 | |
| 671 def __init__(self, elem): | |
| 672 mods = [] | |
| 673 file_els = elem.findall("file") | |
| 674 assert file_els is not None | |
| 675 for mod_elem in file_els: | |
| 676 mod = {} | |
| 677 mod["mode"] = mod_elem.attrib["mode"] | |
| 678 mod["target"] = mod_elem.text | |
| 679 mods.append(mod) | |
| 680 self.mods = mods | |
| 681 assert self.mods | |
| 682 | |
| 683 def to_bash(self): | |
| 684 return ["chmod %s %s" % (m["mode"], m["target"]) for m in self.mods], [] | |
| 685 | |
| 686 | |
| 687 class MakeInstallAction(BaseAction): | |
| 688 action_type = "make_install" | |
| 689 _keys = [] | |
| 690 | |
| 691 def __init__(self, elem): | |
| 692 pass | |
| 693 | |
| 694 def to_bash(self): | |
| 695 return ["make install"], [] | |
| 696 | |
| 697 | |
| 698 class AutoconfAction(BaseAction): | |
| 699 action_type = "autoconf" | |
| 700 _keys = ["options"] | |
| 701 | |
| 702 def __init__(self, elem): | |
| 703 self.options = elem.text | |
| 704 | |
| 705 def to_bash(self): | |
| 706 if self.options: | |
| 707 raise NotImplementedError("Options with action autoconf not implemented yet.") | |
| 708 return ['./configure', 'make', 'make install'], [] | |
| 709 | |
| 710 | |
| 711 class ChangeDirectoryAction(BaseAction): | |
| 712 action_type = "change_directory" | |
| 713 _keys = ["directory"] | |
| 714 | |
| 715 def __init__(self, elem): | |
| 716 self.directory = elem.text | |
| 717 assert self.directory | |
| 718 | |
| 719 def to_bash(self): | |
| 720 return ["cd %s" % self.directory], [] | |
| 721 | |
| 722 | |
| 723 class MakeDirectoryAction(BaseAction): | |
| 724 action_type = "make_directory" | |
| 725 _keys = ["directory"] | |
| 726 | |
| 727 def __init__(self, elem): | |
| 728 self.directory = elem.text | |
| 729 | |
| 730 def to_bash(self): | |
| 731 return ["mkdir -p %s" % self.directory], [] | |
| 732 | |
| 733 | |
| 734 class SetupPerlEnvironmentAction(BaseAction): | |
| 735 action_type = "setup_perl_environment" | |
| 736 _keys = ["repo", "packages"] | |
| 737 | |
| 738 def __init__(self, elem): | |
| 739 self.parse_action_repo(elem) | |
| 740 self.parse_package_elems(elem) | |
| 741 | |
| 742 | |
| 743 class SetupRubyEnvironmentAction(BaseAction): | |
| 744 action_type = "setup_ruby_environment" | |
| 745 _keys = ["repo", "packages"] | |
| 746 | |
| 747 def __init__(self, elem): | |
| 748 self.parse_action_repo(elem) | |
| 749 self.parse_package_elems(elem) | |
| 750 | |
| 751 | |
| 752 class SetupPythonEnvironmentAction(BaseAction): | |
| 753 action_type = "setup_python_environment" | |
| 754 _keys = ["repo", "packages"] | |
| 755 | |
| 756 def __init__(self, elem): | |
| 757 self.parse_action_repo(elem) | |
| 758 self.parse_package_elems(elem) | |
| 759 | |
| 760 | |
| 761 class SetupVirtualenvAction(BaseAction): | |
| 762 action_type = "setup_virtualenv" | |
| 763 _keys = ["use_requirements_file", "python", "requirements"] | |
| 764 | |
| 765 def __init__(self, elem): | |
| 766 use_reqs = elem.attrib.get("use_requirements_file", "True") | |
| 767 self.use_requirements_file = asbool(use_reqs) | |
| 768 self.python = elem.get('python', 'python') | |
| 769 self.requirements = elem.text or 'requirements.txt' | |
| 770 | |
| 771 | |
| 772 class SetupREnvironmentAction(BaseAction): | |
| 773 action_type = "setup_r_environment" | |
| 774 _keys = ["repo", "packages"] | |
| 775 | |
| 776 def __init__(self, elem): | |
| 777 self.parse_action_repo(elem) | |
| 778 self.parse_package_elems(elem) | |
| 779 | |
| 780 | |
| 781 class SetEnvironmentForInstallAction(BaseAction): | |
| 782 action_type = "set_environment_for_install" | |
| 783 | |
| 784 def __init__(self, elem): | |
| 785 pass | |
| 786 | |
| 787 def to_bash(self): | |
| 788 # TODO - How could we resolve/check the dependencies? | |
| 789 return ['echo "WARNING: Assuming packages already installed!"'], [] | |
| 790 | |
| 791 | |
| 792 class SetVariable(object): | |
| 793 | |
| 794 def __init__(self, elem): | |
| 795 self.action = elem.attrib["action"] | |
| 796 self.name = elem.attrib["name"] | |
| 797 self.raw_value = elem.text | |
| 798 | |
| 799 | |
| 800 truthy = frozenset(['true', 'yes', 'on', 'y', 't', '1']) | |
| 801 falsy = frozenset(['false', 'no', 'off', 'n', 'f', '0']) | |
| 802 | |
| 803 | |
| 804 def asbool(obj): | |
| 805 if isinstance(obj, string_types): | |
| 806 obj = obj.strip().lower() | |
| 807 if obj in truthy: | |
| 808 return True | |
| 809 elif obj in falsy: | |
| 810 return False | |
| 811 else: | |
| 812 raise ValueError("String is not true/false: %r" % obj) | |
| 813 return bool(obj) | |
| 814 | |
| 815 | |
| 816 action_classes = [ | |
| 817 DownloadByUrlAction, | |
| 818 DownloadFileAction, | |
| 819 DownloadBinary, | |
| 820 ShellCommandAction, | |
| 821 TemplateShellCommandAction, | |
| 822 MoveFileAction, | |
| 823 MoveDirectoryFilesAction, | |
| 824 SetEnvironmentAction, | |
| 825 ChmodAction, | |
| 826 MakeInstallAction, | |
| 827 AutoconfAction, | |
| 828 ChangeDirectoryAction, | |
| 829 MakeDirectoryAction, | |
| 830 SetupPerlEnvironmentAction, | |
| 831 SetupRubyEnvironmentAction, | |
| 832 SetupPythonEnvironmentAction, | |
| 833 SetupVirtualenvAction, | |
| 834 SetupREnvironmentAction, | |
| 835 SetEnvironmentForInstallAction, | |
| 836 ] | |
| 837 | |
| 838 actions_by_type = dict(map(lambda c: (c.action_type, c), action_classes)) |
