Browse Source
Merge pull request #1382 from acsone/12.0-mig-module_auto_update
Merge pull request #1382 from acsone/12.0-mig-module_auto_update
[MIG][12.0] module auto update from 11 to 12pull/1376/merge
Stéphane Bidoul (ACSONE)
6 years ago
committed by
GitHub
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1890 additions and 21 deletions
-
25.travis.yml
-
2README.md
-
144module_auto_update/README.rst
-
4module_auto_update/__init__.py
-
23module_auto_update/__manifest__.py
-
44module_auto_update/addon_hash.py
-
11module_auto_update/hooks.py
-
46module_auto_update/i18n/ca.po
-
59module_auto_update/i18n/cs_CZ.po
-
47module_auto_update/i18n/de.po
-
56module_auto_update/i18n/es.po
-
47module_auto_update/i18n/es_MX.po
-
58module_auto_update/i18n/fr.po
-
47module_auto_update/i18n/hr.po
-
46module_auto_update/i18n/it.po
-
42module_auto_update/i18n/module_auto_update.pot
-
47module_auto_update/i18n/nl_NL.po
-
47module_auto_update/i18n/pt_BR.po
-
47module_auto_update/i18n/sl.po
-
46module_auto_update/i18n/tr.po
-
3module_auto_update/models/__init__.py
-
174module_auto_update/models/module.py
-
9module_auto_update/readme/CONFIGURE.rst
-
4module_auto_update/readme/CONTRIBUTORS.rst
-
4module_auto_update/readme/DESCRIPTION.rst
-
18module_auto_update/readme/USAGE.rst
-
483module_auto_update/static/description/index.html
-
4module_auto_update/tests/__init__.py
-
1module_auto_update/tests/sample_module/README.rst
-
1module_auto_update/tests/sample_module/data/f1.xml
-
1module_auto_update/tests/sample_module/data/f2.xml
-
1module_auto_update/tests/sample_module/i18n/en.po
-
1module_auto_update/tests/sample_module/i18n/en_US.po
-
1module_auto_update/tests/sample_module/i18n/fr.po
-
1module_auto_update/tests/sample_module/i18n/fr_BE.po
-
1module_auto_update/tests/sample_module/i18n/test.pot
-
1module_auto_update/tests/sample_module/i18n_extra/en.po
-
1module_auto_update/tests/sample_module/i18n_extra/fr.po
-
1module_auto_update/tests/sample_module/i18n_extra/nl_NL.po
-
1module_auto_update/tests/sample_module/models/stuff.py
-
BINmodule_auto_update/tests/sample_module/models/stuff.pyc
-
BINmodule_auto_update/tests/sample_module/models/stuff.pyo
-
1module_auto_update/tests/sample_module/static/src/some.js
-
67module_auto_update/tests/test_addon_hash.py
-
237module_auto_update/tests/test_module.py
-
1setup/module_auto_update/odoo/addons/module_auto_update
-
6setup/module_auto_update/setup.py
@ -0,0 +1,144 @@ |
|||||
|
================== |
||||
|
Module Auto Update |
||||
|
================== |
||||
|
|
||||
|
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
|
||||
|
.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png |
||||
|
:target: https://odoo-community.org/page/development-status |
||||
|
:alt: Production/Stable |
||||
|
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png |
||||
|
:target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html |
||||
|
:alt: License: LGPL-3 |
||||
|
.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github |
||||
|
:target: https://github.com/OCA/server-tools/tree/11.0/module_auto_update |
||||
|
:alt: OCA/server-tools |
||||
|
.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png |
||||
|
:target: https://translation.odoo-community.org/projects/server-tools-11-0/server-tools-11-0-module_auto_update |
||||
|
:alt: Translate me on Weblate |
||||
|
.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png |
||||
|
:target: https://runbot.odoo-community.org/runbot/149/11.0 |
||||
|
:alt: Try me on Runbot |
||||
|
|
||||
|
|badge1| |badge2| |badge3| |badge4| |badge5| |
||||
|
|
||||
|
This addon provides mechanisms to compute sha1 hashes of installed addons, |
||||
|
and save them in the database. It also provides a method that exploits these |
||||
|
mechanisms to update a database by upgrading only the modules for which the |
||||
|
hash has changed since the last successful upgrade. |
||||
|
|
||||
|
**Table of contents** |
||||
|
|
||||
|
.. contents:: |
||||
|
:local: |
||||
|
|
||||
|
Configuration |
||||
|
============= |
||||
|
|
||||
|
This module supports the following system parameters: |
||||
|
|
||||
|
* ``module_auto_update.exclude_patterns``: comma-separated list of file |
||||
|
name patterns to ignore when computing addon checksums. Defaults to |
||||
|
``*.pyc,*.pyo,i18n/*.pot,i18n_extra/*.pot,static/*``. |
||||
|
Filename patterns must be compatible with the python ``fnmatch`` function. |
||||
|
|
||||
|
In addition to the above pattern, .po files corresponding to languages that |
||||
|
are not installed in the Odoo database are ignored when computing checksums. |
||||
|
|
||||
|
Usage |
||||
|
===== |
||||
|
|
||||
|
The main method provided by this module is ``upgrade_changed_checksum`` |
||||
|
on ``ir.module.module``. It runs a database upgrade for all installed |
||||
|
modules for which the hash has changed since the last successful |
||||
|
run of this method. On success it saves the hashes in the database. |
||||
|
|
||||
|
The first time this method is invoked after installing the module, it |
||||
|
runs an upgrade of all modules, because it has not saved the hashes yet. |
||||
|
This is by design, priviledging safety. Should this be an issue, |
||||
|
the method ``_save_installed_checksums`` can be invoked in a situation |
||||
|
where one is sure all modules on disk are installed and up-to-date in the |
||||
|
database. |
||||
|
|
||||
|
An easy way to invoke this upgrade mechanism is by issuing the following |
||||
|
in an Odoo shell session:: |
||||
|
|
||||
|
env['ir.module.module'].upgrade_changed_checksum() |
||||
|
|
||||
|
Known issues / Roadmap |
||||
|
====================== |
||||
|
|
||||
|
* Since version ``2.0.0``, some features have been deprecated. |
||||
|
When you upgrade from previous versions, these features will be kept for |
||||
|
backwards compatibility, but beware! They are buggy! |
||||
|
|
||||
|
If you install this addon from scratch, these features are disabled by |
||||
|
default. |
||||
|
|
||||
|
To force enabling or disabling the deprecated features, set a configuration |
||||
|
parameter called ``module_auto_update.enable_deprecated`` to either ``1`` |
||||
|
or ``0``. It is recommended that you disable them. |
||||
|
|
||||
|
Keep in mind that from this version, all upgrades are assumed to run in a |
||||
|
separate odoo instance, dedicated exclusively to upgrade Odoo. |
||||
|
|
||||
|
* When migrating the addon to new versions, the deprecated features should be |
||||
|
removed. To make it simple all deprecated features are found in files |
||||
|
suffixed with ``_deprecated``. |
||||
|
|
||||
|
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 <https://github.com/OCA/server-tools/issues/new?body=module:%20module_auto_update%0Aversion:%2011.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. |
||||
|
|
||||
|
Do not contact contributors directly about support or help with technical issues. |
||||
|
|
||||
|
Credits |
||||
|
======= |
||||
|
|
||||
|
Authors |
||||
|
~~~~~~~ |
||||
|
|
||||
|
* LasLabs |
||||
|
* Juan José Scarafía |
||||
|
* Tecnativa |
||||
|
* ACSONE SA/NV |
||||
|
|
||||
|
Contributors |
||||
|
~~~~~~~~~~~~ |
||||
|
|
||||
|
* Brent Hughes <brent.hughes@laslabs.com> |
||||
|
* Juan José Scarafía <jjs@adhoc.com.ar> |
||||
|
* Jairo Llopis <jairo.llopis@tecnativa.com> |
||||
|
* Stéphane Bidoul <stephane.bidoul@acsone.eu> (https://acsone.eu) |
||||
|
|
||||
|
Maintainers |
||||
|
~~~~~~~~~~~ |
||||
|
|
||||
|
This module is maintained by the OCA. |
||||
|
|
||||
|
.. image:: https://odoo-community.org/logo.png |
||||
|
:alt: Odoo Community Association |
||||
|
:target: https://odoo-community.org |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
.. |maintainer-sbidoul| image:: https://github.com/sbidoul.png?size=40px |
||||
|
:target: https://github.com/sbidoul |
||||
|
:alt: sbidoul |
||||
|
|
||||
|
Current `maintainer <https://odoo-community.org/page/maintainer-role>`__: |
||||
|
|
||||
|
|maintainer-sbidoul| |
||||
|
|
||||
|
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/11.0/module_auto_update>`_ project on GitHub. |
||||
|
|
||||
|
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. |
@ -0,0 +1,4 @@ |
|||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
from . import models |
||||
|
from .hooks import uninstall_hook |
@ -0,0 +1,23 @@ |
|||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
{ |
||||
|
'name': 'Module Auto Update', |
||||
|
'summary': 'Automatically update Odoo modules', |
||||
|
'version': '12.0.2.0.4', |
||||
|
'category': 'Extra Tools', |
||||
|
'website': 'https://github.com/OCA/server-tools', |
||||
|
'author': 'LasLabs, ' |
||||
|
'Juan José Scarafía, ' |
||||
|
'Tecnativa, ' |
||||
|
'ACSONE SA/NV, ' |
||||
|
'Odoo Community Association (OCA)', |
||||
|
'license': 'LGPL-3', |
||||
|
'installable': True, |
||||
|
'uninstall_hook': 'uninstall_hook', |
||||
|
'depends': [ |
||||
|
'base', |
||||
|
], |
||||
|
'development_status': 'Production/Stable', |
||||
|
'maintainers': ['sbidoul'], |
||||
|
} |
@ -0,0 +1,44 @@ |
|||||
|
# Copyright 2018 ACSONE SA/NV. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
from fnmatch import fnmatch |
||||
|
import hashlib |
||||
|
import os |
||||
|
|
||||
|
|
||||
|
def _fnmatch(filename, patterns): |
||||
|
for pattern in patterns: |
||||
|
if fnmatch(filename, pattern): |
||||
|
return True |
||||
|
return False |
||||
|
|
||||
|
|
||||
|
def _walk(top, exclude_patterns, keep_langs): |
||||
|
keep_langs = {l.split('_')[0] for l in keep_langs} |
||||
|
for dirpath, dirnames, filenames in os.walk(top): |
||||
|
dirnames.sort() |
||||
|
reldir = os.path.relpath(dirpath, top) |
||||
|
if reldir == '.': |
||||
|
reldir = '' |
||||
|
for filename in sorted(filenames): |
||||
|
filepath = os.path.join(reldir, filename) |
||||
|
if _fnmatch(filepath, exclude_patterns): |
||||
|
continue |
||||
|
if keep_langs and reldir in {'i18n', 'i18n_extra'}: |
||||
|
basename, ext = os.path.splitext(filename) |
||||
|
if ext == '.po': |
||||
|
if basename.split('_')[0] not in keep_langs: |
||||
|
continue |
||||
|
yield filepath |
||||
|
|
||||
|
|
||||
|
def addon_hash(top, exclude_patterns, keep_langs): |
||||
|
"""Compute a sha1 digest of file contents.""" |
||||
|
m = hashlib.sha1() |
||||
|
for filepath in _walk(top, exclude_patterns, keep_langs): |
||||
|
# hash filename so empty files influence the hash |
||||
|
m.update(filepath.encode('utf-8')) |
||||
|
# hash file content |
||||
|
with open(os.path.join(top, filepath), 'rb') as f: |
||||
|
m.update(f.read()) |
||||
|
return m.hexdigest() |
@ -0,0 +1,11 @@ |
|||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
from odoo import SUPERUSER_ID, api |
||||
|
|
||||
|
from .models.module import PARAM_INSTALLED_CHECKSUMS |
||||
|
|
||||
|
|
||||
|
def uninstall_hook(cr, registry): |
||||
|
env = api.Environment(cr, SUPERUSER_ID, {}) |
||||
|
env["ir.config_parameter"].set_param(PARAM_INSTALLED_CHECKSUMS, False) |
@ -0,0 +1,46 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2017\n" |
||||
|
"Language-Team: Catalan (https://www.transifex.com/oca/teams/23907/ca/)\n" |
||||
|
"Language: ca\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Mòdul" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
@ -0,0 +1,59 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# Lukáš Spurný <lukasspurny8@gmail.com>, 2018 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 11.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2018-03-03 10:08+0000\n" |
||||
|
"PO-Revision-Date: 2018-03-03 10:08+0000\n" |
||||
|
"Last-Translator: Lukáš Spurný <lukasspurny8@gmail.com>, 2018\n" |
||||
|
"Language-Team: Czech (Czech Republic) (https://www.transifex.com/oca/" |
||||
|
"teams/23907/cs_CZ/)\n" |
||||
|
"Language: cs_CZ\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "Kontrolní součet Dir" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "Kontrolní součet je nainstalován" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Modul" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "Aktualizace modulů" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "Provést aktualizaci modulů" |
||||
|
|
||||
|
#~ msgid "Modules" |
||||
|
#~ msgstr "Moduly" |
||||
|
|
||||
|
#~ msgid "Open Updates and Update Apps List Server Action" |
||||
|
#~ msgstr "Otevřít aktualizaci a aktualizovat seznam serverových akcí" |
||||
|
|
||||
|
#~ msgid "Scheduled Upgrades" |
||||
|
#~ msgstr "Plánované aktualizace" |
||||
|
|
||||
|
#~ msgid "Updates" |
||||
|
#~ msgstr "Aktualizace" |
@ -0,0 +1,47 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# Niki Waibel <niki.waibel@gmail.com>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: Niki Waibel <niki.waibel@gmail.com>, 2017\n" |
||||
|
"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n" |
||||
|
"Language: de\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Modul" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "Modul aktualisieren" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
#, fuzzy |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "Modul aktualisieren" |
@ -0,0 +1,56 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2018 |
||||
|
# enjolras <yo@miguelrevilla.com>, 2018 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 11.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2018-03-03 10:08+0000\n" |
||||
|
"PO-Revision-Date: 2018-03-03 10:08+0000\n" |
||||
|
"Last-Translator: enjolras <yo@miguelrevilla.com>, 2018\n" |
||||
|
"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" |
||||
|
"Language: es\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Módulo" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "Actualización de módulo" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
||||
|
|
||||
|
#~ msgid "Modules" |
||||
|
#~ msgstr "Módulos" |
||||
|
|
||||
|
#~ msgid "Scheduled Upgrades" |
||||
|
#~ msgstr "Actualizaciones programadas" |
||||
|
|
||||
|
#~ msgid "Updates" |
||||
|
#~ msgstr "Actualizaciones" |
@ -0,0 +1,47 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2017\n" |
||||
|
"Language-Team: Spanish (Mexico) (https://www.transifex.com/oca/teams/23907/" |
||||
|
"es_MX/)\n" |
||||
|
"Language: es_MX\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Módulo" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
@ -0,0 +1,58 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# Nicolas JEUDY <njeudy@panda-chi.io>, 2018 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 11.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2018-03-03 10:08+0000\n" |
||||
|
"PO-Revision-Date: 2018-03-03 10:08+0000\n" |
||||
|
"Last-Translator: Nicolas JEUDY <njeudy@panda-chi.io>, 2018\n" |
||||
|
"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" |
||||
|
"Language: fr\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "Somme de contrôle du dossier" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "Somme de contrôle installée" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Module" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "Mise à niveau du module" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "Appliquer les mise à jour de modules" |
||||
|
|
||||
|
#~ msgid "Modules" |
||||
|
#~ msgstr "Modules" |
||||
|
|
||||
|
#~ msgid "Open Updates and Update Apps List Server Action" |
||||
|
#~ msgstr "Afficher les mises à jour" |
||||
|
|
||||
|
#~ msgid "Scheduled Upgrades" |
||||
|
#~ msgstr "Planifier les mises à jour" |
||||
|
|
||||
|
#~ msgid "Updates" |
||||
|
#~ msgstr "Mises à jour" |
@ -0,0 +1,47 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# Bole <bole@dajmi5.com>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: Bole <bole@dajmi5.com>, 2017\n" |
||||
|
"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n" |
||||
|
"Language: hr\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" |
||||
|
"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Modul" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
@ -0,0 +1,46 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2017\n" |
||||
|
"Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n" |
||||
|
"Language: it\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Modulo" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
@ -0,0 +1,42 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 11.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"Last-Translator: <>\n" |
||||
|
"Language-Team: \n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: \n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
||||
|
|
@ -0,0 +1,47 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# Peter Hageman <hageman.p@gmail.com>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: Peter Hageman <hageman.p@gmail.com>, 2017\n" |
||||
|
"Language-Team: Dutch (Netherlands) (https://www.transifex.com/oca/" |
||||
|
"teams/23907/nl_NL/)\n" |
||||
|
"Language: nl_NL\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Module" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
@ -0,0 +1,47 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2017\n" |
||||
|
"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/" |
||||
|
"teams/23907/pt_BR/)\n" |
||||
|
"Language: pt_BR\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Módulo" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
@ -0,0 +1,47 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2017\n" |
||||
|
"Language-Team: Slovenian (https://www.transifex.com/oca/teams/23907/sl/)\n" |
||||
|
"Language: sl\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" |
||||
|
"%100==4 ? 2 : 3);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Modul" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
@ -0,0 +1,46 @@ |
|||||
|
# Translation of Odoo Server. |
||||
|
# This file contains the translation of the following modules: |
||||
|
# * module_auto_update |
||||
|
# |
||||
|
# Translators: |
||||
|
# OCA Transbot <transbot@odoo-community.org>, 2017 |
||||
|
msgid "" |
||||
|
msgstr "" |
||||
|
"Project-Id-Version: Odoo Server 10.0\n" |
||||
|
"Report-Msgid-Bugs-To: \n" |
||||
|
"POT-Creation-Date: 2017-07-21 02:43+0000\n" |
||||
|
"PO-Revision-Date: 2017-07-21 02:43+0000\n" |
||||
|
"Last-Translator: OCA Transbot <transbot@odoo-community.org>, 2017\n" |
||||
|
"Language-Team: Turkish (https://www.transifex.com/oca/teams/23907/tr/)\n" |
||||
|
"Language: tr\n" |
||||
|
"MIME-Version: 1.0\n" |
||||
|
"Content-Type: text/plain; charset=UTF-8\n" |
||||
|
"Content-Transfer-Encoding: \n" |
||||
|
"Plural-Forms: nplurals=2; plural=(n > 1);\n" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_dir |
||||
|
msgid "Checksum Dir" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module_checksum_installed |
||||
|
msgid "Checksum Installed" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_ir_module_module |
||||
|
msgid "Module" |
||||
|
msgstr "Modül" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.model,name:module_auto_update.model_base_module_upgrade |
||||
|
msgid "Module Upgrade" |
||||
|
msgstr "" |
||||
|
|
||||
|
#. module: module_auto_update |
||||
|
#: model:ir.actions.server,name:module_auto_update.module_check_upgrades_cron_ir_actions_server |
||||
|
#: model:ir.cron,cron_name:module_auto_update.module_check_upgrades_cron |
||||
|
#: model:ir.cron,name:module_auto_update.module_check_upgrades_cron |
||||
|
msgid "Perform Module Upgrades" |
||||
|
msgstr "" |
@ -0,0 +1,3 @@ |
|||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
from . import module |
@ -0,0 +1,174 @@ |
|||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# Copyright 2018 ACSONE SA/NV. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
import json |
||||
|
import logging |
||||
|
import os |
||||
|
|
||||
|
from odoo import api, exceptions, models, tools |
||||
|
from odoo.modules.module import get_module_path |
||||
|
|
||||
|
from ..addon_hash import addon_hash |
||||
|
|
||||
|
PARAM_INSTALLED_CHECKSUMS = \ |
||||
|
'module_auto_update.installed_checksums' |
||||
|
PARAM_EXCLUDE_PATTERNS = \ |
||||
|
'module_auto_update.exclude_patterns' |
||||
|
DEFAULT_EXCLUDE_PATTERNS = \ |
||||
|
'*.pyc,*.pyo,i18n/*.pot,i18n_extra/*.pot,static/*' |
||||
|
|
||||
|
_logger = logging.getLogger(__name__) |
||||
|
|
||||
|
|
||||
|
class FailedUpgradeError(exceptions.UserError): |
||||
|
pass |
||||
|
|
||||
|
|
||||
|
class IncompleteUpgradeError(exceptions.UserError): |
||||
|
pass |
||||
|
|
||||
|
|
||||
|
def ensure_module_state(env, modules, state): |
||||
|
# read module states, bypassing any Odoo cache |
||||
|
if not modules: |
||||
|
return |
||||
|
env.cr.execute( |
||||
|
"SELECT name FROM ir_module_module " |
||||
|
"WHERE id IN %s AND state != %s", |
||||
|
(tuple(modules.ids), state), |
||||
|
) |
||||
|
names = [r[0] for r in env.cr.fetchall()] |
||||
|
if names: |
||||
|
raise FailedUpgradeError( |
||||
|
"The following modules should be in state '%s' " |
||||
|
"at this stage: %s. Bailing out for safety." % |
||||
|
(state, ','.join(names), ), |
||||
|
) |
||||
|
|
||||
|
|
||||
|
class Module(models.Model): |
||||
|
_inherit = 'ir.module.module' |
||||
|
|
||||
|
@api.multi |
||||
|
def _get_checksum_dir(self): |
||||
|
self.ensure_one() |
||||
|
|
||||
|
exclude_patterns = self.env["ir.config_parameter"].get_param( |
||||
|
PARAM_EXCLUDE_PATTERNS, |
||||
|
DEFAULT_EXCLUDE_PATTERNS, |
||||
|
) |
||||
|
exclude_patterns = [p.strip() for p in exclude_patterns.split(',')] |
||||
|
keep_langs = self.env['res.lang'].search([]).mapped('code') |
||||
|
|
||||
|
module_path = get_module_path(self.name) |
||||
|
if module_path and os.path.isdir(module_path): |
||||
|
checksum_dir = addon_hash( |
||||
|
module_path, |
||||
|
exclude_patterns, |
||||
|
keep_langs, |
||||
|
) |
||||
|
else: |
||||
|
checksum_dir = False |
||||
|
|
||||
|
return checksum_dir |
||||
|
|
||||
|
@api.model |
||||
|
def _get_saved_checksums(self): |
||||
|
Icp = self.env['ir.config_parameter'] |
||||
|
return json.loads(Icp.get_param(PARAM_INSTALLED_CHECKSUMS, '{}')) |
||||
|
|
||||
|
@api.model |
||||
|
def _save_checksums(self, checksums): |
||||
|
Icp = self.env['ir.config_parameter'] |
||||
|
Icp.set_param(PARAM_INSTALLED_CHECKSUMS, json.dumps(checksums)) |
||||
|
|
||||
|
@api.model |
||||
|
def _save_installed_checksums(self): |
||||
|
checksums = {} |
||||
|
installed_modules = self.search([('state', '=', 'installed')]) |
||||
|
for module in installed_modules: |
||||
|
checksums[module.name] = module._get_checksum_dir() |
||||
|
self._save_checksums(checksums) |
||||
|
|
||||
|
@api.model |
||||
|
def _get_modules_partially_installed(self): |
||||
|
return self.search([ |
||||
|
('state', 'in', ('to install', 'to remove', 'to upgrade')), |
||||
|
]) |
||||
|
|
||||
|
@api.model |
||||
|
def _get_modules_with_changed_checksum(self): |
||||
|
saved_checksums = self._get_saved_checksums() |
||||
|
installed_modules = self.search([('state', '=', 'installed')]) |
||||
|
return installed_modules.filtered( |
||||
|
lambda r: r._get_checksum_dir() != saved_checksums.get(r.name), |
||||
|
) |
||||
|
|
||||
|
@api.model |
||||
|
def upgrade_changed_checksum(self, overwrite_existing_translations=False): |
||||
|
"""Run an upgrade of the database, upgrading only changed modules. |
||||
|
|
||||
|
Installed modules for which the checksum has changed since the |
||||
|
last successful run of this method are marked "to upgrade", |
||||
|
then the normal Odoo scheduled upgrade process |
||||
|
is launched. |
||||
|
|
||||
|
If there is no module with a changed checksum, and no module in state |
||||
|
other than installed, uninstalled, uninstallable, this method does |
||||
|
nothing, otherwise the normal Odoo upgrade process is launched. |
||||
|
|
||||
|
After a successful upgrade, the checksums of installed modules are |
||||
|
saved. |
||||
|
|
||||
|
In case of error during the upgrade, an exception is raised. |
||||
|
If any module remains to upgrade or to uninstall after the upgrade |
||||
|
process, an exception is raised as well. |
||||
|
|
||||
|
Note: this method commits the current transaction at each important |
||||
|
step, it is therefore not intended to be run as part of a |
||||
|
larger transaction. |
||||
|
""" |
||||
|
_logger.info( |
||||
|
"Checksum upgrade starting (i18n-overwrite=%s)...", |
||||
|
overwrite_existing_translations |
||||
|
) |
||||
|
|
||||
|
tools.config['overwrite_existing_translations'] = \ |
||||
|
overwrite_existing_translations |
||||
|
|
||||
|
_logger.info("Updating modules list...") |
||||
|
self.update_list() |
||||
|
changed_modules = self._get_modules_with_changed_checksum() |
||||
|
if not changed_modules and not self._get_modules_partially_installed(): |
||||
|
_logger.info("No checksum change detected in installed modules " |
||||
|
"and all modules installed, nothing to do.") |
||||
|
return |
||||
|
_logger.info("Marking the following modules to upgrade, " |
||||
|
"for their checksums changed: %s...", |
||||
|
','.join(changed_modules.mapped('name'))) |
||||
|
changed_modules.button_upgrade() |
||||
|
self.env.cr.commit() # pylint: disable=invalid-commit |
||||
|
# in rare situations, button_upgrade may fail without |
||||
|
# exception, this would lead to corruption because |
||||
|
# no upgrade would be performed and save_installed_checksums |
||||
|
# would update cheksums for modules that have not been upgraded |
||||
|
ensure_module_state(self.env, changed_modules, 'to upgrade') |
||||
|
|
||||
|
_logger.info("Upgrading...") |
||||
|
self.env['base.module.upgrade'].upgrade_module() |
||||
|
self.env.cr.commit() # pylint: disable=invalid-commit |
||||
|
|
||||
|
_logger.info("Upgrade successful, updating checksums...") |
||||
|
self._save_installed_checksums() |
||||
|
self.env.cr.commit() # pylint: disable=invalid-commit |
||||
|
|
||||
|
partial_modules = self._get_modules_partially_installed() |
||||
|
if partial_modules: |
||||
|
raise IncompleteUpgradeError( |
||||
|
"Checksum upgrade successful " |
||||
|
"but incomplete for the following modules: %s" % |
||||
|
','.join(partial_modules.mapped('name')) |
||||
|
) |
||||
|
|
||||
|
_logger.info("Checksum upgrade complete.") |
@ -0,0 +1,9 @@ |
|||||
|
This module supports the following system parameters: |
||||
|
|
||||
|
* ``module_auto_update.exclude_patterns``: comma-separated list of file |
||||
|
name patterns to ignore when computing addon checksums. Defaults to |
||||
|
``*.pyc,*.pyo,i18n/*.pot,i18n_extra/*.pot,static/*``. |
||||
|
Filename patterns must be compatible with the python ``fnmatch`` function. |
||||
|
|
||||
|
In addition to the above pattern, .po files corresponding to languages that |
||||
|
are not installed in the Odoo database are ignored when computing checksums. |
@ -0,0 +1,4 @@ |
|||||
|
* Brent Hughes <brent.hughes@laslabs.com> |
||||
|
* Juan José Scarafía <jjs@adhoc.com.ar> |
||||
|
* Jairo Llopis <jairo.llopis@tecnativa.com> |
||||
|
* Stéphane Bidoul <stephane.bidoul@acsone.eu> (https://acsone.eu) |
@ -0,0 +1,4 @@ |
|||||
|
This addon provides mechanisms to compute sha1 hashes of installed addons, |
||||
|
and save them in the database. It also provides a method that exploits these |
||||
|
mechanisms to update a database by upgrading only the modules for which the |
||||
|
hash has changed since the last successful upgrade. |
@ -0,0 +1,18 @@ |
|||||
|
The main method provided by this module is ``upgrade_changed_checksum`` |
||||
|
on ``ir.module.module``. It runs a database upgrade for all installed |
||||
|
modules for which the hash has changed since the last successful |
||||
|
run of this method. On success it saves the hashes in the database. |
||||
|
|
||||
|
The first time this method is invoked after installing the module, it |
||||
|
runs an upgrade of all modules, because it has not saved the hashes yet. |
||||
|
This is by design, priviledging safety. Should this be an issue, |
||||
|
the method ``_save_installed_checksums`` can be invoked in a situation |
||||
|
where one is sure all modules on disk are installed and up-to-date in the |
||||
|
database. |
||||
|
|
||||
|
An easy way to invoke this upgrade mechanism is by issuing the following |
||||
|
in an Odoo shell session: |
||||
|
|
||||
|
.. code-block:: python |
||||
|
|
||||
|
env['ir.module.module'].upgrade_changed_checksum() |
@ -0,0 +1,483 @@ |
|||||
|
<?xml version="1.0" encoding="utf-8" ?> |
||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> |
||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> |
||||
|
<head> |
||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> |
||||
|
<meta name="generator" content="Docutils 0.14: http://docutils.sourceforge.net/" /> |
||||
|
<title>Module Auto Update</title> |
||||
|
<style type="text/css"> |
||||
|
|
||||
|
/* |
||||
|
:Author: David Goodger (goodger@python.org) |
||||
|
:Id: $Id: html4css1.css 7952 2016-07-26 18:15:59Z milde $ |
||||
|
:Copyright: This stylesheet has been placed in the public domain. |
||||
|
|
||||
|
Default cascading style sheet for the HTML output of Docutils. |
||||
|
|
||||
|
See http://docutils.sf.net/docs/howto/html-stylesheets.html for how to |
||||
|
customize this style sheet. |
||||
|
*/ |
||||
|
|
||||
|
/* used to remove borders from tables and images */ |
||||
|
.borderless, table.borderless td, table.borderless th { |
||||
|
border: 0 } |
||||
|
|
||||
|
table.borderless td, table.borderless th { |
||||
|
/* Override padding for "table.docutils td" with "! important". |
||||
|
The right padding separates the table cells. */ |
||||
|
padding: 0 0.5em 0 0 ! important } |
||||
|
|
||||
|
.first { |
||||
|
/* Override more specific margin styles with "! important". */ |
||||
|
margin-top: 0 ! important } |
||||
|
|
||||
|
.last, .with-subtitle { |
||||
|
margin-bottom: 0 ! important } |
||||
|
|
||||
|
.hidden { |
||||
|
display: none } |
||||
|
|
||||
|
.subscript { |
||||
|
vertical-align: sub; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
.superscript { |
||||
|
vertical-align: super; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
a.toc-backref { |
||||
|
text-decoration: none ; |
||||
|
color: black } |
||||
|
|
||||
|
blockquote.epigraph { |
||||
|
margin: 2em 5em ; } |
||||
|
|
||||
|
dl.docutils dd { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
object[type="image/svg+xml"], object[type="application/x-shockwave-flash"] { |
||||
|
overflow: hidden; |
||||
|
} |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get bold-faced definition list terms |
||||
|
dl.docutils dt { |
||||
|
font-weight: bold } |
||||
|
*/ |
||||
|
|
||||
|
div.abstract { |
||||
|
margin: 2em 5em } |
||||
|
|
||||
|
div.abstract p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
text-align: center } |
||||
|
|
||||
|
div.admonition, div.attention, div.caution, div.danger, div.error, |
||||
|
div.hint, div.important, div.note, div.tip, div.warning { |
||||
|
margin: 2em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.admonition p.admonition-title, div.hint p.admonition-title, |
||||
|
div.important p.admonition-title, div.note p.admonition-title, |
||||
|
div.tip p.admonition-title { |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
div.attention p.admonition-title, div.caution p.admonition-title, |
||||
|
div.danger p.admonition-title, div.error p.admonition-title, |
||||
|
div.warning p.admonition-title, .code .error { |
||||
|
color: red ; |
||||
|
font-weight: bold ; |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
/* Uncomment (and remove this text!) to get reduced vertical space in |
||||
|
compound paragraphs. |
||||
|
div.compound .compound-first, div.compound .compound-middle { |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
div.compound .compound-last, div.compound .compound-middle { |
||||
|
margin-top: 0.5em } |
||||
|
*/ |
||||
|
|
||||
|
div.dedication { |
||||
|
margin: 2em 5em ; |
||||
|
text-align: center ; |
||||
|
font-style: italic } |
||||
|
|
||||
|
div.dedication p.topic-title { |
||||
|
font-weight: bold ; |
||||
|
font-style: normal } |
||||
|
|
||||
|
div.figure { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
div.footer, div.header { |
||||
|
clear: both; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
div.line-block { |
||||
|
display: block ; |
||||
|
margin-top: 1em ; |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
div.line-block div.line-block { |
||||
|
margin-top: 0 ; |
||||
|
margin-bottom: 0 ; |
||||
|
margin-left: 1.5em } |
||||
|
|
||||
|
div.sidebar { |
||||
|
margin: 0 0 0.5em 1em ; |
||||
|
border: medium outset ; |
||||
|
padding: 1em ; |
||||
|
background-color: #ffffee ; |
||||
|
width: 40% ; |
||||
|
float: right ; |
||||
|
clear: right } |
||||
|
|
||||
|
div.sidebar p.rubric { |
||||
|
font-family: sans-serif ; |
||||
|
font-size: medium } |
||||
|
|
||||
|
div.system-messages { |
||||
|
margin: 5em } |
||||
|
|
||||
|
div.system-messages h1 { |
||||
|
color: red } |
||||
|
|
||||
|
div.system-message { |
||||
|
border: medium outset ; |
||||
|
padding: 1em } |
||||
|
|
||||
|
div.system-message p.system-message-title { |
||||
|
color: red ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
div.topic { |
||||
|
margin: 2em } |
||||
|
|
||||
|
h1.section-subtitle, h2.section-subtitle, h3.section-subtitle, |
||||
|
h4.section-subtitle, h5.section-subtitle, h6.section-subtitle { |
||||
|
margin-top: 0.4em } |
||||
|
|
||||
|
h1.title { |
||||
|
text-align: center } |
||||
|
|
||||
|
h2.subtitle { |
||||
|
text-align: center } |
||||
|
|
||||
|
hr.docutils { |
||||
|
width: 75% } |
||||
|
|
||||
|
img.align-left, .figure.align-left, object.align-left, table.align-left { |
||||
|
clear: left ; |
||||
|
float: left ; |
||||
|
margin-right: 1em } |
||||
|
|
||||
|
img.align-right, .figure.align-right, object.align-right, table.align-right { |
||||
|
clear: right ; |
||||
|
float: right ; |
||||
|
margin-left: 1em } |
||||
|
|
||||
|
img.align-center, .figure.align-center, object.align-center { |
||||
|
display: block; |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
table.align-center { |
||||
|
margin-left: auto; |
||||
|
margin-right: auto; |
||||
|
} |
||||
|
|
||||
|
.align-left { |
||||
|
text-align: left } |
||||
|
|
||||
|
.align-center { |
||||
|
clear: both ; |
||||
|
text-align: center } |
||||
|
|
||||
|
.align-right { |
||||
|
text-align: right } |
||||
|
|
||||
|
/* reset inner alignment in figures */ |
||||
|
div.align-right { |
||||
|
text-align: inherit } |
||||
|
|
||||
|
/* div.align-center * { */ |
||||
|
/* text-align: left } */ |
||||
|
|
||||
|
.align-top { |
||||
|
vertical-align: top } |
||||
|
|
||||
|
.align-middle { |
||||
|
vertical-align: middle } |
||||
|
|
||||
|
.align-bottom { |
||||
|
vertical-align: bottom } |
||||
|
|
||||
|
ol.simple, ul.simple { |
||||
|
margin-bottom: 1em } |
||||
|
|
||||
|
ol.arabic { |
||||
|
list-style: decimal } |
||||
|
|
||||
|
ol.loweralpha { |
||||
|
list-style: lower-alpha } |
||||
|
|
||||
|
ol.upperalpha { |
||||
|
list-style: upper-alpha } |
||||
|
|
||||
|
ol.lowerroman { |
||||
|
list-style: lower-roman } |
||||
|
|
||||
|
ol.upperroman { |
||||
|
list-style: upper-roman } |
||||
|
|
||||
|
p.attribution { |
||||
|
text-align: right ; |
||||
|
margin-left: 50% } |
||||
|
|
||||
|
p.caption { |
||||
|
font-style: italic } |
||||
|
|
||||
|
p.credits { |
||||
|
font-style: italic ; |
||||
|
font-size: smaller } |
||||
|
|
||||
|
p.label { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
p.rubric { |
||||
|
font-weight: bold ; |
||||
|
font-size: larger ; |
||||
|
color: maroon ; |
||||
|
text-align: center } |
||||
|
|
||||
|
p.sidebar-title { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold ; |
||||
|
font-size: larger } |
||||
|
|
||||
|
p.sidebar-subtitle { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
p.topic-title { |
||||
|
font-weight: bold } |
||||
|
|
||||
|
pre.address { |
||||
|
margin-bottom: 0 ; |
||||
|
margin-top: 0 ; |
||||
|
font: inherit } |
||||
|
|
||||
|
pre.literal-block, pre.doctest-block, pre.math, pre.code { |
||||
|
margin-left: 2em ; |
||||
|
margin-right: 2em } |
||||
|
|
||||
|
pre.code .ln { color: grey; } /* line numbers */ |
||||
|
pre.code, code { background-color: #eeeeee } |
||||
|
pre.code .comment, code .comment { color: #5C6576 } |
||||
|
pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } |
||||
|
pre.code .literal.string, code .literal.string { color: #0C5404 } |
||||
|
pre.code .name.builtin, code .name.builtin { color: #352B84 } |
||||
|
pre.code .deleted, code .deleted { background-color: #DEB0A1} |
||||
|
pre.code .inserted, code .inserted { background-color: #A3D289} |
||||
|
|
||||
|
span.classifier { |
||||
|
font-family: sans-serif ; |
||||
|
font-style: oblique } |
||||
|
|
||||
|
span.classifier-delimiter { |
||||
|
font-family: sans-serif ; |
||||
|
font-weight: bold } |
||||
|
|
||||
|
span.interpreted { |
||||
|
font-family: sans-serif } |
||||
|
|
||||
|
span.option { |
||||
|
white-space: nowrap } |
||||
|
|
||||
|
span.pre { |
||||
|
white-space: pre } |
||||
|
|
||||
|
span.problematic { |
||||
|
color: red } |
||||
|
|
||||
|
span.section-subtitle { |
||||
|
/* font-size relative to parent (h1..h6 element) */ |
||||
|
font-size: 80% } |
||||
|
|
||||
|
table.citation { |
||||
|
border-left: solid 1px gray; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docinfo { |
||||
|
margin: 2em 4em } |
||||
|
|
||||
|
table.docutils { |
||||
|
margin-top: 0.5em ; |
||||
|
margin-bottom: 0.5em } |
||||
|
|
||||
|
table.footnote { |
||||
|
border-left: solid 1px black; |
||||
|
margin-left: 1px } |
||||
|
|
||||
|
table.docutils td, table.docutils th, |
||||
|
table.docinfo td, table.docinfo th { |
||||
|
padding-left: 0.5em ; |
||||
|
padding-right: 0.5em ; |
||||
|
vertical-align: top } |
||||
|
|
||||
|
table.docutils th.field-name, table.docinfo th.docinfo-name { |
||||
|
font-weight: bold ; |
||||
|
text-align: left ; |
||||
|
white-space: nowrap ; |
||||
|
padding-left: 0 } |
||||
|
|
||||
|
/* "booktabs" style (no vertical lines) */ |
||||
|
table.docutils.booktabs { |
||||
|
border: 0px; |
||||
|
border-top: 2px solid; |
||||
|
border-bottom: 2px solid; |
||||
|
border-collapse: collapse; |
||||
|
} |
||||
|
table.docutils.booktabs * { |
||||
|
border: 0px; |
||||
|
} |
||||
|
table.docutils.booktabs th { |
||||
|
border-bottom: thin solid; |
||||
|
text-align: left; |
||||
|
} |
||||
|
|
||||
|
h1 tt.docutils, h2 tt.docutils, h3 tt.docutils, |
||||
|
h4 tt.docutils, h5 tt.docutils, h6 tt.docutils { |
||||
|
font-size: 100% } |
||||
|
|
||||
|
ul.auto-toc { |
||||
|
list-style-type: none } |
||||
|
|
||||
|
</style> |
||||
|
</head> |
||||
|
<body> |
||||
|
<div class="document" id="module-auto-update"> |
||||
|
<h1 class="title">Module Auto Update</h1> |
||||
|
|
||||
|
<!-- !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||||
|
!! This file is generated by oca-gen-addon-readme !! |
||||
|
!! changes will be overwritten. !! |
||||
|
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! --> |
||||
|
<p><a class="reference external" href="https://odoo-community.org/page/development-status"><img alt="Production/Stable" src="https://img.shields.io/badge/maturity-Production%2FStable-green.png" /></a> <a class="reference external" href="http://www.gnu.org/licenses/lgpl-3.0-standalone.html"><img alt="License: LGPL-3" src="https://img.shields.io/badge/licence-LGPL--3-blue.png" /></a> <a class="reference external" href="https://github.com/OCA/server-tools/tree/11.0/module_auto_update"><img alt="OCA/server-tools" src="https://img.shields.io/badge/github-OCA%2Fserver--tools-lightgray.png?logo=github" /></a> <a class="reference external" href="https://translation.odoo-community.org/projects/server-tools-11-0/server-tools-11-0-module_auto_update"><img alt="Translate me on Weblate" src="https://img.shields.io/badge/weblate-Translate%20me-F47D42.png" /></a> <a class="reference external" href="https://runbot.odoo-community.org/runbot/149/11.0"><img alt="Try me on Runbot" src="https://img.shields.io/badge/runbot-Try%20me-875A7B.png" /></a></p> |
||||
|
<p>This addon provides mechanisms to compute sha1 hashes of installed addons, |
||||
|
and save them in the database. It also provides a method that exploits these |
||||
|
mechanisms to update a database by upgrading only the modules for which the |
||||
|
hash has changed since the last successful upgrade.</p> |
||||
|
<p><strong>Table of contents</strong></p> |
||||
|
<div class="contents local topic" id="contents"> |
||||
|
<ul class="simple"> |
||||
|
<li><a class="reference internal" href="#configuration" id="id1">Configuration</a></li> |
||||
|
<li><a class="reference internal" href="#usage" id="id2">Usage</a></li> |
||||
|
<li><a class="reference internal" href="#known-issues-roadmap" id="id3">Known issues / Roadmap</a></li> |
||||
|
<li><a class="reference internal" href="#bug-tracker" id="id4">Bug Tracker</a></li> |
||||
|
<li><a class="reference internal" href="#credits" id="id5">Credits</a><ul> |
||||
|
<li><a class="reference internal" href="#authors" id="id6">Authors</a></li> |
||||
|
<li><a class="reference internal" href="#contributors" id="id7">Contributors</a></li> |
||||
|
<li><a class="reference internal" href="#maintainers" id="id8">Maintainers</a></li> |
||||
|
</ul> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="configuration"> |
||||
|
<h1><a class="toc-backref" href="#id1">Configuration</a></h1> |
||||
|
<p>This module supports the following system parameters:</p> |
||||
|
<ul class="simple"> |
||||
|
<li><tt class="docutils literal">module_auto_update.exclude_patterns</tt>: comma-separated list of file |
||||
|
name patterns to ignore when computing addon checksums. Defaults to |
||||
|
<tt class="docutils literal"><span class="pre">*.pyc,*.pyo,i18n/*.pot,i18n_extra/*.pot,static/*</span></tt>. |
||||
|
Filename patterns must be compatible with the python <tt class="docutils literal">fnmatch</tt> function.</li> |
||||
|
</ul> |
||||
|
<p>In addition to the above pattern, .po files corresponding to languages that |
||||
|
are not installed in the Odoo database are ignored when computing checksums.</p> |
||||
|
</div> |
||||
|
<div class="section" id="usage"> |
||||
|
<h1><a class="toc-backref" href="#id2">Usage</a></h1> |
||||
|
<p>The main method provided by this module is <tt class="docutils literal">upgrade_changed_checksum</tt> |
||||
|
on <tt class="docutils literal">ir.module.module</tt>. It runs a database upgrade for all installed |
||||
|
modules for which the hash has changed since the last successful |
||||
|
run of this method. On success it saves the hashes in the database.</p> |
||||
|
<p>The first time this method is invoked after installing the module, it |
||||
|
runs an upgrade of all modules, because it has not saved the hashes yet. |
||||
|
This is by design, priviledging safety. Should this be an issue, |
||||
|
the method <tt class="docutils literal">_save_installed_checksums</tt> can be invoked in a situation |
||||
|
where one is sure all modules on disk are installed and up-to-date in the |
||||
|
database.</p> |
||||
|
<p>An easy way to invoke this upgrade mechanism is by issuing the following |
||||
|
in an Odoo shell session:</p> |
||||
|
<pre class="literal-block"> |
||||
|
env['ir.module.module'].upgrade_changed_checksum() |
||||
|
</pre> |
||||
|
</div> |
||||
|
<div class="section" id="known-issues-roadmap"> |
||||
|
<h1><a class="toc-backref" href="#id3">Known issues / Roadmap</a></h1> |
||||
|
<ul> |
||||
|
<li><p class="first">Since version <tt class="docutils literal">2.0.0</tt>, some features have been deprecated. |
||||
|
When you upgrade from previous versions, these features will be kept for |
||||
|
backwards compatibility, but beware! They are buggy!</p> |
||||
|
<p>If you install this addon from scratch, these features are disabled by |
||||
|
default.</p> |
||||
|
<p>To force enabling or disabling the deprecated features, set a configuration |
||||
|
parameter called <tt class="docutils literal">module_auto_update.enable_deprecated</tt> to either <tt class="docutils literal">1</tt> |
||||
|
or <tt class="docutils literal">0</tt>. It is recommended that you disable them.</p> |
||||
|
<p>Keep in mind that from this version, all upgrades are assumed to run in a |
||||
|
separate odoo instance, dedicated exclusively to upgrade Odoo.</p> |
||||
|
</li> |
||||
|
<li><p class="first">When migrating the addon to new versions, the deprecated features should be |
||||
|
removed. To make it simple all deprecated features are found in files |
||||
|
suffixed with <tt class="docutils literal">_deprecated</tt>.</p> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="bug-tracker"> |
||||
|
<h1><a class="toc-backref" href="#id4">Bug Tracker</a></h1> |
||||
|
<p>Bugs are tracked on <a class="reference external" href="https://github.com/OCA/server-tools/issues">GitHub Issues</a>. |
||||
|
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 |
||||
|
<a class="reference external" href="https://github.com/OCA/server-tools/issues/new?body=module:%20module_auto_update%0Aversion:%2011.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**">feedback</a>.</p> |
||||
|
<p>Do not contact contributors directly about support or help with technical issues.</p> |
||||
|
</div> |
||||
|
<div class="section" id="credits"> |
||||
|
<h1><a class="toc-backref" href="#id5">Credits</a></h1> |
||||
|
<div class="section" id="authors"> |
||||
|
<h2><a class="toc-backref" href="#id6">Authors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>LasLabs</li> |
||||
|
<li>Juan José Scarafía</li> |
||||
|
<li>Tecnativa</li> |
||||
|
<li>ACSONE SA/NV</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="contributors"> |
||||
|
<h2><a class="toc-backref" href="#id7">Contributors</a></h2> |
||||
|
<ul class="simple"> |
||||
|
<li>Brent Hughes <<a class="reference external" href="mailto:brent.hughes@laslabs.com">brent.hughes@laslabs.com</a>></li> |
||||
|
<li>Juan José Scarafía <<a class="reference external" href="mailto:jjs@adhoc.com.ar">jjs@adhoc.com.ar</a>></li> |
||||
|
<li>Jairo Llopis <<a class="reference external" href="mailto:jairo.llopis@tecnativa.com">jairo.llopis@tecnativa.com</a>></li> |
||||
|
<li>Stéphane Bidoul <<a class="reference external" href="mailto:stephane.bidoul@acsone.eu">stephane.bidoul@acsone.eu</a>> (<a class="reference external" href="https://acsone.eu">https://acsone.eu</a>)</li> |
||||
|
</ul> |
||||
|
</div> |
||||
|
<div class="section" id="maintainers"> |
||||
|
<h2><a class="toc-backref" href="#id8">Maintainers</a></h2> |
||||
|
<p>This module is maintained by the OCA.</p> |
||||
|
<a class="reference external image-reference" href="https://odoo-community.org"><img alt="Odoo Community Association" src="https://odoo-community.org/logo.png" /></a> |
||||
|
<p>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.</p> |
||||
|
<p>Current <a class="reference external" href="https://odoo-community.org/page/maintainer-role">maintainer</a>:</p> |
||||
|
<p><a class="reference external" href="https://github.com/sbidoul"><img alt="sbidoul" src="https://github.com/sbidoul.png?size=40px" /></a></p> |
||||
|
<p>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/11.0/module_auto_update">OCA/server-tools</a> project on GitHub.</p> |
||||
|
<p>You are welcome to contribute. To learn how please visit <a class="reference external" href="https://odoo-community.org/page/Contribute">https://odoo-community.org/page/Contribute</a>.</p> |
||||
|
</div> |
||||
|
</div> |
||||
|
</div> |
||||
|
</body> |
||||
|
</html> |
@ -0,0 +1,4 @@ |
|||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
from . import test_addon_hash |
||||
|
from . import test_module |
@ -0,0 +1 @@ |
|||||
|
Test data for addon_hash module. |
@ -0,0 +1 @@ |
|||||
|
<odoo/> |
@ -0,0 +1 @@ |
|||||
|
<odoo/> |
@ -0,0 +1 @@ |
|||||
|
en text |
@ -0,0 +1 @@ |
|||||
|
en_US |
@ -0,0 +1 @@ |
|||||
|
fr |
@ -0,0 +1 @@ |
|||||
|
fr_BE |
@ -0,0 +1 @@ |
|||||
|
... |
@ -0,0 +1 @@ |
|||||
|
en |
@ -0,0 +1 @@ |
|||||
|
fr |
@ -0,0 +1 @@ |
|||||
|
nl_NL |
@ -0,0 +1 @@ |
|||||
|
1+1 |
@ -0,0 +1 @@ |
|||||
|
/* Javascript */ |
@ -0,0 +1,67 @@ |
|||||
|
# Copyright 2018 ACSONE SA/NV. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
import os |
||||
|
import unittest |
||||
|
|
||||
|
from .. import addon_hash |
||||
|
from ..models.module import DEFAULT_EXCLUDE_PATTERNS |
||||
|
|
||||
|
|
||||
|
class TestAddonHash(unittest.TestCase): |
||||
|
|
||||
|
def setUp(self): |
||||
|
super(TestAddonHash, self).setUp() |
||||
|
self.sample_dir = os.path.join( |
||||
|
os.path.dirname(__file__), |
||||
|
'sample_module', |
||||
|
) |
||||
|
|
||||
|
def test_basic(self): |
||||
|
files = list(addon_hash._walk( |
||||
|
self.sample_dir, |
||||
|
exclude_patterns=["*/__pycache__/*"], |
||||
|
keep_langs=[], |
||||
|
)) |
||||
|
self.assertEqual(files, [ |
||||
|
'README.rst', |
||||
|
'data/f1.xml', |
||||
|
'data/f2.xml', |
||||
|
'i18n/en.po', |
||||
|
'i18n/en_US.po', |
||||
|
'i18n/fr.po', |
||||
|
'i18n/fr_BE.po', |
||||
|
'i18n/test.pot', |
||||
|
'i18n_extra/en.po', |
||||
|
'i18n_extra/fr.po', |
||||
|
'i18n_extra/nl_NL.po', |
||||
|
'models/stuff.py', |
||||
|
'models/stuff.pyc', |
||||
|
'models/stuff.pyo', |
||||
|
'static/src/some.js', |
||||
|
]) |
||||
|
|
||||
|
def test_exclude(self): |
||||
|
files = list(addon_hash._walk( |
||||
|
self.sample_dir, |
||||
|
exclude_patterns=DEFAULT_EXCLUDE_PATTERNS.split(','), |
||||
|
keep_langs=['fr_FR', 'nl'], |
||||
|
)) |
||||
|
self.assertEqual(files, [ |
||||
|
'README.rst', |
||||
|
'data/f1.xml', |
||||
|
'data/f2.xml', |
||||
|
'i18n/fr.po', |
||||
|
'i18n/fr_BE.po', |
||||
|
'i18n_extra/fr.po', |
||||
|
'i18n_extra/nl_NL.po', |
||||
|
'models/stuff.py', |
||||
|
]) |
||||
|
|
||||
|
def test2(self): |
||||
|
checksum = addon_hash.addon_hash( |
||||
|
self.sample_dir, |
||||
|
exclude_patterns=['*.pyc', '*.pyo', '*.pot', 'static/*'], |
||||
|
keep_langs=['fr_FR', 'nl'], |
||||
|
) |
||||
|
self.assertEqual(checksum, 'fecb89486c8a29d1f760cbd01c1950f6e8421b14') |
@ -0,0 +1,237 @@ |
|||||
|
# Copyright 2017 LasLabs Inc. |
||||
|
# Copyright 2018 ACSONE SA/NV. |
||||
|
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). |
||||
|
|
||||
|
import os |
||||
|
import tempfile |
||||
|
|
||||
|
import mock |
||||
|
|
||||
|
import odoo |
||||
|
from odoo.modules import get_module_path |
||||
|
from odoo.tests import TransactionCase |
||||
|
|
||||
|
from ..addon_hash import addon_hash |
||||
|
from ..models.module import IncompleteUpgradeError, DEFAULT_EXCLUDE_PATTERNS |
||||
|
|
||||
|
MODULE_NAME = 'module_auto_update' |
||||
|
|
||||
|
|
||||
|
class TestModule(TransactionCase): |
||||
|
|
||||
|
def setUp(self): |
||||
|
super(TestModule, self).setUp() |
||||
|
self.own_module = self.env['ir.module.module'].search([ |
||||
|
('name', '=', MODULE_NAME), |
||||
|
]) |
||||
|
self.own_dir_path = get_module_path(MODULE_NAME) |
||||
|
keep_langs = self.env['res.lang'].search([]).mapped('code') |
||||
|
self.own_checksum = addon_hash( |
||||
|
self.own_dir_path, |
||||
|
exclude_patterns=DEFAULT_EXCLUDE_PATTERNS.split(','), |
||||
|
keep_langs=keep_langs, |
||||
|
) |
||||
|
self.own_writeable = os.access(self.own_dir_path, os.W_OK) |
||||
|
|
||||
|
def test_compute_checksum_dir(self): |
||||
|
"""It should compute the directory's SHA-1 hash""" |
||||
|
self.assertEqual( |
||||
|
self.own_module._get_checksum_dir(), self.own_checksum, |
||||
|
'Module directory checksum not computed properly', |
||||
|
) |
||||
|
|
||||
|
def test_compute_checksum_dir_ignore_excluded(self): |
||||
|
"""It should exclude .pyc/.pyo extensions from checksum |
||||
|
calculations""" |
||||
|
if not self.own_writeable: |
||||
|
self.skipTest("Own directory not writeable") |
||||
|
with tempfile.NamedTemporaryFile(suffix='.pyc', dir=self.own_dir_path): |
||||
|
self.assertEqual( |
||||
|
self.own_module._get_checksum_dir(), self.own_checksum, |
||||
|
'SHA1 checksum does not ignore excluded extensions', |
||||
|
) |
||||
|
|
||||
|
def test_compute_checksum_dir_recomputes_when_file_added(self): |
||||
|
"""It should return a different value when a non-.pyc/.pyo file is |
||||
|
added to the module directory""" |
||||
|
if not self.own_writeable: |
||||
|
self.skipTest("Own directory not writeable") |
||||
|
with tempfile.NamedTemporaryFile(suffix='.py', dir=self.own_dir_path): |
||||
|
self.assertNotEqual( |
||||
|
self.own_module._get_checksum_dir(), self.own_checksum, |
||||
|
'SHA1 checksum not recomputed', |
||||
|
) |
||||
|
|
||||
|
def test_saved_checksums(self): |
||||
|
Imm = self.env['ir.module.module'] |
||||
|
base_module = Imm.search([('name', '=', 'base')]) |
||||
|
self.assertEqual(base_module.state, 'installed') |
||||
|
self.assertFalse(Imm._get_saved_checksums()) |
||||
|
Imm._save_installed_checksums() |
||||
|
saved_checksums = Imm._get_saved_checksums() |
||||
|
self.assertTrue(saved_checksums) |
||||
|
self.assertTrue(saved_checksums['base']) |
||||
|
|
||||
|
def test_get_modules_with_changed_checksum(self): |
||||
|
Imm = self.env['ir.module.module'] |
||||
|
self.assertTrue(Imm._get_modules_with_changed_checksum()) |
||||
|
Imm._save_installed_checksums() |
||||
|
self.assertFalse(Imm._get_modules_with_changed_checksum()) |
||||
|
|
||||
|
|
||||
|
@odoo.tests.tagged('post_install', '-at_install') |
||||
|
class TestModuleAfterInstall(TransactionCase): |
||||
|
|
||||
|
def setUp(self): |
||||
|
super(TestModuleAfterInstall, self).setUp() |
||||
|
Imm = self.env['ir.module.module'] |
||||
|
self.own_module = Imm.search([('name', '=', MODULE_NAME)]) |
||||
|
self.base_module = Imm.search([('name', '=', 'base')]) |
||||
|
|
||||
|
def test_get_modules_partially_installed(self): |
||||
|
Imm = self.env['ir.module.module'] |
||||
|
self.assertTrue( |
||||
|
self.own_module not in Imm._get_modules_partially_installed()) |
||||
|
self.own_module.button_upgrade() |
||||
|
self.assertTrue( |
||||
|
self.own_module in Imm._get_modules_partially_installed()) |
||||
|
self.own_module.button_upgrade_cancel() |
||||
|
self.assertTrue( |
||||
|
self.own_module not in Imm._get_modules_partially_installed()) |
||||
|
|
||||
|
def test_upgrade_changed_checksum(self): |
||||
|
Imm = self.env['ir.module.module'] |
||||
|
Bmu = self.env['base.module.upgrade'] |
||||
|
|
||||
|
# check modules are in installed state |
||||
|
installed_modules = Imm.search([('state', '=', 'installed')]) |
||||
|
self.assertTrue(self.own_module in installed_modules) |
||||
|
self.assertTrue(self.base_module in installed_modules) |
||||
|
self.assertTrue(len(installed_modules) > 2) |
||||
|
# change the checksum of 'base' |
||||
|
Imm._save_installed_checksums() |
||||
|
saved_checksums = Imm._get_saved_checksums() |
||||
|
saved_checksums['base'] = False |
||||
|
Imm._save_checksums(saved_checksums) |
||||
|
changed_modules = Imm._get_modules_with_changed_checksum() |
||||
|
self.assertEqual(len(changed_modules), 1) |
||||
|
self.assertTrue(self.base_module in changed_modules) |
||||
|
|
||||
|
def upgrade_module_mock(self_model): |
||||
|
upgrade_module_mock.call_count += 1 |
||||
|
# since we are upgrading base, all installed module |
||||
|
# must have been marked to upgrade at this stage |
||||
|
self.assertEqual(self.base_module.state, 'to upgrade') |
||||
|
self.assertEqual(self.own_module.state, 'to upgrade') |
||||
|
installed_modules.write({'state': 'installed'}) |
||||
|
|
||||
|
upgrade_module_mock.call_count = 0 |
||||
|
|
||||
|
# upgrade_changed_checksum commits, so mock that |
||||
|
with mock.patch.object(self.env.cr, 'commit'): |
||||
|
|
||||
|
# we simulate an install by setting module states |
||||
|
Bmu._patch_method('upgrade_module', upgrade_module_mock) |
||||
|
try: |
||||
|
Imm.upgrade_changed_checksum() |
||||
|
self.assertEqual(upgrade_module_mock.call_count, 1) |
||||
|
self.assertEqual(self.base_module.state, 'installed') |
||||
|
self.assertEqual(self.own_module.state, 'installed') |
||||
|
saved_checksums = Imm._get_saved_checksums() |
||||
|
self.assertTrue(saved_checksums['base']) |
||||
|
self.assertTrue(saved_checksums[MODULE_NAME]) |
||||
|
finally: |
||||
|
Bmu._revert_method('upgrade_module') |
||||
|
|
||||
|
def test_incomplete_upgrade(self): |
||||
|
Imm = self.env['ir.module.module'] |
||||
|
Bmu = self.env['base.module.upgrade'] |
||||
|
|
||||
|
installed_modules = Imm.search([('state', '=', 'installed')]) |
||||
|
# change the checksum of 'base' |
||||
|
Imm._save_installed_checksums() |
||||
|
saved_checksums = Imm._get_saved_checksums() |
||||
|
saved_checksums['base'] = False |
||||
|
Imm._save_checksums(saved_checksums) |
||||
|
|
||||
|
def upgrade_module_mock(self_model): |
||||
|
upgrade_module_mock.call_count += 1 |
||||
|
# since we are upgrading base, all installed module |
||||
|
# must have been marked to upgrade at this stage |
||||
|
self.assertEqual(self.base_module.state, 'to upgrade') |
||||
|
self.assertEqual(self.own_module.state, 'to upgrade') |
||||
|
installed_modules.write({'state': 'installed'}) |
||||
|
# simulate partial upgrade |
||||
|
self.own_module.write({'state': 'to upgrade'}) |
||||
|
|
||||
|
upgrade_module_mock.call_count = 0 |
||||
|
|
||||
|
# upgrade_changed_checksum commits, so mock that |
||||
|
with mock.patch.object(self.env.cr, 'commit'): |
||||
|
|
||||
|
# we simulate an install by setting module states |
||||
|
Bmu._patch_method('upgrade_module', upgrade_module_mock) |
||||
|
try: |
||||
|
with self.assertRaises(IncompleteUpgradeError): |
||||
|
Imm.upgrade_changed_checksum() |
||||
|
self.assertEqual(upgrade_module_mock.call_count, 1) |
||||
|
finally: |
||||
|
Bmu._revert_method('upgrade_module') |
||||
|
|
||||
|
def test_incomplete_upgrade_no_checkusm(self): |
||||
|
Imm = self.env['ir.module.module'] |
||||
|
Bmu = self.env['base.module.upgrade'] |
||||
|
|
||||
|
installed_modules = Imm.search( |
||||
|
[('state', '=', 'installed')]) |
||||
|
# change the checksum of 'base' |
||||
|
Imm._save_installed_checksums() |
||||
|
saved_checksums = Imm._get_saved_checksums() |
||||
|
|
||||
|
Imm._save_checksums(saved_checksums) |
||||
|
self.base_module.write({'state': 'to upgrade'}) |
||||
|
|
||||
|
def upgrade_module_mock(self_model): |
||||
|
upgrade_module_mock.call_count += 1 |
||||
|
# since we are upgrading base, all installed module |
||||
|
# must have been marked to upgrade at this stage |
||||
|
self.assertEqual(self.base_module.state, 'to upgrade') |
||||
|
self.assertEqual(self.own_module.state, 'installed') |
||||
|
installed_modules.write({'state': 'installed'}) |
||||
|
|
||||
|
upgrade_module_mock.call_count = 0 |
||||
|
|
||||
|
# upgrade_changed_checksum commits, so mock that |
||||
|
with mock.patch.object(self.env.cr, 'commit'): |
||||
|
|
||||
|
# we simulate an install by setting module states |
||||
|
Bmu._patch_method('upgrade_module', |
||||
|
upgrade_module_mock) |
||||
|
# got just other modules to_upgrade and no checksum ones |
||||
|
try: |
||||
|
Imm.upgrade_changed_checksum() |
||||
|
self.assertEqual(upgrade_module_mock.call_count, 1) |
||||
|
finally: |
||||
|
Bmu._revert_method('upgrade_module') |
||||
|
|
||||
|
def test_nothing_to_upgrade(self): |
||||
|
Imm = self.env['ir.module.module'] |
||||
|
Bmu = self.env['base.module.upgrade'] |
||||
|
|
||||
|
Imm._save_installed_checksums() |
||||
|
|
||||
|
def upgrade_module_mock(self_model): |
||||
|
upgrade_module_mock.call_count += 1 |
||||
|
|
||||
|
upgrade_module_mock.call_count = 0 |
||||
|
|
||||
|
# upgrade_changed_checksum commits, so mock that |
||||
|
with mock.patch.object(self.env.cr, 'commit'): |
||||
|
|
||||
|
# we simulate an install by setting module states |
||||
|
Bmu._patch_method('upgrade_module', upgrade_module_mock) |
||||
|
try: |
||||
|
Imm.upgrade_changed_checksum() |
||||
|
self.assertEqual(upgrade_module_mock.call_count, 0) |
||||
|
finally: |
||||
|
Bmu._revert_method('upgrade_module') |
@ -0,0 +1 @@ |
|||||
|
../../../../module_auto_update |
@ -0,0 +1,6 @@ |
|||||
|
import setuptools |
||||
|
|
||||
|
setuptools.setup( |
||||
|
setup_requires=['setuptools-odoo'], |
||||
|
odoo_addon=True, |
||||
|
) |
Write
Preview
Loading…
Cancel
Save
Reference in new issue