Example #1
0
    def _check_xml(self, cr, uid, ids, context=None):
        if context is None:
            context = {}
        context = dict(context, check_view_ids=ids)

        # Sanity checks: the view should not break anything upon rendering!
        # Any exception raised below will cause a transaction rollback.
        for view in self.browse(cr, uid, ids, context):
            view_def = self.read_combined(cr, uid, view.id, None, context=context)
            view_arch_utf8 = view_def['arch']
            if view.type != 'qweb':
                view_doc = etree.fromstring(view_arch_utf8)
                # verify that all fields used are valid, etc.
                self.postprocess_and_fields(cr, uid, view.model, view_doc, view.id, context=context)
                # RNG-based validation is not possible anymore with 7.0 forms
                view_docs = [view_doc]
                if view_docs[0].tag == 'data':
                    # A <data> element is a wrapper for multiple root nodes
                    view_docs = view_docs[0]
                validator = self._relaxng()
                for view_arch in view_docs:
                    version = view_arch.get('version', '7.0')
                    if parse_version(version) < parse_version('7.0') and validator and not validator.validate(view_arch):
                        for error in validator.error_log:
                            _logger.error(tools.ustr(error))
                        return False
                    if not valid_view(view_arch):
                        return False
        return True
Example #2
0
 def download(self, cr, uid, ids, download=True, context=None):
     res = []
     default_version = modules.adapt_version('1.0')
     for mod in self.browse(cr, uid, ids, context=context):
         if not mod.url:
             continue
         match = re.search('-([a-zA-Z0-9\._-]+)(\.zip)', mod.url, re.I)
         version = default_version
         if match:
             version = match.group(1)
         if parse_version(mod.installed_version) >= parse_version(version):
             continue
         res.append(mod.url)
         if not download:
             continue
         zip_content = urllib.urlopen(mod.url).read()
         fname = modules.get_module_path(str(mod.name) + '.zip', downloaded=True)
         try:
             with open(fname, 'wb') as fp:
                 fp.write(zip_content)
         except Exception:
             _logger.exception('Error when trying to create module '
                               'file %s', fname)
             raise orm.except_orm(_('Error'), _('Can not create the module file:\n %s') % (fname,))
         terp = self.get_module_info(mod.name)
         self.write(cr, uid, mod.id, self.get_values_from_terp(terp))
         cr.execute('DELETE FROM ir_module_module_dependency WHERE module_id = %s', (mod.id,))
         self._update_dependencies(cr, uid, mod, terp.get('depends', []))
         self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized'))
         # Import module
         zimp = zipimport.zipimporter(fname)
         zimp.load_module(mod.name)
     return res
Example #3
0
    def update_list(self, cr, uid, context=None):
        res = [0, 0]  # [update, add]

        default_version = modules.adapt_version("1.0")
        known_mods = self.browse(cr, uid, self.search(cr, uid, []))
        known_mods_names = dict([(m.name, m) for m in known_mods])

        # iterate through detected modules and update/create them in db
        for mod_name in modules.get_modules():
            mod = known_mods_names.get(mod_name)
            terp = self.get_module_info(mod_name)
            values = self.get_values_from_terp(terp)

            if mod:
                updated_values = {}
                for key in values:
                    old = getattr(mod, key)
                    updated = isinstance(values[key], basestring) and tools.ustr(values[key]) or values[key]
                    if (old or updated) and updated != old:
                        updated_values[key] = values[key]
                if terp.get("installable", True) and mod.state == "uninstallable":
                    updated_values["state"] = "uninstalled"
                if parse_version(terp.get("version", default_version)) > parse_version(
                    mod.latest_version or default_version
                ):
                    res[0] += 1
                if updated_values:
                    self.write(cr, uid, mod.id, updated_values)
            else:
                mod_path = modules.get_module_path(mod_name)
                if not mod_path:
                    continue
                if not terp or not terp.get("installable", True):
                    continue
                id = self.create(cr, uid, dict(name=mod_name, state="uninstalled", **values))
                mod = self.browse(cr, uid, id)
                res[1] += 1

            self._update_dependencies(cr, uid, mod, terp.get("depends", []))
            self._update_category(cr, uid, mod, terp.get("category", "Uncategorized"))

        # Trigger load_addons if new module have been discovered it exists on
        # wsgi handlers, so they can react accordingly
        if tuple(res) != (0, 0):
            for handler in openerp.service.wsgi_server.module_handlers:
                if hasattr(handler, "load_addons"):
                    handler.load_addons()

        return res
Example #4
0
 def parse(self, incoming):
     if isinstance(incoming, OpenERPVersion):
         self.vstring = incoming.vstring
         self.components = incoming.components
     else:
         self.vstring = incoming
         self.components = parse_version(incoming)
Example #5
0
        def _get_migration_versions(pkg):
            def __get_dir(tree):
                return [d for d in tree if tree[d] is not None]

            versions = list(set(
                __get_dir(self.migrations[pkg.name]['module']) +
                __get_dir(self.migrations[pkg.name]['maintenance'])
            ))
            versions.sort(key=lambda k: parse_version(convert_version(k)))
            return versions
Example #6
0
    def update_list(self, cr, uid, context=None):
        res = [0, 0]  # [update, add]

        default_version = modules.adapt_version("1.0")
        known_mods = self.browse(cr, uid, self.search(cr, uid, []))
        known_mods_names = dict([(m.name, m) for m in known_mods])

        # iterate through detected modules and update/create them in db
        for mod_name in modules.get_modules():
            mod = known_mods_names.get(mod_name)
            terp = self.get_module_info(mod_name)
            values = self.get_values_from_terp(terp)

            if mod:
                updated_values = {}
                for key in values:
                    old = getattr(mod, key)
                    updated = isinstance(values[key], basestring) and tools.ustr(values[key]) or values[key]
                    if (old or updated) and updated != old:
                        updated_values[key] = values[key]
                if terp.get("installable", True) and mod.state == "uninstallable":
                    updated_values["state"] = "uninstalled"
                if parse_version(terp.get("version", default_version)) > parse_version(
                    mod.latest_version or default_version
                ):
                    res[0] += 1
                if updated_values:
                    self.write(cr, uid, mod.id, updated_values)
            else:
                mod_path = modules.get_module_path(mod_name)
                if not mod_path:
                    continue
                if not terp or not terp.get("installable", True):
                    continue
                id = self.create(cr, uid, dict(name=mod_name, state="uninstalled", **values))
                mod = self.browse(cr, uid, id)
                res[1] += 1

            self._update_dependencies(cr, uid, mod, terp.get("depends", []))
            self._update_category(cr, uid, mod, terp.get("category", "Uncategorized"))

        return res
Example #7
0
def patch():
    """ Monkey patch Odoo to discover addons from the odoo_addons namespace """
    version = openerp.cli.server.__version__
    if parse_version(version) < parse_version('8.0'):
        raise RuntimeError("Unsupported Odoo version %s" % version)

    # monkey-patch sys path for autodiscovery of addons

    initialize_sys_path_orig = openerp.modules.module.initialize_sys_path

    def initialize_sys_path_odoo_addons():
        initialize_sys_path_orig()

        ad_paths = openerp.modules.module.ad_paths

        try:
            # explicit workaround for https://github.com/pypa/pip/issues/3 and
            # https://github.com/pypa/setuptools/issues/250 (it sort of works
            # without this but I'm not sure why, so better be safe)
            pkg_resources.declare_namespace('odoo_addons')

            for ad in __import__('odoo_addons').__path__:
                ad = os.path.abspath(ad)
                if ad not in ad_paths:
                    ad_paths.append(ad)
        except ImportError:
            # odoo_addons is not provided by any distribution
            pass

    openerp.modules.module.initialize_sys_path = initialize_sys_path_odoo_addons

    # monkey-patch long_polling_spawn to launch the autodiscover version

    def long_polling_spawn(self):
        nargs = stripped_sys_argv()
        cmd = nargs[0]
        cmd = os.path.join(os.path.dirname(cmd), "openerp-gevent-autodiscover")
        nargs[0] = cmd
        popen = subprocess.Popen([sys.executable] + nargs)
        self.long_polling_pid = popen.pid

    openerp.service.server.PreforkServer.long_polling_spawn = long_polling_spawn
