README.rst

pull/2543/head
OCA-git-bot 2022-07-15 09:17:13 +00:00 committed by fkantelberg
parent 2913604595
commit 52495d4931
46 changed files with 2017 additions and 0 deletions

View File

@ -0,0 +1,123 @@
==================
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/15.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-15-0/server-tools-15-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/15.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.
To invoke the upgrade mechanism, navigate to *Apps* menu and use the
*Auto-Upgrade Modules* button, available only in developer mode. Restarting
the Odoo instance is highly recommended to minify risk of any possible issues.
Another 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()
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:%2015.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)
* Eric Antones <eantones@nuobit.com>
* Manuel Engel <manuel.engel@initos.com>
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.
This module is part of the `OCA/server-tools <https://github.com/OCA/server-tools/tree/15.0/module_auto_update>`_ project on GitHub.
You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

View File

@ -0,0 +1,4 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from . import models
from .hooks import uninstall_hook

View File

@ -0,0 +1,22 @@
# Copyright 2017 LasLabs Inc.
# Copyright 2018 Brainbean Apps (https://brainbeanapps.com)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
{
"name": "Module Auto Update",
"summary": "Automatically update Odoo modules",
"version": "15.0.1.0.0",
"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"],
"data": ["views/ir_module_module.xml"],
"development_status": "Production/Stable",
}

View File

@ -0,0 +1,44 @@
# Copyright 2018 ACSONE SA/NV.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
import hashlib
import os
from fnmatch import fnmatch
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 = {language.split("_")[0] for language 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()

View File

@ -0,0 +1,11 @@
# Copyright 2017 LasLabs Inc.
# License LGPL-3.0 or later (https://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)

View File

@ -0,0 +1,50 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""

View File

@ -0,0 +1,75 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""
#~ msgid "Checksum Dir"
#~ msgstr "Kontrolní součet Dir"
#~ msgid "Checksum Installed"
#~ msgstr "Kontrolní součet je nainstalován"
#~ msgid "Module Upgrade"
#~ msgstr "Aktualizace modulů"
#~ 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"

View File

@ -0,0 +1,57 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""
#~ msgid "Module Upgrade"
#~ msgstr "Modul aktualisieren"
#, fuzzy
#~ msgid "Perform Module Upgrades"
#~ msgstr "Modul aktualisieren"

View File

@ -0,0 +1,63 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""
#~ msgid "Module Upgrade"
#~ msgstr "Actualización de módulo"
#~ msgid "Modules"
#~ msgstr "Módulos"
#~ msgid "Scheduled Upgrades"
#~ msgstr "Actualizaciones programadas"
#~ msgid "Updates"
#~ msgstr "Actualizaciones"

View File

@ -0,0 +1,51 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""

View File

@ -0,0 +1,75 @@
# 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: 2021-05-14 19:47+0000\n"
"Last-Translator: Yves Le Doeuff <yld@alliasys.fr>\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"
"X-Generator: Weblate 4.3.2\n"
#. module: module_auto_update
#: model:ir.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr "Mise à jour automatique des modules"
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr "Nom affiché"
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr "Recherche intelligente"
#~ msgid "Checksum Dir"
#~ msgstr "Somme de contrôle du dossier"
#~ msgid "Checksum Installed"
#~ msgstr "Somme de contrôle installée"
#~ msgid "Module Upgrade"
#~ msgstr "Mise à niveau du module"
#~ 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"

View File

@ -0,0 +1,51 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""

View File

@ -0,0 +1,51 @@
# 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: 2021-11-29 11:45+0000\n"
"Last-Translator: Francesco Foresti <francesco.foresti@ooops404.com>\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"
"X-Generator: Weblate 4.3.2\n"
#. module: module_auto_update
#: model:ir.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr "Aggiorna Moduli Automaticamente"
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr "Nome da visualizzare"
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr "ID"
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
msgstr "Ultima modifica il"
#. 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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr "Ricerca Smart"

View File

@ -0,0 +1,39 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * module_auto_update
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 15.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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: code:addons/module_auto_update/models/module.py:0
#, python-format
msgid "Checksum upgrade complete."
msgstr ""
#. module: module_auto_update
#: model:ir.model,name:module_auto_update.model_ir_module_module
msgid "Module"
msgstr ""
#. module: module_auto_update
#: code:addons/module_auto_update/models/module.py:0
#, python-format
msgid ""
"No checksum change detected in installed modules and all modules installed, "
"nothing to do."
msgstr ""

View File

@ -0,0 +1,51 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""

View File

@ -0,0 +1,52 @@
# 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: 2019-08-30 14:37+0000\n"
"Last-Translator: Rodrigo Macedo <rmsolucoeseminformatic4@gmail.com>\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"
"X-Generator: Weblate 3.8\n"
#. module: module_auto_update
#: model:ir.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr "Módulos de atualização automática"
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""

View File

@ -0,0 +1,51 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""

View File

@ -0,0 +1,50 @@
# 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.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""

View File

@ -0,0 +1,48 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * module_auto_update
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 13.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2019-08-31 06:18+0000\n"
"Last-Translator: 黎伟杰 <674416404@qq.com>\n"
"Language-Team: none\n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Weblate 3.8\n"
#. module: module_auto_update
#: model:ir.actions.server,name:module_auto_update.ir_module_module_upgrade_changed_checksum
#: model:ir.ui.menu,name:module_auto_update.menu_ir_module_module_upgrade_changed_checksum
msgid "Auto-Upgrade Modules"
msgstr "自动升级模块"
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__display_name
msgid "Display Name"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module__id
msgid "ID"
msgstr ""
#. module: module_auto_update
#: model:ir.model.fields,field_description:module_auto_update.field_ir_module_module____last_update
msgid "Last Modified on"
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.fields,field_description:module_auto_update.field_ir_module_module__smart_search
msgid "Smart Search"
msgstr ""

View File

@ -0,0 +1,3 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from . import module

View File

@ -0,0 +1,198 @@
# Copyright 2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV.
# License LGPL-3.0 or later (https://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"
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))
Icp.flush()
@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 {
"type": "ir.actions.client",
"tag": "display_notification",
"params": {
"message": _(
"No checksum change detected in installed modules "
"and all modules installed, nothing to do."
),
"type": "success",
"sticky": False,
},
}
_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.")
return {
"type": "ir.actions.client",
"tag": "display_notification",
"params": {
"message": _("Checksum upgrade complete."),
"type": "success",
"sticky": False,
},
}

View File

@ -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.

View File

@ -0,0 +1,6 @@
* 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)
* Eric Antones <eantones@nuobit.com>
* Manuel Engel <manuel.engel@initos.com>

View File

@ -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.

View File

@ -0,0 +1,22 @@
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.
To invoke the upgrade mechanism, navigate to *Apps* menu and use the
*Auto-Upgrade Modules* button, available only in developer mode. Restarting
the Odoo instance is highly recommended to minify risk of any possible issues.
Another 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()

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@ -0,0 +1,465 @@
<?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.15.1: 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/15.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-15-0/server-tools-15-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/15.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="#bug-tracker" id="id3">Bug Tracker</a></li>
<li><a class="reference internal" href="#credits" id="id4">Credits</a><ul>
<li><a class="reference internal" href="#authors" id="id5">Authors</a></li>
<li><a class="reference internal" href="#contributors" id="id6">Contributors</a></li>
<li><a class="reference internal" href="#maintainers" id="id7">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>To invoke the upgrade mechanism, navigate to <em>Apps</em> menu and use the
<em>Auto-Upgrade Modules</em> button, available only in developer mode. Restarting
the Odoo instance is highly recommended to minify risk of any possible issues.</p>
<p>Another easy way to invoke this upgrade mechanism is by issuing the following
in an Odoo shell session:</p>
<pre class="code python literal-block">
<span class="n">env</span><span class="p">[</span><span class="s1">'ir.module.module'</span><span class="p">]</span><span class="o">.</span><span class="n">upgrade_changed_checksum</span><span class="p">()</span>
</pre>
</div>
<div class="section" id="bug-tracker">
<h1><a class="toc-backref" href="#id3">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:%2015.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="#id4">Credits</a></h1>
<div class="section" id="authors">
<h2><a class="toc-backref" href="#id5">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="#id6">Contributors</a></h2>
<ul class="simple">
<li>Brent Hughes &lt;<a class="reference external" href="mailto:brent.hughes&#64;laslabs.com">brent.hughes&#64;laslabs.com</a>&gt;</li>
<li>Juan José Scarafía &lt;<a class="reference external" href="mailto:jjs&#64;adhoc.com.ar">jjs&#64;adhoc.com.ar</a>&gt;</li>
<li>Jairo Llopis &lt;<a class="reference external" href="mailto:jairo.llopis&#64;tecnativa.com">jairo.llopis&#64;tecnativa.com</a>&gt;</li>
<li>Stéphane Bidoul &lt;<a class="reference external" href="mailto:stephane.bidoul&#64;acsone.eu">stephane.bidoul&#64;acsone.eu</a>&gt; (<a class="reference external" href="https://acsone.eu">https://acsone.eu</a>)</li>
<li>Eric Antones &lt;<a class="reference external" href="mailto:eantones&#64;nuobit.com">eantones&#64;nuobit.com</a>&gt;</li>
<li>Manuel Engel &lt;<a class="reference external" href="mailto:manuel.engel&#64;initos.com">manuel.engel&#64;initos.com</a>&gt;</li>
</ul>
</div>
<div class="section" id="maintainers">
<h2><a class="toc-backref" href="#id7">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>This module is part of the <a class="reference external" href="https://github.com/OCA/server-tools/tree/15.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>

View File

@ -0,0 +1,4 @@
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
from . import test_addon_hash
from . import test_module

View File

@ -0,0 +1 @@
Sample module for tests addon_hash module.

View File

@ -0,0 +1 @@
<odoo />

View File

@ -0,0 +1 @@
<odoo />

View File

@ -0,0 +1 @@
_ = 1 + 1

View File

@ -0,0 +1 @@
/* Javascript */

View File

@ -0,0 +1,76 @@
# Copyright 2018 ACSONE SA/NV.
# License LGPL-3.0 or later (https://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")

View File

@ -0,0 +1,233 @@
# Copyright 2017 LasLabs Inc.
# Copyright 2018 ACSONE SA/NV.
# License LGPL-3.0 or later (https://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 DEFAULT_EXCLUDE_PATTERNS, IncompleteUpgradeError
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")

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<!--
Copyright 2018 Brainbean Apps (https://brainbeanapps.com)
License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl).
-->
<record id="ir_module_module_upgrade_changed_checksum" model="ir.actions.server">
<field name="name">Auto-Upgrade Modules</field>
<field name="type">ir.actions.server</field>
<field name="model_id" ref="base.model_ir_module_module" />
<field name="state">code</field>
<field name="code">
action = model.upgrade_changed_checksum()
</field>
</record>
<menuitem
name="Auto-Upgrade Modules"
action="ir_module_module_upgrade_changed_checksum"
id="menu_ir_module_module_upgrade_changed_checksum"
groups="base.group_no_one"
parent="base.menu_management"
sequence="45"
/>
</odoo>