You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

132 lines
3.8 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2017 Therp BV <http://therp.nl>
  3. # Copyright 2017 LasLabs Inc.
  4. # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html)
  5. import inspect
  6. from werkzeug.local import Local
  7. from odoo.sql_db import Cursor
  8. from odoo.modules import module
  9. from odoo.modules.graph import Graph
  10. original = module.load_information_from_description_file
  11. local = Local()
  12. local.rdepends_to_process = {}
  13. def load_information_from_description_file(module, mod_path=None):
  14. result = original(module, mod_path=mod_path)
  15. # add the keys you want to react on here
  16. if result.get('depends_if_installed'):
  17. cr = _get_cr()
  18. if cr:
  19. _handle_depends_if_installed(cr, result)
  20. if result.get('rdepends_if_installed'):
  21. cr = _get_cr()
  22. if cr:
  23. _handle_rdepends_if_installed(cr, result, module)
  24. # Apply depends specified in other modules as rdepends
  25. extra_depends = local.rdepends_to_process.get(module)
  26. if extra_depends:
  27. result['depends'] += extra_depends
  28. return result
  29. def _handle_depends_if_installed(cr, manifest):
  30. if not manifest.get('depends_if_installed'):
  31. return
  32. added_depends = manifest.pop('depends_if_installed')
  33. added_depends = _installed_modules(cr, added_depends)
  34. depends = manifest.setdefault('depends', [])
  35. depends.extend(added_depends)
  36. def _handle_rdepends_if_installed(cr, manifest, current_module):
  37. graph = _get_graph()
  38. if not graph:
  39. return
  40. rdepends = manifest.pop('rdepends_if_installed')
  41. rdepends = _installed_modules(cr, rdepends)
  42. for rdepend in rdepends:
  43. to_process = local.rdepends_to_process.get(rdepend, set([]))
  44. local.rdepends_to_process[rdepend] = to_process | set([current_module])
  45. # If rdepend already in graph, reload it so new depend is applied
  46. if graph.get(rdepend):
  47. del graph[rdepend]
  48. graph.add_module(cr, rdepend)
  49. def _installed_modules(cr, modules):
  50. if not modules:
  51. return []
  52. cr.execute(
  53. 'SELECT name FROM ir_module_module '
  54. 'WHERE state IN %s AND name IN %s',
  55. (
  56. tuple(['installed', 'to install', 'to upgrade']),
  57. tuple(modules),
  58. ),
  59. )
  60. return [module for module, in cr.fetchall()]
  61. def _get_cr():
  62. cr = None
  63. for frame, filename, lineno, funcname, line, index in inspect.stack():
  64. # walk up the stack until we've found a cursor
  65. if 'cr' in frame.f_locals and isinstance(frame.f_locals['cr'], Cursor):
  66. cr = frame.f_locals['cr']
  67. break
  68. return cr
  69. def _get_graph():
  70. graph = None
  71. for frame, filename, lineno, funcname, line, index in inspect.stack():
  72. # walk up the stack until we've found a graph
  73. if 'graph' in frame.f_locals and isinstance(
  74. frame.f_locals['graph'], Graph
  75. ):
  76. graph = frame.f_locals['graph']
  77. break
  78. return graph
  79. def post_load_hook():
  80. cr = _get_cr()
  81. if not cr:
  82. return
  83. # do nothing if we're not installed
  84. installed = _installed_modules(cr, ['base_manifest_extension'])
  85. if not installed:
  86. return
  87. module.load_information_from_description_file =\
  88. load_information_from_description_file
  89. # here stuff can become tricky: On the python level, modules
  90. # are not loaded in dependency order. This means that there might
  91. # be modules loaded depending on us before we could patch the function
  92. # above. So we reload the module graph for all modules coming after us
  93. graph = _get_graph()
  94. if not graph:
  95. return
  96. this = graph['base_manifest_extension']
  97. to_reload = []
  98. for node in graph.itervalues():
  99. if node.depth > this.depth:
  100. to_reload.append(node.name)
  101. for module_name in to_reload:
  102. del graph[module_name]
  103. graph.add_modules(cr, to_reload)