Example #8
0
    def update_list(self, cr, uid, context=None):
        res = [0, 0] # [update, add]

        known_mods = self.browse(cr, uid, self.search(cr, uid, []))
        known_mods_names = dict([(m.name, m) for m in known_mods])

        # iterate through detected modules and update/create them in db
        for mod_name in modules.get_modules():
            mod = known_mods_names.get(mod_name)
            terp = self.get_module_info(mod_name)
            values = self.get_values_from_terp(terp)

            if mod:
                updated_values = {}
                for key in values:
                    old = getattr(mod, key)
                    updated = isinstance(values[key], basestring) and tools.ustr(values[key]) or values[key]
                    if not old == updated:
                        updated_values[key] = values[key]
                if terp.get('installable', True) and mod.state == 'uninstallable':
                    updated_values['state'] = 'uninstalled'
                if parse_version(terp.get('version', '')) > parse_version(mod.latest_version or ''):
                    res[0] += 1
                if updated_values:
                    self.write(cr, uid, mod.id, updated_values)
            else:
                mod_path = modules.get_module_path(mod_name)
                if not mod_path:
                    continue
                if not terp or not terp.get('installable', True):
                    continue
                id = self.create(cr, uid, dict(name=mod_name, state='uninstalled', **values))
                mod = self.browse(cr, uid, id)
                res[1] += 1

            self._update_dependencies(cr, uid, mod, terp.get('depends', []))
            self._update_category(cr, uid, mod, terp.get('category', 'Uncategorized'))

        return res
Example #9
0
    def migrate_module(self, pkg, stage):
        assert stage in ('pre', 'post')
        stageformat = {
            'pre': '[>%s]',
            'post': '[%s>]',
        }

        if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade'):
            return

        def convert_version(version):
            if version.startswith(release.major_version) and version != release.major_version:
                return version  # the version number already containt the server version
            return "%s.%s" % (release.major_version, version)

        def _get_migration_versions(pkg):
            def __get_dir(tree):
                return [d for d in tree if tree[d] is not None]

            versions = list(set(
                __get_dir(self.migrations[pkg.name]['module']) +
                __get_dir(self.migrations[pkg.name]['maintenance'])
            ))
            versions.sort(key=lambda k: parse_version(convert_version(k)))
            return versions

        def _get_migration_files(pkg, version, stage):
            """ return a list of tuple (module, file)
            """
            m = self.migrations[pkg.name]
            lst = []

            mapping = {
                'module': opj(pkg.name, 'migrations'),
                'maintenance': opj('base', 'maintenance', 'migrations', pkg.name),
            }

            for x in mapping.keys():
                if version in m[x]:
                    for f in m[x][version]:
                        if m[x][version][f] is not None:
                            continue
                        if not f.startswith(stage + '-'):
                            continue
                        lst.append(opj(mapping[x], version, f))
            lst.sort()
            return lst

        def mergedict(a, b):
            a = a.copy()
            a.update(b)
            return a

        from openerp.tools.parse_version import parse_version

        parsed_installed_version = parse_version(pkg.installed_version or '')
        current_version = parse_version(convert_version(pkg.data['version']))

        versions = _get_migration_versions(pkg)

        for version in versions:
            if parsed_installed_version < parse_version(convert_version(version)) <= current_version:

                strfmt = {'addon': pkg.name,
                          'stage': stage,
                          'version': stageformat[stage] % version,
                          }

                for pyfile in _get_migration_files(pkg, version, stage):
                    name, ext = os.path.splitext(os.path.basename(pyfile))
                    if ext.lower() != '.py':
                        continue
                    mod = fp = fp2 = None
                    try:
                        fp = tools.file_open(pyfile)

                        # imp.load_source need a real file object, so we create
                        # one from the file-like object we get from file_open
                        fp2 = os.tmpfile()
                        fp2.write(fp.read())
                        fp2.seek(0)
                        try:
                            mod = imp.load_source(name, pyfile, fp2)
                            _logger.info('module %(addon)s: Running migration %(version)s %(name)s' % mergedict({'name': mod.__name__}, strfmt))
                            migrate = mod.migrate
                        except ImportError:
                            _logger.exception('module %(addon)s: Unable to load %(stage)s-migration file %(file)s' % mergedict({'file': pyfile}, strfmt))
                            raise
                        except AttributeError:
                            _logger.error('module %(addon)s: Each %(stage)s-migration file must have a "migrate(cr, installed_version)" function' % strfmt)
                        else:
                            migrate(self.cr, pkg.installed_version)
                    finally:
                        if fp:
                            fp.close()
                        if fp2:
                            fp2.close()
                        if mod:
                            del mod
