mirror of
https://github.com/bringout/oca-technical.git
synced 2026-04-18 12:52:05 +02:00
Initial commit: OCA Technical packages (595 packages)
This commit is contained in:
commit
2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions
|
|
@ -0,0 +1,4 @@
|
|||
from . import ir_module_author
|
||||
from . import ir_module_module
|
||||
from . import ir_module_type
|
||||
from . import ir_module_type_rule
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
# Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class IrModuleAuthor(models.Model):
|
||||
_name = "ir.module.author"
|
||||
_description = "Modules Authors"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
|
||||
installed_module_ids = fields.Many2many(
|
||||
string="Modules",
|
||||
comodel_name="ir.module.module",
|
||||
relation="ir_module_module_author_rel",
|
||||
)
|
||||
|
||||
installed_module_qty = fields.Integer(
|
||||
string="Installed Modules Quantity",
|
||||
compute="_compute_installed_module_qty",
|
||||
store=True,
|
||||
)
|
||||
|
||||
_sql_constraints = [
|
||||
(
|
||||
"name_uniq",
|
||||
"unique(name)",
|
||||
"The name of the modules author should be unique per database!",
|
||||
),
|
||||
]
|
||||
|
||||
@api.depends("installed_module_ids")
|
||||
def _compute_installed_module_qty(self):
|
||||
for author in self:
|
||||
author.installed_module_qty = len(author.installed_module_ids)
|
||||
|
||||
@api.model
|
||||
def _get_or_create(self, name):
|
||||
authors = self.search([("name", "=", name)])
|
||||
if authors:
|
||||
return authors[0]
|
||||
else:
|
||||
return self.create({"name": name})
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
# Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from pygount import SourceAnalysis
|
||||
|
||||
from odoo import api, fields, models
|
||||
from odoo.modules.module import get_module_path
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class IrModuleModule(models.Model):
|
||||
_inherit = "ir.module.module"
|
||||
|
||||
author_ids = fields.Many2many(
|
||||
string="Authors",
|
||||
comodel_name="ir.module.author",
|
||||
readonly=True,
|
||||
relation="ir_module_module_author_rel",
|
||||
)
|
||||
|
||||
module_type_id = fields.Many2one(
|
||||
string="Module Type", comodel_name="ir.module.type", readonly=True
|
||||
)
|
||||
|
||||
python_code_qty = fields.Integer(string="Python Code Quantity", readonly=True)
|
||||
|
||||
xml_code_qty = fields.Integer(string="XML Code Quantity", readonly=True)
|
||||
|
||||
js_code_qty = fields.Integer(string="JS Code Quantity", readonly=True)
|
||||
|
||||
css_code_qty = fields.Integer(string="CSS Code Quantity", readonly=True)
|
||||
scss_code_qty = fields.Integer(string="SCSS Code Quantity", readonly=True)
|
||||
|
||||
# Overloadable Section
|
||||
@api.model
|
||||
def _get_analyse_settings(self):
|
||||
"""Return a dictionnary of data analysed
|
||||
Overload this function if you want to analyse other data
|
||||
{
|
||||
'extension': {
|
||||
'data_to_analyse': 'field_name',
|
||||
},
|
||||
}, [...]
|
||||
extension: extension of the file, with the '.'
|
||||
data_to_analyse : possible value : code, documentation, empty, string
|
||||
field_name: Odoo field name to store the analysis
|
||||
"""
|
||||
return {
|
||||
".py": {"code": "python_code_qty"},
|
||||
".xml": {"code": "xml_code_qty"},
|
||||
".js": {"code": "js_code_qty"},
|
||||
".css": {"code": "css_code_qty"},
|
||||
".scss": {"code": "scss_code_qty"},
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _get_clean_analyse_values(self):
|
||||
"""List of fields to unset when a module is uninstalled"""
|
||||
return {
|
||||
"author_ids": [(6, 0, [])],
|
||||
"module_type_id": False,
|
||||
"python_code_qty": False,
|
||||
"xml_code_qty": 0,
|
||||
"js_code_qty": 0,
|
||||
"css_code_qty": 0,
|
||||
"scss_code_qty": 0,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _get_module_encoding(self, file_ext):
|
||||
return "utf-8"
|
||||
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
if vals.get("state", False) == "uninstalled" and "module_analysis" not in [
|
||||
x.name for x in self
|
||||
]:
|
||||
self.write(self._get_clean_analyse_values())
|
||||
return res
|
||||
|
||||
# Public Section
|
||||
def button_analyse_code(self):
|
||||
self._analyse_code()
|
||||
|
||||
@api.model
|
||||
def cron_analyse_code(self, domain=None):
|
||||
if domain is None:
|
||||
domain = [("state", "=", "installed")]
|
||||
self.search(domain)._analyse_code()
|
||||
|
||||
# Custom Section
|
||||
def _analyse_code(self):
|
||||
IrModuleAuthor = self.env["ir.module.author"]
|
||||
IrModuleTypeRule = self.env["ir.module.type.rule"]
|
||||
rules = IrModuleTypeRule.search([])
|
||||
|
||||
cfg = self.env["ir.config_parameter"]
|
||||
val = cfg.get_param("module_analysis.exclude_directories", "")
|
||||
exclude_directories = [x.strip() for x in val.split(",") if x.strip()]
|
||||
val = cfg.get_param("module_analysis.exclude_files", "")
|
||||
exclude_files = [x.strip() for x in val.split(",") if x.strip()]
|
||||
|
||||
for module in self:
|
||||
_logger.info("Analysing Code for module %s ..." % (module.name))
|
||||
|
||||
# Update Authors, based on manifest key
|
||||
authors = []
|
||||
if module.author and module.author[0] == "[":
|
||||
author_txt_list = safe_eval(module.author)
|
||||
else:
|
||||
author_txt_list = (module.author and module.author.split(",")) or []
|
||||
|
||||
author_txt_list = [x.strip() for x in author_txt_list]
|
||||
author_txt_list = [x for x in author_txt_list if x]
|
||||
for author_txt in author_txt_list:
|
||||
authors.append(IrModuleAuthor._get_or_create(author_txt))
|
||||
|
||||
author_ids = [x.id for x in authors]
|
||||
module.author_ids = author_ids
|
||||
|
||||
# Update Module Type, based on rules
|
||||
module_type_id = rules._get_module_type_id_from_module(module)
|
||||
module.module_type_id = module_type_id
|
||||
|
||||
# Get Path of module folder and parse the code
|
||||
module_path = get_module_path(module.name)
|
||||
|
||||
# Get Files
|
||||
analysed_datas = self._get_analyse_data_dict()
|
||||
file_extensions = analysed_datas.keys()
|
||||
file_list = self._get_files_to_analyse(
|
||||
module_path, file_extensions, exclude_directories, exclude_files
|
||||
)
|
||||
|
||||
for file_path, file_ext in file_list:
|
||||
file_res = SourceAnalysis.from_file(
|
||||
file_path, "", encoding=self._get_module_encoding(file_ext)
|
||||
)
|
||||
for k, v in analysed_datas.get(file_ext).items():
|
||||
v["value"] += getattr(file_res, k)
|
||||
|
||||
# Update the module with the datas
|
||||
values = {}
|
||||
for analyses in analysed_datas.values():
|
||||
for v in analyses.values():
|
||||
values[v["field"]] = v["value"]
|
||||
module.write(values)
|
||||
|
||||
@api.model
|
||||
def _get_files_to_analyse(
|
||||
self, path, file_extensions, exclude_directories, exclude_files
|
||||
):
|
||||
res = []
|
||||
if not path:
|
||||
return res
|
||||
for root, _, files in os.walk(path, followlinks=True):
|
||||
if set(Path(root).relative_to(path).parts) & set(exclude_directories):
|
||||
continue
|
||||
for name in files:
|
||||
if name in exclude_files:
|
||||
continue
|
||||
filename, file_extension = os.path.splitext(name)
|
||||
if file_extension in file_extensions:
|
||||
res.append((os.path.join(root, name), file_extension))
|
||||
return res
|
||||
|
||||
@api.model
|
||||
def _get_analyse_data_dict(self):
|
||||
res_dict = self._get_analyse_settings().copy()
|
||||
for analyse_dict in res_dict.values():
|
||||
for analyse_type, v in analyse_dict.items():
|
||||
analyse_dict[analyse_type] = {"field": v, "value": 0}
|
||||
return res_dict
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
# Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import api, fields, models
|
||||
|
||||
|
||||
class IrModuleType(models.Model):
|
||||
_name = "ir.module.type"
|
||||
_description = "Modules Types"
|
||||
_order = "sequence"
|
||||
|
||||
name = fields.Char(required=True)
|
||||
|
||||
sequence = fields.Integer()
|
||||
|
||||
installed_module_ids = fields.One2many(
|
||||
string="Installed Modules",
|
||||
comodel_name="ir.module.module",
|
||||
inverse_name="module_type_id",
|
||||
)
|
||||
|
||||
installed_module_qty = fields.Integer(
|
||||
string="Modules Quantity", compute="_compute_installed_module_qty", store=True
|
||||
)
|
||||
|
||||
@api.depends("installed_module_ids.module_type_id")
|
||||
def _compute_installed_module_qty(self):
|
||||
for module_type in self:
|
||||
module_type.installed_module_qty = len(module_type.installed_module_ids)
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
# Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
|
||||
# @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
|
||||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
from odoo import fields, models
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
|
||||
class IrModuleType(models.Model):
|
||||
_name = "ir.module.type.rule"
|
||||
_description = "Modules Types Rules"
|
||||
_order = "sequence"
|
||||
|
||||
sequence = fields.Integer()
|
||||
|
||||
module_domain = fields.Char(required=True, default="[]")
|
||||
|
||||
module_type_id = fields.Many2one(
|
||||
string="Module type", comodel_name="ir.module.type", required=True
|
||||
)
|
||||
|
||||
def _get_module_type_id_from_module(self, module):
|
||||
IrModuleModule = self.env["ir.module.module"]
|
||||
for rule in self:
|
||||
domain = safe_eval(rule.module_domain)
|
||||
domain.append(("id", "=", module.id))
|
||||
if IrModuleModule.search(domain):
|
||||
return rule.module_type_id.id
|
||||
return False
|
||||
Loading…
Add table
Add a link
Reference in a new issue