/lib/galaxy/tools/deps/__init__.py

https://bitbucket.org/cistrome/cistrome-harvard/ · Python · 133 lines · 109 code · 14 blank · 10 comment · 2 complexity · fda4669f84a6ce67427db1f79ac5c835 MD5 · raw file

  1. """
  2. Dependency management for tools.
  3. """
  4. import os.path
  5. import logging
  6. log = logging.getLogger( __name__ )
  7. from xml.etree import ElementTree
  8. from .resolvers import INDETERMINATE_DEPENDENCY
  9. from .resolvers.galaxy_packages import GalaxyPackageDependencyResolver
  10. from .resolvers.tool_shed_packages import ToolShedPackageDependencyResolver
  11. from galaxy.util.submodules import submodules
  12. def build_dependency_manager( config ):
  13. if config.use_tool_dependencies:
  14. dependency_manager_kwds = {
  15. 'default_base_path': config.tool_dependency_dir,
  16. 'conf_file': config.dependency_resolvers_config_file,
  17. }
  18. dependency_manager = DependencyManager( **dependency_manager_kwds )
  19. else:
  20. dependency_manager = NullDependencyManager()
  21. return dependency_manager
  22. class NullDependencyManager( object ):
  23. def uses_tool_shed_dependencies(self):
  24. return False
  25. def dependency_shell_commands( self, requirements, **kwds ):
  26. return []
  27. def find_dep( self, name, version=None, type='package', **kwds ):
  28. return INDETERMINATE_DEPENDENCY
  29. class DependencyManager( object ):
  30. """
  31. A DependencyManager attempts to resolve named and versioned dependencies by
  32. searching for them under a list of directories. Directories should be
  33. of the form:
  34. $BASE/name/version/...
  35. and should each contain a file 'env.sh' which can be sourced to make the
  36. dependency available in the current shell environment.
  37. """
  38. def __init__( self, default_base_path, conf_file=None ):
  39. """
  40. Create a new dependency manager looking for packages under the paths listed
  41. in `base_paths`. The default base path is app.config.tool_dependency_dir.
  42. """
  43. if not os.path.exists( default_base_path ):
  44. log.warn( "Path '%s' does not exist, ignoring", default_base_path )
  45. if not os.path.isdir( default_base_path ):
  46. log.warn( "Path '%s' is not directory, ignoring", default_base_path )
  47. self.default_base_path = os.path.abspath( default_base_path )
  48. self.resolver_classes = self.__resolvers_dict()
  49. self.dependency_resolvers = self.__build_dependency_resolvers( conf_file )
  50. def dependency_shell_commands( self, requirements, **kwds ):
  51. commands = []
  52. for requirement in requirements:
  53. log.debug( "Building dependency shell command for dependency '%s'", requirement.name )
  54. dependency = INDETERMINATE_DEPENDENCY
  55. if requirement.type in [ 'package', 'set_environment' ]:
  56. dependency = self.find_dep( name=requirement.name,
  57. version=requirement.version,
  58. type=requirement.type,
  59. **kwds )
  60. dependency_commands = dependency.shell_commands( requirement )
  61. if not dependency_commands:
  62. log.warn( "Failed to resolve dependency on '%s', ignoring", requirement.name )
  63. else:
  64. commands.append( dependency_commands )
  65. return commands
  66. def uses_tool_shed_dependencies(self):
  67. return any( map( lambda r: isinstance( r, ToolShedPackageDependencyResolver ), self.dependency_resolvers ) )
  68. def find_dep( self, name, version=None, type='package', **kwds ):
  69. for resolver in self.dependency_resolvers:
  70. dependency = resolver.resolve( name, version, type, **kwds )
  71. if dependency != INDETERMINATE_DEPENDENCY:
  72. return dependency
  73. return INDETERMINATE_DEPENDENCY
  74. def __build_dependency_resolvers( self, conf_file ):
  75. if not conf_file or not os.path.exists( conf_file ):
  76. return self.__default_dependency_resolvers()
  77. root = ElementTree.parse( conf_file ).getroot()
  78. return self.__parse_resolver_conf_xml( root )
  79. def __default_dependency_resolvers( self ):
  80. return [
  81. ToolShedPackageDependencyResolver(self),
  82. GalaxyPackageDependencyResolver(self),
  83. GalaxyPackageDependencyResolver(self, versionless=True),
  84. ]
  85. def __parse_resolver_conf_xml(self, root):
  86. """
  87. :param root: Object representing the root ``<dependency_resolvers>`` object in the file.
  88. :type root: ``xml.etree.ElementTree.Element``
  89. """
  90. resolvers = []
  91. resolvers_element = root
  92. for resolver_element in resolvers_element.getchildren():
  93. resolver_type = resolver_element.tag
  94. resolver_kwds = dict(resolver_element.items())
  95. resolver = self.resolver_classes[resolver_type](self, **resolver_kwds)
  96. resolvers.append(resolver)
  97. return resolvers
  98. def __resolvers_dict( self ):
  99. resolver_dict = {}
  100. for resolver_module in self.__resolver_modules():
  101. for clazz in resolver_module.__all__:
  102. resolver_type = getattr(clazz, 'resolver_type', None)
  103. if resolver_type:
  104. resolver_dict[resolver_type] = clazz
  105. return resolver_dict
  106. def __resolver_modules( self ):
  107. import galaxy.tools.deps.resolvers
  108. return submodules( galaxy.tools.deps.resolvers )