Example #10
0
    def migrate_module(self, pkg, stage):
        assert stage in ("pre", "post")
        stageformat = {"pre": "[>%s]", "post": "[%s>]"}

        if not (hasattr(pkg, "update") or pkg.state == "to upgrade"):
            return

        def convert_version(version):
            if version.startswith(release.major_version) and version != release.major_version:
                return version  # the version number already containt the server version
            return "%s.%s" % (release.major_version, version)

        def _get_migration_versions(pkg):
            def __get_dir(tree):
                return [d for d in tree if tree[d] is not None]

            versions = list(
                set(
                    __get_dir(self.migrations[pkg.name]["module"]) + __get_dir(self.migrations[pkg.name]["maintenance"])
                )
            )
            versions.sort(key=lambda k: parse_version(convert_version(k)))
            return versions

        def _get_migration_files(pkg, version, stage):
            """ return a list of tuple (module, file)
            """
            m = self.migrations[pkg.name]
            lst = []

            mapping = {
                "module": opj(pkg.name, "migrations"),
                "maintenance": opj("base", "maintenance", "migrations", pkg.name),
            }

            for x in mapping.keys():
                if version in m[x]:
                    for f in m[x][version]:
                        if m[x][version][f] is not None:
                            continue
                        if not f.startswith(stage + "-"):
                            continue
                        lst.append(opj(mapping[x], version, f))
            lst.sort()
            return lst

        def mergedict(a, b):
            a = a.copy()
            a.update(b)
            return a

        from openerp.tools.parse_version import parse_version

        parsed_installed_version = parse_version(pkg.installed_version or "")
        current_version = parse_version(convert_version(pkg.data["version"]))

        versions = _get_migration_versions(pkg)

        for version in versions:
            if parsed_installed_version < parse_version(convert_version(version)) <= current_version:

                strfmt = {"addon": pkg.name, "stage": stage, "version": stageformat[stage] % version}

                for pyfile in _get_migration_files(pkg, version, stage):
                    name, ext = os.path.splitext(os.path.basename(pyfile))
                    if ext.lower() != ".py":
                        continue
                    mod = fp = fp2 = None
                    try:
                        fp = tools.file_open(pyfile)

                        # imp.load_source need a real file object, so we create
                        # one from the file-like object we get from file_open
                        fp2 = os.tmpfile()
                        fp2.write(fp.read())
                        fp2.seek(0)
                        try:
                            mod = imp.load_source(name, pyfile, fp2)
                            logger.notifyChannel(
                                "migration",
                                netsvc.LOG_INFO,
                                "module %(addon)s: Running migration %(version)s %(name)s"
                                % mergedict({"name": mod.__name__}, strfmt),
                            )
                            mod.migrate(self.cr, pkg.installed_version)
                        except ImportError:
                            logger.notifyChannel(
                                "migration",
                                netsvc.LOG_ERROR,
                                "module %(addon)s: Unable to load %(stage)s-migration file %(file)s"
                                % mergedict({"file": pyfile}, strfmt),
                            )
                            raise
                        except AttributeError:
                            logger.notifyChannel(
                                "migration",
                                netsvc.LOG_ERROR,
                                'module %(addon)s: Each %(stage)s-migration file must have a "migrate(cr, installed_version)" function'
                                % strfmt,
                            )
                        except:
                            raise
                    finally:
                        if fp:
                            fp.close()
                        if fp2:
                            fp2.close()
                        if mod:
                            del mod
