gooderp18绿色标准版
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

200 rindas
6.6KB

  1. # -*- coding: utf-8 -*-
  2. # Part of Odoo. See LICENSE file for full copyright and licensing details.
  3. """ Modules dependency graph. """
  4. import functools
  5. import itertools
  6. import logging
  7. import odoo
  8. import odoo.tools as tools
  9. _logger = logging.getLogger(__name__)
  10. @functools.lru_cache(maxsize=1)
  11. def _ignored_modules(cr):
  12. result = ['studio_customization']
  13. if tools.sql.column_exists(cr, 'ir_module_module', 'imported'):
  14. cr.execute('SELECT name FROM ir_module_module WHERE imported')
  15. result += [m[0] for m in cr.fetchall()]
  16. return result
  17. class Graph(dict):
  18. """ Modules dependency graph.
  19. The graph is a mapping from module name to Nodes.
  20. """
  21. def add_node(self, name, info):
  22. max_depth, father = 0, None
  23. for d in info['depends']:
  24. n = self.get(d) or Node(d, self, None) # lazy creation, do not use default value for get()
  25. if n.depth >= max_depth:
  26. father = n
  27. max_depth = n.depth
  28. if father:
  29. return father.add_child(name, info)
  30. else:
  31. return Node(name, self, info)
  32. def update_from_db(self, cr):
  33. if not len(self):
  34. return
  35. # update the graph with values from the database (if exist)
  36. ## First, we set the default values for each package in graph
  37. additional_data = {key: {'id': 0, 'state': 'uninstalled', 'dbdemo': False, 'installed_version': None} for key in self.keys()}
  38. ## Then we get the values from the database
  39. cr.execute('SELECT name, id, state, demo AS dbdemo, latest_version AS installed_version'
  40. ' FROM ir_module_module'
  41. ' WHERE name IN %s',(tuple(additional_data),)
  42. )
  43. ## and we update the default values with values from the database
  44. additional_data.update((x['name'], x) for x in cr.dictfetchall())
  45. for package in self.values():
  46. for k, v in additional_data[package.name].items():
  47. setattr(package, k, v)
  48. def add_module(self, cr, module, force=None):
  49. self.add_modules(cr, [module], force)
  50. def add_modules(self, cr, module_list, force=None):
  51. if force is None:
  52. force = []
  53. packages = []
  54. len_graph = len(self)
  55. for module in module_list:
  56. info = odoo.modules.module.get_manifest(module)
  57. if info and info['installable']:
  58. packages.append((module, info)) # TODO directly a dict, like in get_modules_with_version
  59. elif module not in _ignored_modules(cr):
  60. _logger.warning('module %s: not installable, skipped', module)
  61. dependencies = dict([(p, info['depends']) for p, info in packages])
  62. current, later = set([p for p, info in packages]), set()
  63. while packages and current > later:
  64. package, info = packages[0]
  65. deps = info['depends']
  66. # if all dependencies of 'package' are already in the graph, add 'package' in the graph
  67. if all(dep in self for dep in deps):
  68. if not package in current:
  69. packages.pop(0)
  70. continue
  71. later.clear()
  72. current.remove(package)
  73. node = self.add_node(package, info)
  74. for kind in ('init', 'demo', 'update'):
  75. if package in tools.config[kind] or 'all' in tools.config[kind] or kind in force:
  76. setattr(node, kind, True)
  77. else:
  78. later.add(package)
  79. packages.append((package, info))
  80. packages.pop(0)
  81. self.update_from_db(cr)
  82. for package in later:
  83. unmet_deps = [p for p in dependencies[package] if p not in self]
  84. _logger.info('module %s: Unmet dependencies: %s', package, ', '.join(unmet_deps))
  85. return len(self) - len_graph
  86. def __iter__(self):
  87. level = 0
  88. done = set(self.keys())
  89. while done:
  90. level_modules = sorted((name, module) for name, module in self.items() if module.depth==level)
  91. for name, module in level_modules:
  92. done.remove(name)
  93. yield module
  94. level += 1
  95. def __str__(self):
  96. return '\n'.join(str(n) for n in self if n.depth == 0)
  97. class Node(object):
  98. """ One module in the modules dependency graph.
  99. Node acts as a per-module singleton. A node is constructed via
  100. Graph.add_module() or Graph.add_modules(). Some of its fields are from
  101. ir_module_module (set by Graph.update_from_db()).
  102. """
  103. def __new__(cls, name, graph, info):
  104. if name in graph:
  105. inst = graph[name]
  106. else:
  107. inst = object.__new__(cls)
  108. graph[name] = inst
  109. return inst
  110. def __init__(self, name, graph, info):
  111. self.name = name
  112. self.graph = graph
  113. self.info = info or getattr(self, 'info', {})
  114. if not hasattr(self, 'children'):
  115. self.children = []
  116. if not hasattr(self, 'depth'):
  117. self.depth = 0
  118. @property
  119. def data(self):
  120. return self.info
  121. def add_child(self, name, info):
  122. node = Node(name, self.graph, info)
  123. node.depth = self.depth + 1
  124. if node not in self.children:
  125. self.children.append(node)
  126. for attr in ('init', 'update', 'demo'):
  127. if hasattr(self, attr):
  128. setattr(node, attr, True)
  129. self.children.sort(key=lambda x: x.name)
  130. return node
  131. def __setattr__(self, name, value):
  132. super(Node, self).__setattr__(name, value)
  133. if name in ('init', 'update', 'demo'):
  134. tools.config[name][self.name] = 1
  135. for child in self.children:
  136. setattr(child, name, value)
  137. if name == 'depth':
  138. for child in self.children:
  139. setattr(child, name, value + 1)
  140. def __iter__(self):
  141. return itertools.chain(
  142. self.children,
  143. itertools.chain.from_iterable(self.children)
  144. )
  145. def __str__(self):
  146. return self._pprint()
  147. def _pprint(self, depth=0):
  148. s = '%s\n' % self.name
  149. for c in self.children:
  150. s += '%s`-> %s' % (' ' * depth, c._pprint(depth+1))
  151. return s
  152. def should_have_demo(self):
  153. return (hasattr(self, 'demo') or (self.dbdemo and self.state != 'installed')) and all(p.dbdemo for p in self.parents)
  154. @property
  155. def parents(self):
  156. if self.depth == 0:
  157. return []
  158. return (
  159. node for node in self.graph.values()
  160. if node.depth < self.depth
  161. if self in node.children
  162. )
上海开阖软件有限公司 沪ICP备12045867号-1