server-tools/upgrade_analysis/models/upgrade_record.py

186 lines
5.9 KiB
Python

# Copyright 2011-2015 Therp BV <https://therp.nl>
# Copyright 2016-2020 Opener B.V. <https://opener.am>
# Copyright 2019 ForgeFlow <https://forgeflow.com>
# Copyright 2020 GRAP <https://grap.coop>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
import ast
import logging
import os
from odoo import api, fields, models
from odoo.exceptions import ValidationError
from odoo.modules.module import MANIFEST_NAMES, get_module_path
from odoo.tools.translate import _
_logger = logging.getLogger(__name__)
class UpgradeRecord(models.Model):
_name = "upgrade.record"
_description = "Upgrade Record"
name = fields.Char(readonly=True)
module = fields.Char(readonly=True)
model = fields.Char(readonly=True)
field = fields.Char(readonly=True)
mode = fields.Selection(
[("create", "Create"), ("modify", "Modify")],
help="Set to Create if a field is newly created "
"in this module. If this module modifies an attribute of an "
"existing field, set to Modify.",
readonly=True,
)
type = fields.Selection(
[("field", "Field"), ("xmlid", "XML ID"), ("model", "Model")],
readonly=True,
)
attribute_ids = fields.One2many(
comodel_name="upgrade.attribute", inverse_name="record_id", readonly=True
)
noupdate = fields.Boolean(readonly=True)
domain = fields.Char(readonly=True)
definition = fields.Char(readonly=True)
prefix = fields.Char(compute="_compute_prefix_and_suffix")
suffix = fields.Char(compute="_compute_prefix_and_suffix")
model_original_module = fields.Char(compute="_compute_model_original_module")
model_type = fields.Char(compute="_compute_model_type")
@api.depends("name")
def _compute_prefix_and_suffix(self):
for rec in self:
rec.prefix, rec.suffix = rec.name.split(".", 1)
@api.depends("model", "type")
def _compute_model_original_module(self):
for rec in self:
if rec.type == "model":
rec.model_original_module = self.env[rec.model]._original_module
else:
rec.model_original_module = ""
@api.depends("model", "type")
def _compute_model_type(self):
for rec in self:
if rec.type == "model":
model = self.env[rec.model]
if model._auto and model._transient:
rec.model_type = "transient"
elif model._auto:
rec.model_type = ""
elif not model._auto and model._abstract:
rec.model_type = "abstract"
else:
rec.model_type = "sql_view"
else:
rec.model_type = ""
@api.model
def field_dump(self):
keys = [
"attachment",
"module",
"mode",
"model",
"field",
"type",
"isfunction",
"isproperty",
"isrelated",
"relation",
"required",
"stored",
"selection_keys",
"hasdefault",
"table",
"_inherits",
"_order",
]
template = {x: False for x in keys}
data = []
for record in self.search([("type", "=", "field")]):
repre = template.copy()
repre.update(
{
"module": record.module,
"model": record.model,
"field": record.field,
"mode": record.mode,
}
)
repre.update({x.name: x.value for x in record.attribute_ids})
if repre["table"]:
repre.update(
{
"column1": self.env[repre["model"]]
._fields[repre["field"]]
.column1,
"column2": self.env[repre["model"]]
._fields[repre["field"]]
.column2,
}
)
data.append(repre)
return data
@api.model
def list_modules(self):
"""Return the set of covered modules"""
self.env.cr.execute(
"""SELECT DISTINCT(module) FROM upgrade_record
ORDER BY module"""
)
return [module for module, in self.env.cr.fetchall()]
@staticmethod
def _read_manifest(addon_dir):
for manifest_name in MANIFEST_NAMES:
if os.access(os.path.join(addon_dir, manifest_name), os.R_OK):
with open(os.path.join(addon_dir, manifest_name), "r") as f:
manifest_string = f.read()
return ast.literal_eval(manifest_string)
raise ValidationError(
_("No manifest found in %(addon_dir)s") % {"addon_dir": addon_dir}
)
@api.model
def get_xml_records(self, module):
"""Return all XML records from the given module"""
addon_dir = get_module_path(module)
manifest = self._read_manifest(addon_dir)
# The order of the keys are important.
# Load files in the same order as in
# module/loading.py:load_module_graph
files = []
for key in ["init_xml", "update_xml", "data"]:
if not manifest.get(key):
continue
for xml_file in manifest[key]:
if not xml_file.lower().endswith(".xml"):
continue
parts = xml_file.split("/")
try:
with open(os.path.join(addon_dir, *parts), "r") as xml_handle:
files.append(xml_handle.read())
except UnicodeDecodeError:
_logger.warning(
"Encoding error: Unable to read %s",
os.path.join(addon_dir, *parts),
)
continue
return files