Example #11
0
    def migrate_module(self, pkg, stage):
        assert stage in ('pre', 'post')
        stageformat = {
            'pre': '[>%s]',
            'post': '[%s>]',
        }

        if not (hasattr(pkg, 'update')
                or pkg.state == 'to upgrade') or pkg.state == 'to install':
            return

        def convert_version(version):
            if version.count('.') >= 2:
                return version  # the version number already containt the server version
            return "%s.%s" % (release.major_version, version)

        def _get_migration_versions(pkg):
            def __get_dir(tree):
                return [d for d in tree if tree[d] is not None]

            versions = list(
                set(
                    __get_dir(self.migrations[pkg.name]['module']) +
                    __get_dir(self.migrations[pkg.name]['maintenance'])))
            versions.sort(key=lambda k: parse_version(convert_version(k)))
            return versions

        def _get_migration_files(pkg, version, stage):
            """ return a list of tuple (module, file)
            """
            m = self.migrations[pkg.name]
            lst = []

            mapping = {
                'module': opj(pkg.name, 'migrations'),
                'maintenance': opj('base', 'maintenance', 'migrations',
                                   pkg.name),
            }

            for x in list(mapping.keys()):
                if version in m[x]:
                    for f in m[x][version]:
                        if m[x][version][f] is not None:
                            continue
                        if not f.startswith(stage + '-'):
                            continue
                        lst.append(opj(mapping[x], version, f))
            lst.sort()
            return lst

        parsed_installed_version = parse_version(pkg.installed_version or '')
        current_version = parse_version(convert_version(pkg.data['version']))

        versions = _get_migration_versions(pkg)

        for version in versions:
            if parsed_installed_version < parse_version(
                    convert_version(version)) <= current_version:

                strfmt = {
                    'addon': pkg.name,
                    'stage': stage,
                    'version': stageformat[stage] % version,
                }

                for pyfile in _get_migration_files(pkg, version, stage):
                    name, ext = os.path.splitext(os.path.basename(pyfile))
                    if ext.lower() != '.py':
                        continue
                    mod = fp = fp2 = None
                    try:
                        fp, fname = tools.file_open(pyfile, pathinfo=True)

                        if not isinstance(fp, file):
                            # imp.load_source need a real file object, so we create
                            # one from the file-like object we get from file_open
                            fp2 = os.tmpfile()
                            fp2.write(fp.read())
                            fp2.seek(0)
                        try:
                            mod = imp.load_source(name, fname, fp2 or fp)
                            _logger.info(
                                'module %(addon)s: Running migration %(version)s %(name)s'
                                % dict(strfmt, name=mod.__name__))
                            migrate = mod.migrate
                        except ImportError:
                            _logger.exception(
                                'module %(addon)s: Unable to load %(stage)s-migration file %(file)s'
                                % dict(strfmt, file=pyfile))
                            raise
                        except AttributeError:
                            _logger.error(
                                'module %(addon)s: Each %(stage)s-migration file must have a "migrate(cr, installed_version)" function'
                                % strfmt)
                        else:
                            migrate(self.cr, pkg.installed_version)
                    finally:
                        if fp:
                            fp.close()
                        if fp2:
                            fp2.close()
                        if mod:
                            del mod
