Browse Source
Merge pull request #876 from hbrunn/8.0-base_manifest_extension
Merge pull request #876 from hbrunn/8.0-base_manifest_extension
[ADD] base_manifest_extensionpull/940/head
Dave Lasley
7 years ago
committed by
GitHub
7 changed files with 213 additions and 0 deletions
-
65base_manifest_extension/README.rst
-
4base_manifest_extension/__init__.py
-
15base_manifest_extension/__openerp__.py
-
94base_manifest_extension/hooks.py
-
BINbase_manifest_extension/static/description/icon.png
-
4base_manifest_extension/tests/__init__.py
-
31base_manifest_extension/tests/test_base_manifest_extension.py
@ -0,0 +1,65 @@ |
|||||
|
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg |
||||
|
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html |
||||
|
:alt: License: AGPL-3 |
||||
|
|
||||
|
========================= |
||||
|
Extra options in manifest |
||||
|
========================= |
||||
|
|
||||
|
This is a technical module to allow developers to make use of a couple of new keys in module manifests. |
||||
|
|
||||
|
The following new keys are available currently: |
||||
|
|
||||
|
depends_if_installed |
||||
|
Your module will depend on modules listed here, but only if those modules are already installed. This is useful if your module is supposed to override behavior of a third module if present, but it's not a hard dependency of your module. Think of auth_* and their interactions. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
* depend on this module and use the keys described above |
||||
|
|
||||
|
Roadmap |
||||
|
======= |
||||
|
|
||||
|
* ``breaks`` to mark some modules as being incompatible. This also could be versioned (``'breaks': ['my_module<<0.4.2']``) |
||||
|
* ``demo_if_installed``, ``data_if_installed``, ``qweb_if_installed`` being dicts with module names as keys and a list of files as values in order to pull some data files in case some other module is installed |
||||
|
* ``rdepends_if_installed`` to make another installed module depend on the current module |
||||
|
* ``_if_module`` on models to load certain models only if the appropriate module is installed |
||||
|
|
||||
|
Bug Tracker |
||||
|
=========== |
||||
|
|
||||
|
Bugs are tracked on `GitHub Issues |
||||
|
<https://github.com/OCA/server-tools/issues>`_. In case of trouble, please |
||||
|
check there if your issue has already been reported. If you spotted it first, |
||||
|
help us smashing it by providing a detailed and welcomed feedback. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Images |
||||
|
------ |
||||
|
|
||||
|
* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_. |
||||
|
|
||||
|
Contributors |
||||
|
------------ |
||||
|
|
||||
|
* Holger Brunn <hbrunn@therp.nl> |
||||
|
|
||||
|
Do not contact contributors directly about help with questions or problems concerning this addon, but use the `community mailing list <mailto:community@mail.odoo.com>`_ or the `appropriate specialized mailinglist <https://odoo-community.org/groups>`_ for help, and the bug tracker linked in `Bug Tracker`_ above for technical issues. |
||||
|
|
||||
|
Maintainer |
||||
|
---------- |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
OCA, or the Odoo Community Association, is a nonprofit organization whose |
||||
|
mission is to support the collaborative development of Odoo features and |
||||
|
promote its widespread use. |
||||
|
|
||||
|
To contribute to this module, please visit https://odoo-community.org. |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from .hooks import post_load_hook |
@ -0,0 +1,15 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
{ |
||||
|
"name": "More options in manifest", |
||||
|
"version": "8.0.1.0.0", |
||||
|
"author": "Therp BV,Odoo Community Association (OCA)", |
||||
|
"license": "AGPL-3", |
||||
|
"category": "Hidden/Dependency", |
||||
|
"summary": "Adds some useful keys to manifest files", |
||||
|
"depends": [ |
||||
|
'base', |
||||
|
], |
||||
|
"post_load": 'post_load_hook', |
||||
|
} |
@ -0,0 +1,94 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
import inspect |
||||
|
from openerp.sql_db import Cursor |
||||
|
from openerp.modules import module |
||||
|
from openerp.modules.graph import Graph |
||||
|
original = module.load_information_from_description_file |
||||
|
|
||||
|
|
||||
|
def load_information_from_description_file(module, mod_path=None): |
||||
|
result = original(module, mod_path=mod_path) |
||||
|
# add the keys you want to react on here |
||||
|
if result.get('depends_if_installed'): |
||||
|
cr = _get_cr() |
||||
|
if cr: |
||||
|
_handle_depends_if_installed(cr, result) |
||||
|
|
||||
|
return result |
||||
|
|
||||
|
|
||||
|
def _handle_depends_if_installed(cr, manifest): |
||||
|
if not manifest.get('depends_if_installed'): |
||||
|
return |
||||
|
cr.execute( |
||||
|
'select name from ir_module_module ' |
||||
|
'where state in %s and name in %s', |
||||
|
( |
||||
|
tuple(['installed', 'to install', 'to upgrade']), |
||||
|
tuple(manifest['depends_if_installed']), |
||||
|
), |
||||
|
) |
||||
|
manifest.pop('depends_if_installed') |
||||
|
depends = manifest.setdefault('depends', []) |
||||
|
depends.extend(module for module, in cr.fetchall()) |
||||
|
|
||||
|
|
||||
|
def _get_cr(): |
||||
|
cr = None |
||||
|
for frame, filename, lineno, funcname, line, index in inspect.stack(): |
||||
|
# walk up the stack until we've found a cursor |
||||
|
if 'cr' in frame.f_locals and isinstance(frame.f_locals['cr'], Cursor): |
||||
|
cr = frame.f_locals['cr'] |
||||
|
break |
||||
|
return cr |
||||
|
|
||||
|
|
||||
|
def _get_graph(): |
||||
|
graph = None |
||||
|
for frame, filename, lineno, funcname, line, index in inspect.stack(): |
||||
|
# walk up the stack until we've found a graph |
||||
|
if 'graph' in frame.f_locals and isinstance( |
||||
|
frame.f_locals['graph'], Graph |
||||
|
): |
||||
|
graph = frame.f_locals['graph'] |
||||
|
break |
||||
|
return graph |
||||
|
|
||||
|
|
||||
|
def post_load_hook(): |
||||
|
cr = _get_cr() |
||||
|
if not cr: |
||||
|
return |
||||
|
cr.execute( |
||||
|
'select id from ir_module_module where name=%s and state in %s', |
||||
|
( |
||||
|
'base_manifest_extension', |
||||
|
tuple(['installed', 'to install', 'to upgrade']), |
||||
|
), |
||||
|
) |
||||
|
# do nothing if we're not installed |
||||
|
if not cr.rowcount: |
||||
|
return |
||||
|
|
||||
|
module.load_information_from_description_file =\ |
||||
|
load_information_from_description_file |
||||
|
|
||||
|
# here stuff can become tricky: On the python level, modules |
||||
|
# are not loaded in dependency order. This means that there might |
||||
|
# be modules loaded depending on us before we could patch the function |
||||
|
# above. So we reload the module graph for all modules coming after us |
||||
|
|
||||
|
graph = _get_graph() |
||||
|
if not graph: |
||||
|
return |
||||
|
|
||||
|
this = graph['base_manifest_extension'] |
||||
|
to_reload = [] |
||||
|
for node in graph.itervalues(): |
||||
|
if node.depth > this.depth: |
||||
|
to_reload.append(node.name) |
||||
|
for module_name in to_reload: |
||||
|
del graph[module_name] |
||||
|
graph.add_modules(cr, to_reload) |
After Width: 128 | Height: 128 | Size: 9.2 KiB |
@ -0,0 +1,4 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
from . import test_base_manifest_extension |
@ -0,0 +1,31 @@ |
|||||
|
# -*- coding: utf-8 -*- |
||||
|
# © 2017 Therp BV <http://therp.nl> |
||||
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). |
||||
|
import os |
||||
|
import tempfile |
||||
|
from openerp.tests.common import TransactionCase |
||||
|
from openerp.modules.module import load_information_from_description_file,\ |
||||
|
get_module_path, MANIFEST |
||||
|
|
||||
|
|
||||
|
class TestBaseManifestExtension(TransactionCase): |
||||
|
def test_base_manifest_extension(self): |
||||
|
# write a test manifest |
||||
|
module_path = tempfile.mkdtemp(dir=os.path.join( |
||||
|
get_module_path('base_manifest_extension'), 'static' |
||||
|
)) |
||||
|
with open(os.path.join(module_path, MANIFEST), 'w') as manifest: |
||||
|
manifest.write(repr({ |
||||
|
'depends_if_installed': [ |
||||
|
'base_manifest_extension', |
||||
|
'not installed', |
||||
|
], |
||||
|
})) |
||||
|
# parse it |
||||
|
parsed = load_information_from_description_file( |
||||
|
# this name won't really be used, but avoids a warning |
||||
|
'base', mod_path=module_path, |
||||
|
) |
||||
|
self.assertIn('base_manifest_extension', parsed['depends']) |
||||
|
self.assertNotIn('not installed', parsed['depends']) |
||||
|
self.assertNotIn('depends_if_installed', parsed) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue