108 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			Python
		
	
	
| # -*- coding: utf-8 -*-
 | |
| # Copyright 2017 Camptocamp SA
 | |
| # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html)
 | |
| 
 | |
| """
 | |
| 
 | |
| Components Builder
 | |
| ==================
 | |
| 
 | |
| Build the components at the build of a registry.
 | |
| 
 | |
| """
 | |
| import odoo
 | |
| from odoo import api, models
 | |
| from .core import (
 | |
|     _component_databases,
 | |
|     ComponentRegistry,
 | |
|     DEFAULT_CACHE_SIZE,
 | |
| )
 | |
| 
 | |
| 
 | |
| class ComponentBuilder(models.AbstractModel):
 | |
|     """ Build the component classes
 | |
| 
 | |
|     And register them in a global registry.
 | |
| 
 | |
|     Every time an Odoo registry is built, the know components are cleared and
 | |
|     rebuilt as well.  The Component classes are built using the same mechanism
 | |
|     than Odoo's Models: a final class is created, taking every Components with
 | |
|     a ``_name`` and applying Components with an ``_inherits`` upon them.
 | |
| 
 | |
|     The final Component classes are registered in global registry.
 | |
| 
 | |
|     This class is an Odoo model, allowing us to hook the build of the
 | |
|     components at the end of the Odoo's registry loading, using
 | |
|     ``_register_hook``. This method is called after all modules are loaded, so
 | |
|     we are sure that we have all the components Classes and in the correct
 | |
|     order.
 | |
| 
 | |
|     """
 | |
|     _name = 'component.builder'
 | |
|     _description = 'Component Builder'
 | |
| 
 | |
|     _components_registry_cache_size = DEFAULT_CACHE_SIZE
 | |
| 
 | |
|     @api.model_cr
 | |
|     def _register_hook(self):
 | |
|         # This method is called by Odoo when the registry is built,
 | |
|         # so in case the registry is rebuilt (cache invalidation, ...),
 | |
|         # we have to to rebuild the components. We use a new
 | |
|         # registry so we have an empty cache and we'll add components in it.
 | |
|         components_registry = self._init_global_registry()
 | |
|         self.build_registry(components_registry)
 | |
|         components_registry.ready = True
 | |
| 
 | |
|     def _init_global_registry(self):
 | |
|         components_registry = ComponentRegistry(
 | |
|             cachesize=self._components_registry_cache_size
 | |
|         )
 | |
|         _component_databases[self.env.cr.dbname] = components_registry
 | |
|         return components_registry
 | |
| 
 | |
|     def build_registry(self, components_registry, states=None,
 | |
|                        exclude_addons=None):
 | |
|         if not states:
 | |
|             states = ('installed', 'to upgrade')
 | |
|         # lookup all the installed (or about to be) addons and generate
 | |
|         # the graph, so we can load the components following the order
 | |
|         # of the addons' dependencies
 | |
|         graph = odoo.modules.graph.Graph()
 | |
|         graph.add_module(self.env.cr, 'base')
 | |
| 
 | |
|         query = (
 | |
|             "SELECT name "
 | |
|             "FROM ir_module_module "
 | |
|             "WHERE state IN %s "
 | |
|         )
 | |
|         params = [tuple(states)]
 | |
|         if exclude_addons:
 | |
|             query += " AND name NOT IN %s "
 | |
|             params.append(tuple(exclude_addons))
 | |
|         self.env.cr.execute(query, params)
 | |
| 
 | |
|         module_list = [name for (name,) in self.env.cr.fetchall()
 | |
|                        if name not in graph]
 | |
|         graph.add_modules(self.env.cr, module_list)
 | |
| 
 | |
|         for module in graph:
 | |
|             self.load_components(module.name,
 | |
|                                  components_registry=components_registry)
 | |
| 
 | |
|     def load_components(self, module, components_registry=None):
 | |
|         """ Build every component known by MetaComponent for an odoo module
 | |
| 
 | |
|         The final component (composed by all the Component classes in this
 | |
|         module) will be pushed into the registry.
 | |
| 
 | |
|         :param module: the name of the addon for which we want to load
 | |
|                        the components
 | |
|         :type module: str | unicode
 | |
|         :param registry: the registry in which we want to put the Component
 | |
|         :type registry: :py:class:`~.core.ComponentRegistry`
 | |
|         """
 | |
|         components_registry = (
 | |
|             components_registry or
 | |
|             _component_databases[self.env.cr.dbname])
 | |
|         components_registry.load_components(module)
 |