Example #12
0
    def migrate_module(self, pkg, stage):
        assert stage in ('pre', 'post')
        stageformat = {
            'pre': '[>%s]',
            'post': '[%s>]',
        }
        # In openupgrade, remove 'or pkg.installed_version is None'
        # We want to always pass in pre and post migration files and use a new
        # argument in the migrate decorator (explained in the docstring)
        # to decide if we want to do something if a new module is installed
        # during the migration.
        if not (hasattr(pkg, 'update') or pkg.state == 'to upgrade'):
            return

        def convert_version(version):
            if version.count('.') >= 2:
                return version  # the version number already containt the server version
            return "%s.%s" % (release.major_version, version)

        def _get_migration_versions(pkg):
            def __get_dir(tree):
                return [d for d in tree if tree[d] is not None]

            versions = list(
                set(
                    __get_dir(self.migrations[pkg.name]['module']) +
                    __get_dir(self.migrations[pkg.name]['maintenance'])))
            versions.sort(key=lambda k: parse_version(convert_version(k)))
            return versions

        def _get_migration_files(pkg, version, stage):
            """ return a list of tuple (module, file)
            """
            m = self.migrations[pkg.name]
            lst = []

            mapping = {
                'module': opj(pkg.name, 'migrations'),
                'maintenance': opj('base', 'maintenance', 'migrations',
                                   pkg.name),
            }

            for x in mapping.keys():
                if version in m[x]:
                    for f in m[x][version]:
                        if m[x][version][f] is not None:
                            continue
                        if not f.startswith(stage + '-'):
                            continue
                        lst.append(opj(mapping[x], version, f))
            lst.sort()
            return lst

        def mergedict(a, b):
            a = a.copy()
            a.update(b)
            return a

        parsed_installed_version = parse_version(pkg.installed_version or '')
        current_version = parse_version(convert_version(pkg.data['version']))

        versions = _get_migration_versions(pkg)

        for version in versions:
            if parsed_installed_version < parse_version(
                    convert_version(version)) <= current_version:

                strfmt = {
                    'addon': pkg.name,
                    'stage': stage,
                    'version': stageformat[stage] % version,
                }

                for pyfile in _get_migration_files(pkg, version, stage):
                    name, ext = os.path.splitext(os.path.basename(pyfile))
                    if ext.lower() != '.py':
                        continue
                    mod = fp = fp2 = None
                    try:
                        fp = tools.file_open(pyfile)

                        # imp.load_source need a real file object, so we create
                        # one from the file-like object we get from file_open
                        fp2 = os.tmpfile()
                        fp2.write(fp.read())
                        fp2.seek(0)
                        try:
                            mod = imp.load_source(name, pyfile, fp2)
                            _logger.info(
                                'module %(addon)s: Running migration %(version)s %(name)s',
                                mergedict({'name': mod.__name__}, strfmt))
                        except ImportError:
                            _logger.exception(
                                'module %(addon)s: Unable to load %(stage)s-migration file %(file)s',
                                mergedict({'file': pyfile}, strfmt))
                            raise

                        _logger.info(
                            'module %(addon)s: Running migration %(version)s %(name)s',
                            mergedict({'name': mod.__name__}, strfmt))

                        if hasattr(mod, 'migrate'):
                            mod.migrate(self.cr, pkg.installed_version)
                        else:
                            _logger.error(
                                'module %(addon)s: Each %(stage)s-migration file must have a "migrate(cr, installed_version)" function',
                                strfmt)
                    finally:
                        if fp:
                            fp.close()
                        if fp2:
                            fp2.close()
                        if mod:
                            del mod