diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py index 5bad5ea53ebbe83e66e01964789707c5d0fbe103..a28ee6bf429b1afdbe4cd5a1acfa02863238953d 100644 --- a/addons/base_import_module/models/ir_module.py +++ b/addons/base_import_module/models/ir_module.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- +import ast import base64 import logging +import lxml import os import sys import zipfile @@ -32,8 +34,17 @@ class IrModule(models.Model): values = self.get_values_from_terp(terp) unmet_dependencies = set(terp['depends']).difference(installed_mods) + if unmet_dependencies: - raise UserError(_("Unmet module dependencies: %s") % ', '.join(unmet_dependencies)) + if _is_studio_custom(path): + err = _("Studio customizations require Studio") + else: + err = _("Unmet module dependencies: %s") % ', '.join( + unmet_dependencies, + ) + raise UserError(err) + elif 'web_studio' not in installed_mods and _is_studio_custom(path): + raise UserError(_("Studio customizations require Studio")) mod = known_mods_names.get(module) if mod: @@ -52,7 +63,7 @@ class IrModule(models.Model): continue _logger.info("module %s: loading %s", module, filename) noupdate = False - if filename.endswith('.csv') and kind in ('init', 'init_xml'): + if ext == '.csv' and kind in ('init', 'init_xml'): noupdate = True pathname = opj(path, filename) idref = {} @@ -101,9 +112,9 @@ class IrModule(models.Model): raise UserError(_("File '%s' exceed maximum allowed file size") % zf.filename) with tempdir() as module_dir: - import odoo.modules as addons + import odoo.modules.module as module try: - addons.module.ad_paths.append(module_dir) + module.ad_paths.append(module_dir) z.extractall(module_dir) dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))] for mod_name in dirs: @@ -117,8 +128,38 @@ class IrModule(models.Model): _logger.exception('Error while importing module') errors[mod_name] = exception_to_unicode(e) finally: - addons.module.ad_paths.remove(module_dir) + module.ad_paths.remove(module_dir) r = ["Successfully imported module '%s'" % mod for mod in success] for mod, error in errors.items(): r.append("Error while importing module '%s': %r" % (mod, error)) return '\n'.join(r), module_names + + +def _is_studio_custom(path): + """ + Checks the to-be-imported records to see if there are any references to + studio, which would mean that the module was created using studio + + Returns True if any of the records contains a context with the key + studio in it, False if none of the records do + """ + path = os.path.join(path, 'data') + filenames = next(iter(os.walk(path)))[2] + filenames = [f for f in filenames if f.lower().endswith('.xml')] + + for filename in filenames: + root = lxml.etree.parse(os.path.join(path, filename)).getroot() + + for record in root: + # there might not be a context if it's a non-studio module + try: + # ast.literal_eval is like eval(), but safer + # context is a string representing a python dict + ctx = ast.literal_eval(record.get('context')) + # there are no cases in which studio is false + # so just checking for its existence is enough + if ctx and ctx.get('studio'): + return True + except Exception: + continue + return False