You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
4.5 KiB

  1. # Copyright (C) 2019-Today: GRAP (<http://www.grap.coop/>)
  2. # @author: Sylvain LE GAL (https://twitter.com/legalsylvain)
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. import json
  5. import logging
  6. import os
  7. import subprocess
  8. from odoo import api, fields, models
  9. from odoo.tools.safe_eval import safe_eval
  10. from odoo.modules.module import get_module_path
  11. _logger = logging.getLogger(__name__)
  12. class IrModuleModule(models.Model):
  13. _inherit = 'ir.module.module'
  14. author_ids = fields.Many2many(
  15. string='Authors', comodel_name='ir.module.author', readonly=True)
  16. module_type_id = fields.Many2one(
  17. string='Module Type', comodel_name='ir.module.type', readonly=True)
  18. python_lines_qty = fields.Integer(string='Python Lines', readonly=True)
  19. xml_lines_qty = fields.Integer(string='XML Lines', readonly=True)
  20. js_lines_qty = fields.Integer(string='JS Lines', readonly=True)
  21. css_lines_qty = fields.Integer(string='CSS Lines', readonly=True)
  22. @api.model
  23. def update_list(self):
  24. res = super(IrModuleModule, self).update_list()
  25. if self.env.context.get('analyze_installed_modules', False):
  26. self.search([('state', '=', 'installed')]).button_analyze_code()
  27. return res
  28. @api.multi
  29. def write(self, vals):
  30. res = super(IrModuleModule, self).write(vals)
  31. if vals.get('state', False) == 'installed':
  32. self.button_analyze_code()
  33. elif vals.get('state', False) == 'uninstalled':
  34. self.write({
  35. 'author_ids': [6, 0, []],
  36. 'module_type_id': False,
  37. 'python_lines_qty': False,
  38. 'xml_lines_qty': 0,
  39. 'js_lines_qty': 0,
  40. 'css_lines_qty': 0,
  41. })
  42. return res
  43. @api.multi
  44. def button_analyze_code(self):
  45. IrModuleAuthor = self.env['ir.module.author']
  46. IrModuleTypeRule = self.env['ir.module.type.rule']
  47. rules = IrModuleTypeRule.search([])
  48. exclude_dir = "lib,description,tests,demo"
  49. include_lang = self._get_analyzed_languages()
  50. for module in self:
  51. _logger.info("Analyzing Code for module %s" % (module.name))
  52. # Update Authors, based on manifest key
  53. authors = []
  54. if module.author and module.author[0] == '[':
  55. author_txt_list = safe_eval(module.author)
  56. else:
  57. author_txt_list = module.author.split(',')
  58. author_txt_list = [x.strip() for x in author_txt_list]
  59. author_txt_list = [x for x in author_txt_list if x]
  60. for author_txt in author_txt_list:
  61. authors.append(IrModuleAuthor._get_or_create(author_txt))
  62. author_ids = [x.id for x in authors]
  63. module.author_ids = author_ids
  64. # Update Module Type, based on rules
  65. module_type_id = rules._get_module_type_id_from_module(module)
  66. module.module_type_id = module_type_id
  67. # Get Path of module folder and parse the code
  68. path = get_module_path(module.name)
  69. try:
  70. command = [
  71. 'cloc',
  72. '--exclude-dir=%s' % (exclude_dir),
  73. '--skip-uniqueness',
  74. '--include-lang=%s' % (include_lang),
  75. '--not-match-f="__openerp__.py|__manifest__.py"',
  76. '--json',
  77. os.path.join(path)]
  78. temp = subprocess.Popen(command, stdout=subprocess.PIPE)
  79. bytes_output = temp.communicate()
  80. output = bytes_output[0].decode("utf-8").replace('\n', '')
  81. json_res = json.loads(output)
  82. values = self._prepare_values_from_json(json_res)
  83. module.write(values)
  84. except Exception as e:
  85. _logger.warning(
  86. 'Failed to execute the cloc command on module %s',
  87. module.name, e.message())
  88. @api.model
  89. def _get_analyzed_languages(self):
  90. "Overload the function to add extra languages to analyze"
  91. return "Python,XML,JavaScript,CSS"
  92. @api.model
  93. def _prepare_values_from_json(self, json_value):
  94. return {
  95. 'python_lines_qty': json_value.get('Python', {}).get('code', 0),
  96. 'xml_lines_qty': json_value.get('XML', {}).get('code', 0),
  97. 'js_lines_qty': json_value.get('JavaScript', {}).get('code', 0),
  98. 'css_lines_qty': json_value.get('CSS', {}).get('code', 0),
  99. }