Esempio n. 1
0
def load_modules(db, force_demo=False, status=None, update_module=False):
    # TODO status['progress'] reporting is broken: used twice (and reset each
    # time to zero) in load_module_graph, not fine-grained enough.
    # It should be a method exposed by the registry.
    initialize_sys_path()

    force = []
    if force_demo:
        force.append('demo')

    cr = db.cursor()
    try:
        if not openerp.modules.db.is_initialized(cr):
            _logger.info("init db")
            openerp.modules.db.initialize(cr)
            tools.config["init"]["all"] = 1
            tools.config['update']['all'] = 1
            if not tools.config['without_demo']:
                tools.config["demo"]['all'] = 1

        # This is a brand new registry, just created in
        # openerp.modules.registry.RegistryManager.new().
        registry = openerp.registry(cr.dbname)

        if 'base' in tools.config['update'] or 'all' in tools.config['update']:
            cr.execute("update ir_module_module set state=%s where name=%s and state=%s", ('to upgrade', 'base', 'installed'))

        # STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps) 
        graph = openerp.modules.graph.Graph()
        graph.add_module(cr, 'base', force)
        if not graph:
            _logger.critical('module base cannot be loaded! (hint: verify addons-path)')
            raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))

        # processed_modules: for cleanup step after install
        # loaded_modules: to avoid double loading
        report = registry._assertion_report
        loaded_modules, processed_modules = load_module_graph(cr, graph, status, perform_checks=update_module, report=report)

        if tools.config['load_language']:
            for lang in tools.config['load_language'].split(','):
                tools.load_language(cr, lang)

        # STEP 2: Mark other modules to be loaded/updated
        if update_module:
            modobj = registry['ir.module.module']
            if ('base' in tools.config['init']) or ('base' in tools.config['update']):
                _logger.info('updating modules list')
                modobj.update_list(cr, SUPERUSER_ID)

            _check_module_names(cr, itertools.chain(tools.config['init'].keys(), tools.config['update'].keys()))

            mods = [k for k in tools.config['init'] if tools.config['init'][k]]
            if mods:
                ids = modobj.search(cr, SUPERUSER_ID, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
                if ids:
                    modobj.button_install(cr, SUPERUSER_ID, ids)

            mods = [k for k in tools.config['update'] if tools.config['update'][k]]
            if mods:
                ids = modobj.search(cr, SUPERUSER_ID, ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
                if ids:
                    modobj.button_upgrade(cr, SUPERUSER_ID, ids)

            cr.execute("update ir_module_module set state=%s where name=%s", ('installed', 'base'))


        # STEP 3: Load marked modules (skipping base which was done in STEP 1)
        # IMPORTANT: this is done in two parts, first loading all installed or
        #            partially installed modules (i.e. installed/to upgrade), to
        #            offer a consistent system to the second part: installing
        #            newly selected modules.
        #            We include the modules 'to remove' in the first step, because
        #            they are part of the "currently installed" modules. They will
        #            be dropped in STEP 6 later, before restarting the loading
        #            process.
        # IMPORTANT 2: We have to loop here until all relevant modules have been
        #              processed, because in some rare cases the dependencies have
        #              changed, and modules that depend on an uninstalled module
        #              will not be processed on the first pass.
        #              It's especially useful for migrations.
        previously_processed = -1
        while previously_processed < len(processed_modules):
            previously_processed = len(processed_modules)
            processed_modules += load_marked_modules(cr, graph,
                ['installed', 'to upgrade', 'to remove'],
                force, status, report, loaded_modules, update_module)
            if update_module:
                processed_modules += load_marked_modules(cr, graph,
                    ['to install'], force, status, report,
                    loaded_modules, update_module)

        # load custom models
        cr.execute('select model from ir_model where state=%s', ('manual',))
        for model in cr.dictfetchall():
            registry['ir.model'].instanciate(cr, SUPERUSER_ID, model['model'], {})

        # STEP 4: Finish and cleanup installations
        if processed_modules:
            cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
            for (model, name) in cr.fetchall():
                if model in registry and not registry[model].is_transient() and not isinstance(registry[model], openerp.osv.orm.AbstractModel):
                    _logger.warning('The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,,1,1,1,1',
                        model, model.replace('.', '_'), model.replace('.', '_'), model.replace('.', '_'))

            # Temporary warning while we remove access rights on osv_memory objects, as they have
            # been replaced by owner-only access rights
            cr.execute("""select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id""")
            for (model, name) in cr.fetchall():
                if model in registry and registry[model].is_transient():
                    _logger.warning('The transient model %s (%s) should not have explicit access rules!', model, name)

            cr.execute("SELECT model from ir_model")
            for (model,) in cr.fetchall():
                if model in registry:
                    registry[model]._check_removed_columns(cr, log=True)
                else:
                    _logger.warning("Model %s is declared but cannot be loaded! (Perhaps a module was partially removed or renamed)", model)

            # Cleanup orphan records
            registry['ir.model.data']._process_end(cr, SUPERUSER_ID, processed_modules)

        for kind in ('init', 'demo', 'update'):
            tools.config[kind] = {}

        cr.commit()

        # STEP 5: Cleanup menus 
        # Remove menu items that are not referenced by any of other
        # (child) menu item, ir_values, or ir_model_data.
        # TODO: This code could be a method of ir_ui_menu. Remove menu without actions of children
        if update_module:
            while True:
                cr.execute('''delete from
                        ir_ui_menu
                    where
                        (id not IN (select parent_id from ir_ui_menu where parent_id is not null))
                    and
                        (id not IN (select res_id from ir_values where model='ir.ui.menu'))
                    and
                        (id not IN (select res_id from ir_model_data where model='ir.ui.menu'))''')
                cr.commit()
                if not cr.rowcount:
                    break
                else:
                    _logger.info('removed %d unused menus', cr.rowcount)

        # STEP 6: Uninstall modules to remove
        if update_module:
            # Remove records referenced from ir_model_data for modules to be
            # removed (and removed the references from ir_model_data).
            cr.execute("SELECT name, id FROM ir_module_module WHERE state=%s", ('to remove',))
            modules_to_remove = dict(cr.fetchall())
            if modules_to_remove:
                pkgs = reversed([p for p in graph if p.name in modules_to_remove])
                for pkg in pkgs:
                    uninstall_hook = pkg.info.get('uninstall_hook')
                    if uninstall_hook:
                        py_module = sys.modules['openerp.addons.%s' % (pkg.name,)]
                        getattr(py_module, uninstall_hook)(cr, registry)

                registry['ir.module.module'].module_uninstall(cr, SUPERUSER_ID, modules_to_remove.values())
                # Recursive reload, should only happen once, because there should be no
                # modules to remove next time
                cr.commit()
                _logger.info('Reloading registry once more after uninstalling modules')
                return openerp.modules.registry.RegistryManager.new(cr.dbname, force_demo, status, update_module)

        # STEP 7: verify custom views on every model
        if update_module:
            Views = registry['ir.ui.view']
            custom_view_test = True
            for model in registry.models.keys():
                if not Views._validate_custom_views(cr, SUPERUSER_ID, model):
                    custom_view_test = False
                    _logger.error('invalid custom view(s) for model %s', model)
            report.record_result(custom_view_test)

        if report.failures:
            _logger.error('At least one test failed when loading the modules.')
        else:
            _logger.info('Modules loaded.')

        # STEP 8: call _register_hook on every model
        for model in registry.models.values():
            model._register_hook(cr)

        # STEP 9: Run the post-install tests
        cr.commit()

        t0 = time.time()
        t0_sql = openerp.sql_db.sql_counter
        if openerp.tools.config['test_enable']:
            cr.execute("SELECT name FROM ir_module_module WHERE state='installed'")
            for module_name in cr.fetchall():
                report.record_result(openerp.modules.module.run_unit_tests(module_name[0], cr.dbname, position=runs_post_install))
            _logger.log(25, "All post-tested in %.2fs, %s queries", time.time() - t0, openerp.sql_db.sql_counter - t0_sql)
    finally:
        cr.close()
Esempio n. 2
0
def load_modules(db, force_demo=False, status=None, update_module=False):
    initialize_sys_path()

    force = []
    if force_demo:
        force.append("demo")

    cr = db.cursor()
    try:
        if not openerp.modules.db.is_initialized(cr):
            _logger.info("init db")
            openerp.modules.db.initialize(cr)
            update_module = True  # process auto-installed modules
            tools.config["init"]["all"] = 1
            tools.config["update"]["all"] = 1
            if not tools.config["without_demo"]:
                tools.config["demo"]["all"] = 1

        # This is a brand new registry, just created in
        # openerp.modules.registry.RegistryManager.new().
        registry = openerp.registry(cr.dbname)

        if "base" in tools.config["update"] or "all" in tools.config["update"]:
            cr.execute(
                "update ir_module_module set state=%s where name=%s and state=%s", ("to upgrade", "base", "installed")
            )

        # STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
        graph = openerp.modules.graph.Graph()
        graph.add_module(cr, "base", force)
        if not graph:
            _logger.critical("module base cannot be loaded! (hint: verify addons-path)")
            raise ImportError("Module `base` cannot be loaded! (hint: verify addons-path)")

        # processed_modules: for cleanup step after install
        # loaded_modules: to avoid double loading
        report = registry._assertion_report
        loaded_modules, processed_modules = load_module_graph(
            cr, graph, status, perform_checks=update_module, report=report
        )

        if tools.config["load_language"] or update_module:
            # some base models are used below, so make sure they are set up
            registry.setup_models(cr, partial=True)

        if tools.config["load_language"]:
            for lang in tools.config["load_language"].split(","):
                tools.load_language(cr, lang)

        # STEP 2: Mark other modules to be loaded/updated
        if update_module:
            modobj = registry["ir.module.module"]
            if ("base" in tools.config["init"]) or ("base" in tools.config["update"]):
                _logger.info("updating modules list")
                modobj.update_list(cr, SUPERUSER_ID)

            _check_module_names(cr, itertools.chain(tools.config["init"].keys(), tools.config["update"].keys()))

            mods = [k for k in tools.config["init"] if tools.config["init"][k]]
            if mods:
                ids = modobj.search(cr, SUPERUSER_ID, ["&", ("state", "=", "uninstalled"), ("name", "in", mods)])
                if ids:
                    modobj.button_install(cr, SUPERUSER_ID, ids)

            mods = [k for k in tools.config["update"] if tools.config["update"][k]]
            if mods:
                ids = modobj.search(cr, SUPERUSER_ID, ["&", ("state", "=", "installed"), ("name", "in", mods)])
                if ids:
                    modobj.button_upgrade(cr, SUPERUSER_ID, ids)

            cr.execute("update ir_module_module set state=%s where name=%s", ("installed", "base"))
            modobj.invalidate_cache(cr, SUPERUSER_ID, ["state"])

        # STEP 3: Load marked modules (skipping base which was done in STEP 1)
        # IMPORTANT: this is done in two parts, first loading all installed or
        #            partially installed modules (i.e. installed/to upgrade), to
        #            offer a consistent system to the second part: installing
        #            newly selected modules.
        #            We include the modules 'to remove' in the first step, because
        #            they are part of the "currently installed" modules. They will
        #            be dropped in STEP 6 later, before restarting the loading
        #            process.
        # IMPORTANT 2: We have to loop here until all relevant modules have been
        #              processed, because in some rare cases the dependencies have
        #              changed, and modules that depend on an uninstalled module
        #              will not be processed on the first pass.
        #              It's especially useful for migrations.
        previously_processed = -1
        while previously_processed < len(processed_modules):
            previously_processed = len(processed_modules)
            processed_modules += load_marked_modules(
                cr,
                graph,
                ["installed", "to upgrade", "to remove"],
                force,
                status,
                report,
                loaded_modules,
                update_module,
            )
            if update_module:
                processed_modules += load_marked_modules(
                    cr, graph, ["to install"], force, status, report, loaded_modules, update_module
                )

        registry.setup_models(cr)

        # STEP 4: Finish and cleanup installations
        if processed_modules:
            cr.execute(
                """select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)"""
            )
            for (model, name) in cr.fetchall():
                if (
                    model in registry
                    and not registry[model].is_transient()
                    and not isinstance(registry[model], openerp.osv.orm.AbstractModel)
                ):
                    _logger.warning(
                        "The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,,1,0,0,0",
                        model,
                        model.replace(".", "_"),
                        model.replace(".", "_"),
                        model.replace(".", "_"),
                    )

            # Temporary warning while we remove access rights on osv_memory objects, as they have
            # been replaced by owner-only access rights
            cr.execute(
                """select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id"""
            )
            for (model, name) in cr.fetchall():
                if model in registry and registry[model].is_transient():
                    _logger.warning("The transient model %s (%s) should not have explicit access rules!", model, name)

            cr.execute("SELECT model from ir_model")
            for (model,) in cr.fetchall():
                if model in registry:
                    registry[model]._check_removed_columns(cr, log=True)
                else:
                    _logger.warning(
                        "Model %s is declared but cannot be loaded! (Perhaps a module was partially removed or renamed)",
                        model,
                    )

            # Cleanup orphan records
            registry["ir.model.data"]._process_end(cr, SUPERUSER_ID, processed_modules)

        for kind in ("init", "demo", "update"):
            tools.config[kind] = {}

        cr.commit()

        # STEP 5: Uninstall modules to remove
        if update_module:
            # Remove records referenced from ir_model_data for modules to be
            # removed (and removed the references from ir_model_data).
            cr.execute("SELECT name, id FROM ir_module_module WHERE state=%s", ("to remove",))
            modules_to_remove = dict(cr.fetchall())
            if modules_to_remove:
                pkgs = reversed([p for p in graph if p.name in modules_to_remove])
                for pkg in pkgs:
                    uninstall_hook = pkg.info.get("uninstall_hook")
                    if uninstall_hook:
                        py_module = sys.modules["openerp.addons.%s" % (pkg.name,)]
                        getattr(py_module, uninstall_hook)(cr, registry)

                registry["ir.module.module"].module_uninstall(cr, SUPERUSER_ID, modules_to_remove.values())
                # Recursive reload, should only happen once, because there should be no
                # modules to remove next time
                cr.commit()
                _logger.info("Reloading registry once more after uninstalling modules")
                openerp.api.Environment.reset()
                return openerp.modules.registry.RegistryManager.new(cr.dbname, force_demo, status, update_module)

        # STEP 6: verify custom views on every model
        if update_module:
            Views = registry["ir.ui.view"]
            custom_view_test = True
            for model in registry.models.keys():
                if not Views._validate_custom_views(cr, SUPERUSER_ID, model):
                    custom_view_test = False
                    _logger.error("invalid custom view(s) for model %s", model)
            report.record_result(custom_view_test)

        if report.failures:
            _logger.error("At least one test failed when loading the modules.")
        else:
            _logger.info("Modules loaded.")

        # STEP 8: call _register_hook on every model
        for model in registry.models.values():
            model._register_hook(cr)

        # STEP 9: Run the post-install tests
        cr.commit()

        t0 = time.time()
        t0_sql = openerp.sql_db.sql_counter
        if openerp.tools.config["test_enable"]:
            cr.execute("SELECT name FROM ir_module_module WHERE state='installed'")
            for module_name in cr.fetchall():
                report.record_result(
                    openerp.modules.module.run_unit_tests(module_name[0], cr.dbname, position=runs_post_install)
                )
            _logger.log(
                25, "All post-tested in %.2fs, %s queries", time.time() - t0, openerp.sql_db.sql_counter - t0_sql
            )
    finally:
        cr.close()
Esempio n. 3
0
def load_modules(db, force_demo=False, status=None, update_module=False):
    # TODO status['progress'] reporting is broken: used twice (and reset each
    # time to zero) in load_module_graph, not fine-grained enough.
    # It should be a method exposed by the pool.
    initialize_sys_path()

    open_openerp_namespace()

    force = []
    if force_demo:
        force.append('demo')

    cr = db.cursor()
    try:
        if not openerp.modules.db.is_initialized(cr):
            _logger.info("init db")
            openerp.modules.db.initialize(cr)
            tools.config["init"]["all"] = 1
            tools.config['update']['all'] = 1
            if not tools.config['without_demo']:
                tools.config["demo"]['all'] = 1

        # This is a brand new pool, just created in pooler.get_db_and_pool()
        pool = pooler.get_pool(cr.dbname)

        if 'base' in tools.config['update'] or 'all' in tools.config['update']:
            cr.execute("update ir_module_module set state=%s where name=%s and state=%s", ('to upgrade', 'base', 'installed'))

        # STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps) 
        graph = openerp.modules.graph.Graph()
        graph.add_module(cr, 'base', force)
        if not graph:
            _logger.critical('module base cannot be loaded! (hint: verify addons-path)')
            raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))

        # processed_modules: for cleanup step after install
        # loaded_modules: to avoid double loading
        report = pool._assertion_report
        loaded_modules, processed_modules = load_module_graph(cr, graph, status, perform_checks=update_module, report=report)

        if tools.config['load_language']:
            for lang in tools.config['load_language'].split(','):
                tools.load_language(cr, lang)

        # STEP 2: Mark other modules to be loaded/updated
        if update_module:
            modobj = pool.get('ir.module.module')
            if ('base' in tools.config['init']) or ('base' in tools.config['update']):
                _logger.info('updating modules list')
                modobj.update_list(cr, SUPERUSER_ID)

            _check_module_names(cr, itertools.chain(tools.config['init'].keys(), tools.config['update'].keys()))

            mods = [k for k in tools.config['init'] if tools.config['init'][k]]
            if mods:
                ids = modobj.search(cr, SUPERUSER_ID, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
                if ids:
                    modobj.button_install(cr, SUPERUSER_ID, ids)

            mods = [k for k in tools.config['update'] if tools.config['update'][k]]
            if mods:
                ids = modobj.search(cr, SUPERUSER_ID, ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
                if ids:
                    modobj.button_upgrade(cr, SUPERUSER_ID, ids)

            cr.execute("update ir_module_module set state=%s where name=%s", ('installed', 'base'))


        # STEP 3: Load marked modules (skipping base which was done in STEP 1)
        # IMPORTANT: this is done in two parts, first loading all installed or
        #            partially installed modules (i.e. installed/to upgrade), to
        #            offer a consistent system to the second part: installing
        #            newly selected modules.
        #            We include the modules 'to remove' in the first step, because
        #            they are part of the "currently installed" modules. They will
        #            be dropped in STEP 6 later, before restarting the loading
        #            process.
        states_to_load = ['installed', 'to upgrade', 'to remove']
        processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules, update_module)
        processed_modules.extend(processed)
        if update_module:
            states_to_load = ['to install']
            processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules, update_module)
            processed_modules.extend(processed)

        # load custom models
        cr.execute('select model from ir_model where state=%s', ('manual',))
        for model in cr.dictfetchall():
            pool.get('ir.model').instanciate(cr, SUPERUSER_ID, model['model'], {})

        # STEP 4: Finish and cleanup installations
        if processed_modules:
            cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
            for (model, name) in cr.fetchall():
                model_obj = pool.get(model)
                if model_obj and not model_obj.is_transient():
                    _logger.warning('The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,,1,1,1,1',
                        model, model.replace('.', '_'), model.replace('.', '_'), model.replace('.', '_'))

            # Temporary warning while we remove access rights on osv_memory objects, as they have
            # been replaced by owner-only access rights
            cr.execute("""select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id""")
            for (model, name) in cr.fetchall():
                model_obj = pool.get(model)
                if model_obj and model_obj.is_transient():
                    _logger.warning('The transient model %s (%s) should not have explicit access rules!', model, name)

            cr.execute("SELECT model from ir_model")
            for (model,) in cr.fetchall():
                obj = pool.get(model)
                if obj:
                    obj._check_removed_columns(cr, log=True)
                else:
                    _logger.warning("Model %s is declared but cannot be loaded! (Perhaps a module was partially removed or renamed)", model)

            # Cleanup orphan records
            pool.get('ir.model.data')._process_end(cr, SUPERUSER_ID, processed_modules)

        for kind in ('init', 'demo', 'update'):
            tools.config[kind] = {}

        cr.commit()

        # STEP 5: Cleanup menus 
        # Remove menu items that are not referenced by any of other
        # (child) menu item, ir_values, or ir_model_data.
        # TODO: This code could be a method of ir_ui_menu. Remove menu without actions of children
        if update_module:
            while True:
                cr.execute('''delete from
                        ir_ui_menu
                    where
                        (id not IN (select parent_id from ir_ui_menu where parent_id is not null))
                    and
                        (id not IN (select res_id from ir_values where model='ir.ui.menu'))
                    and
                        (id not IN (select res_id from ir_model_data where model='ir.ui.menu'))''')
                cr.commit()
                if not cr.rowcount:
                    break
                else:
                    _logger.info('removed %d unused menus', cr.rowcount)

        # STEP 6: Uninstall modules to remove
        if update_module:
            # Remove records referenced from ir_model_data for modules to be
            # removed (and removed the references from ir_model_data).
            cr.execute("SELECT id FROM ir_module_module WHERE state=%s", ('to remove',))
            mod_ids_to_remove = [x[0] for x in cr.fetchall()]
            if mod_ids_to_remove:
                pool.get('ir.module.module').module_uninstall(cr, SUPERUSER_ID, mod_ids_to_remove)
                # Recursive reload, should only happen once, because there should be no
                # modules to remove next time
                cr.commit()
                _logger.info('Reloading registry once more after uninstalling modules')
                return pooler.restart_pool(cr.dbname, force_demo, status, update_module)

        if report.failures:
            _logger.error('At least one test failed when loading the modules.')
        else:
            _logger.info('Modules loaded.')

        # STEP 7: call _register_hook on every model
        for model in pool.models.values():
            model._register_hook(cr)

    finally:
        cr.close()
Esempio n. 4
0
def load_modules(db, force_demo=False, status=None, update_module=False):
    # TODO status['progress'] reporting is broken: used twice (and reset each
    # time to zero) in load_module_graph, not fine-grained enough.
    # It should be a method exposed by the pool.
    initialize_sys_path()

    open_openerp_namespace()

    force = []
    if force_demo:
        force.append('demo')

    cr = db.cursor()
    try:
        if not openerp.modules.db.is_initialized(cr):
            _logger.info("init db")
            openerp.modules.db.initialize(cr)
            tools.config["init"]["all"] = 1
            tools.config['update']['all'] = 1
            if not tools.config['without_demo']:
                tools.config["demo"]['all'] = 1

        # This is a brand new pool, just created in pooler.get_db_and_pool()
        pool = pooler.get_pool(cr.dbname)

        if 'base' in tools.config['update'] or 'all' in tools.config['update']:
            cr.execute(
                "update ir_module_module set state=%s where name=%s and state=%s",
                ('to upgrade', 'base', 'installed'))

        # STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
        graph = openerp.modules.graph.Graph()
        graph.add_module(cr, 'base', force)
        if not graph:
            _logger.critical(
                'module base cannot be loaded! (hint: verify addons-path)')
            raise osv.osv.except_osv(
                _('Could not load base module'),
                _('module base cannot be loaded! (hint: verify addons-path)'))

        # processed_modules: for cleanup step after install
        # loaded_modules: to avoid double loading
        report = pool._assertion_report
        loaded_modules, processed_modules = load_module_graph(
            cr, graph, status, perform_checks=update_module, report=report)

        if tools.config['load_language']:
            for lang in tools.config['load_language'].split(','):
                tools.load_language(cr, lang)

        # STEP 2: Mark other modules to be loaded/updated
        if update_module:
            modobj = pool.get('ir.module.module')
            if ('base' in tools.config['init']) or ('base'
                                                    in tools.config['update']):
                _logger.info('updating modules list')
                modobj.update_list(cr, SUPERUSER_ID)

            _check_module_names(
                cr,
                itertools.chain(tools.config['init'].keys(),
                                tools.config['update'].keys()))

            mods = [k for k in tools.config['init'] if tools.config['init'][k]]
            if mods:
                ids = modobj.search(
                    cr, SUPERUSER_ID,
                    ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
                if ids:
                    modobj.button_install(cr, SUPERUSER_ID, ids)

            mods = [
                k for k in tools.config['update'] if tools.config['update'][k]
            ]
            if mods:
                ids = modobj.search(
                    cr, SUPERUSER_ID,
                    ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
                if ids:
                    modobj.button_upgrade(cr, SUPERUSER_ID, ids)

            cr.execute("update ir_module_module set state=%s where name=%s",
                       ('installed', 'base'))

        # STEP 3: Load marked modules (skipping base which was done in STEP 1)
        # IMPORTANT: this is done in two parts, first loading all installed or
        #            partially installed modules (i.e. installed/to upgrade), to
        #            offer a consistent system to the second part: installing
        #            newly selected modules.
        #            We include the modules 'to remove' in the first step, because
        #            they are part of the "currently installed" modules. They will
        #            be dropped in STEP 6 later, before restarting the loading
        #            process.
        states_to_load = ['installed', 'to upgrade', 'to remove']
        processed = load_marked_modules(cr, graph, states_to_load, force,
                                        status, report, loaded_modules,
                                        update_module)
        processed_modules.extend(processed)
        if update_module:
            states_to_load = ['to install']
            processed = load_marked_modules(cr, graph, states_to_load, force,
                                            status, report, loaded_modules,
                                            update_module)
            processed_modules.extend(processed)

        # load custom models
        cr.execute('select model from ir_model where state=%s', ('manual', ))
        for model in cr.dictfetchall():
            pool.get('ir.model').instanciate(cr, SUPERUSER_ID, model['model'],
                                             {})

        # STEP 4: Finish and cleanup installations
        if processed_modules:
            cr.execute(
                """select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)"""
            )
            for (model, name) in cr.fetchall():
                model_obj = pool.get(model)
                if model_obj and not model_obj.is_transient():
                    _logger.warning(
                        'The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,,1,1,1,1',
                        model, model.replace('.',
                                             '_'), model.replace('.', '_'),
                        model.replace('.', '_'))

            # Temporary warning while we remove access rights on osv_memory objects, as they have
            # been replaced by owner-only access rights
            cr.execute(
                """select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id"""
            )
            for (model, name) in cr.fetchall():
                model_obj = pool.get(model)
                if model_obj and model_obj.is_transient():
                    _logger.warning(
                        'The transient model %s (%s) should not have explicit access rules!',
                        model, name)

            cr.execute("SELECT model from ir_model")
            for (model, ) in cr.fetchall():
                obj = pool.get(model)
                if obj:
                    obj._check_removed_columns(cr, log=True)
                else:
                    _logger.warning(
                        "Model %s is declared but cannot be loaded! (Perhaps a module was partially removed or renamed)",
                        model)

            # Cleanup orphan records
            pool.get('ir.model.data')._process_end(cr, SUPERUSER_ID,
                                                   processed_modules)

        for kind in ('init', 'demo', 'update'):
            tools.config[kind] = {}

        cr.commit()

        # STEP 5: Cleanup menus
        # Remove menu items that are not referenced by any of other
        # (child) menu item, ir_values, or ir_model_data.
        # TODO: This code could be a method of ir_ui_menu. Remove menu without actions of children
        if update_module:
            while True:
                cr.execute('''delete from
                        ir_ui_menu
                    where
                        (id not IN (select parent_id from ir_ui_menu where parent_id is not null))
                    and
                        (id not IN (select res_id from ir_values where model='ir.ui.menu'))
                    and
                        (id not IN (select res_id from ir_model_data where model='ir.ui.menu'))'''
                           )
                cr.commit()
                if not cr.rowcount:
                    break
                else:
                    _logger.info('removed %d unused menus', cr.rowcount)

        # STEP 6: Uninstall modules to remove
        if update_module:
            # Remove records referenced from ir_model_data for modules to be
            # removed (and removed the references from ir_model_data).
            cr.execute("SELECT id FROM ir_module_module WHERE state=%s",
                       ('to remove', ))
            mod_ids_to_remove = [x[0] for x in cr.fetchall()]
            if mod_ids_to_remove:
                pool.get('ir.module.module').module_uninstall(
                    cr, SUPERUSER_ID, mod_ids_to_remove)
                # Recursive reload, should only happen once, because there should be no
                # modules to remove next time
                cr.commit()
                _logger.info(
                    'Reloading registry once more after uninstalling modules')
                return pooler.restart_pool(cr.dbname, force_demo, status,
                                           update_module)

        if report.failures:
            _logger.error('At least one test failed when loading the modules.')
        else:
            _logger.info('Modules loaded.')

        # STEP 7: call _register_hook on every model
        for model in pool.models.values():
            model._register_hook(cr)

    finally:
        cr.close()
Esempio n. 5
0
def load_modules(db, force_demo=False, status=None, update_module=False):
    initialize_sys_path()

    force = []
    if force_demo:
        force.append('demo')

    models_to_check = set()

    cr = db.cursor()
    try:
        if not openerp.modules.db.is_initialized(cr):
            if not update_module:
                _logger.error(
                    "Database %s not initialized, you can force it with `-i base`",
                    cr.dbname)
                return
            _logger.info("init db")
            openerp.modules.db.initialize(cr)
            update_module = True  # process auto-installed modules
            tools.config["init"]["all"] = 1
            tools.config['update']['all'] = 1
            if not tools.config['without_demo']:
                tools.config["demo"]['all'] = 1

        # This is a brand new registry, just created in
        # openerp.modules.registry.RegistryManager.new().
        registry = openerp.registry(cr.dbname)

        if 'base' in tools.config['update'] or 'all' in tools.config['update']:
            cr.execute(
                "update ir_module_module set state=%s where name=%s and state=%s",
                ('to upgrade', 'base', 'installed'))

        # STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps)
        graph = openerp.modules.graph.Graph()
        graph.add_module(cr, 'base', force)
        if not graph:
            _logger.critical(
                'module base cannot be loaded! (hint: verify addons-path)')
            raise ImportError(
                'Module `base` cannot be loaded! (hint: verify addons-path)')

        # processed_modules: for cleanup step after install
        # loaded_modules: to avoid double loading
        report = registry._assertion_report
        loaded_modules, processed_modules = load_module_graph(
            cr,
            graph,
            status,
            perform_checks=update_module,
            report=report,
            models_to_check=models_to_check)

        load_lang = tools.config.pop('load_language')
        if load_lang or update_module:
            # some base models are used below, so make sure they are set up
            registry.setup_models(cr, partial=True)

        if load_lang:
            for lang in load_lang.split(','):
                tools.load_language(cr, lang)

        # STEP 2: Mark other modules to be loaded/updated
        if update_module:
            modobj = registry['ir.module.module']
            _logger.info('updating modules list')
            modobj.update_list(cr, SUPERUSER_ID)

            _check_module_names(
                cr,
                itertools.chain(tools.config['init'].keys(),
                                tools.config['update'].keys()))

            mods = [k for k in tools.config['init'] if tools.config['init'][k]]
            if mods:
                ids = modobj.search(
                    cr, SUPERUSER_ID,
                    ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
                if ids:
                    modobj.button_install(cr, SUPERUSER_ID, ids)

            mods = [
                k for k in tools.config['update'] if tools.config['update'][k]
            ]
            if mods:
                ids = modobj.search(
                    cr, SUPERUSER_ID,
                    ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
                if ids:
                    modobj.button_upgrade(cr, SUPERUSER_ID, ids)

            cr.execute("update ir_module_module set state=%s where name=%s",
                       ('installed', 'base'))
            modobj.invalidate_cache(cr, SUPERUSER_ID, ['state'])

        # STEP 3: Load marked modules (skipping base which was done in STEP 1)
        # IMPORTANT: this is done in two parts, first loading all installed or
        #            partially installed modules (i.e. installed/to upgrade), to
        #            offer a consistent system to the second part: installing
        #            newly selected modules.
        #            We include the modules 'to remove' in the first step, because
        #            they are part of the "currently installed" modules. They will
        #            be dropped in STEP 6 later, before restarting the loading
        #            process.
        # IMPORTANT 2: We have to loop here until all relevant modules have been
        #              processed, because in some rare cases the dependencies have
        #              changed, and modules that depend on an uninstalled module
        #              will not be processed on the first pass.
        #              It's especially useful for migrations.
        previously_processed = -1
        while previously_processed < len(processed_modules):
            previously_processed = len(processed_modules)
            processed_modules += load_marked_modules(
                cr, graph, ['installed', 'to upgrade', 'to remove'], force,
                status, report, loaded_modules, update_module, models_to_check)
            if update_module:
                processed_modules += load_marked_modules(
                    cr, graph, ['to install'], force, status, report,
                    loaded_modules, update_module, models_to_check)

        registry.setup_models(cr)

        # STEP 3.5: execute migration end-scripts
        migrations = openerp.modules.migration.MigrationManager(cr, graph)
        for package in graph:
            migrations.migrate_module(package, 'end')

        # STEP 4: Finish and cleanup installations
        if processed_modules:
            cr.execute(
                """select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)"""
            )
            for (model, name) in cr.fetchall():
                if model in registry and not registry[model].is_transient(
                ) and not isinstance(registry[model],
                                     openerp.osv.orm.AbstractModel):
                    _logger.warning(
                        'The model %s has no access rules, consider adding one. E.g. access_%s,access_%s,model_%s,base.group_user,1,0,0,0',
                        model, model.replace('.',
                                             '_'), model.replace('.', '_'),
                        model.replace('.', '_'))

            # Temporary warning while we remove access rights on osv_memory objects, as they have
            # been replaced by owner-only access rights
            cr.execute(
                """select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id"""
            )
            for (model, name) in cr.fetchall():
                if model in registry and registry[model].is_transient():
                    _logger.warning(
                        'The transient model %s (%s) should not have explicit access rules!',
                        model, name)

            cr.execute("SELECT model from ir_model")
            for (model, ) in cr.fetchall():
                if model in registry:
                    registry[model]._check_removed_columns(cr, log=True)
                elif _logger.isEnabledFor(
                        logging.INFO):  # more an info that a warning...
                    _logger.warning(
                        "Model %s is declared but cannot be loaded! (Perhaps a module was partially removed or renamed)",
                        model)

            # Cleanup orphan records
            registry['ir.model.data']._process_end(cr, SUPERUSER_ID,
                                                   processed_modules)

        for kind in ('init', 'demo', 'update'):
            tools.config[kind] = {}

        cr.commit()

        # STEP 5: Uninstall modules to remove
        if update_module:
            # Remove records referenced from ir_model_data for modules to be
            # removed (and removed the references from ir_model_data).
            cr.execute("SELECT name, id FROM ir_module_module WHERE state=%s",
                       ('to remove', ))
            modules_to_remove = dict(cr.fetchall())
            if modules_to_remove:
                pkgs = reversed(
                    [p for p in graph if p.name in modules_to_remove])
                for pkg in pkgs:
                    uninstall_hook = pkg.info.get('uninstall_hook')
                    if uninstall_hook:
                        py_module = sys.modules['openerp.addons.%s' %
                                                (pkg.name, )]
                        getattr(py_module, uninstall_hook)(cr, registry)

                registry['ir.module.module'].module_uninstall(
                    cr, SUPERUSER_ID, modules_to_remove.values())
                # Recursive reload, should only happen once, because there should be no
                # modules to remove next time
                cr.commit()
                _logger.info(
                    'Reloading registry once more after uninstalling modules')
                openerp.api.Environment.reset()
                return openerp.modules.registry.RegistryManager.new(
                    cr.dbname, force_demo, status, update_module)

        # STEP 5.5: Verify extended fields on every model
        # This will fix the schema of all models in a situation such as:
        #   - module A is loaded and defines model M;
        #   - module B is installed/upgraded and extends model M;
        #   - module C is loaded and extends model M;
        #   - module B and C depend on A but not on each other;
        # The changes introduced by module C are not taken into account by the upgrade of B.
        if models_to_check:
            module_objs_to_check = [
                registry.models[m] for m in models_to_check
            ]
            init_module_models(cr, 'verification in progress',
                               module_objs_to_check)

        # STEP 6: verify custom views on every model
        if update_module:
            Views = registry['ir.ui.view']
            for model in registry.models.keys():
                try:
                    Views._validate_custom_views(cr, SUPERUSER_ID, model)
                except Exception as e:
                    _logger.warning('invalid custom view(s) for model %s: %s',
                                    model, tools.ustr(e))

        if report.failures:
            _logger.error('At least one test failed when loading the modules.')
        else:
            _logger.info('Modules loaded.')

        # STEP 8: call _register_hook on every model
        for model in registry.models.values():
            model._register_hook(cr)

        # STEP 9: Run the post-install tests
        cr.commit()

        t0 = time.time()
        t0_sql = openerp.sql_db.sql_counter
        if openerp.tools.config['test_enable']:
            if update_module:
                cr.execute(
                    "SELECT name FROM ir_module_module WHERE state='installed' and name = ANY(%s)",
                    (processed_modules, ))
            else:
                cr.execute(
                    "SELECT name FROM ir_module_module WHERE state='installed'"
                )
            for module_name in cr.fetchall():
                report.record_result(
                    openerp.modules.module.run_unit_tests(
                        module_name[0], cr.dbname, position=runs_post_install))
            _logger.log(25, "All post-tested in %.2fs, %s queries",
                        time.time() - t0, openerp.sql_db.sql_counter - t0_sql)
    finally:
        cr.close()
Esempio n. 6
0
def load_modules(db, force_demo=False, status=None, update_module=False):
    # TODO status['progress'] reporting is broken: used twice (and reset each
    # time to zero) in load_module_graph, not fine-grained enough.
    # It should be a method exposed by the pool.
    initialize_sys_path()

    open_openerp_namespace()

    force = []
    if force_demo:
        force.append('demo')

    cr = db.cursor()
    try:
        if not openerp.modules.db.is_initialized(cr):
            logger.notifyChannel("init", netsvc.LOG_INFO, "init db")
            openerp.modules.db.initialize(cr)
            tools.config["init"]["all"] = 1
            tools.config['update']['all'] = 1
            if not tools.config['without_demo']:
                tools.config["demo"]['all'] = 1

        # This is a brand new pool, just created in pooler.get_db_and_pool()
        pool = pooler.get_pool(cr.dbname)

        processed_modules = [] # for cleanup step after install
        loaded_modules = [] # to avoid double loading
        report = tools.assertion_report()
        if 'base' in tools.config['update'] or 'all' in tools.config['update']:
            cr.execute("update ir_module_module set state=%s where name=%s and state=%s", ('to upgrade', 'base', 'installed'))

        # STEP 1: LOAD BASE (must be done before module dependencies can be computed for later steps) 
        graph = openerp.modules.graph.Graph()
        graph.add_module(cr, 'base', force)
        if not graph:
            logger.notifyChannel('init', netsvc.LOG_CRITICAL, 'module base cannot be loaded! (hint: verify addons-path)')
            raise osv.osv.except_osv(_('Could not load base module'), _('module base cannot be loaded! (hint: verify addons-path)'))
        loaded, processed = load_module_graph(cr, graph, status, perform_checks=(not update_module), report=report)
        processed_modules.extend(processed)

        if tools.config['load_language']:
            for lang in tools.config['load_language'].split(','):
                tools.load_language(cr, lang)

        # STEP 2: Mark other modules to be loaded/updated
        if update_module:
            modobj = pool.get('ir.module.module')
            if ('base' in tools.config['init']) or ('base' in tools.config['update']):
                logger.notifyChannel('init', netsvc.LOG_INFO, 'updating modules list')
                modobj.update_list(cr, 1)

            _check_module_names(cr, itertools.chain(tools.config['init'].keys(), tools.config['update'].keys()))

            mods = [k for k in tools.config['init'] if tools.config['init'][k]]
            if mods:
                ids = modobj.search(cr, 1, ['&', ('state', '=', 'uninstalled'), ('name', 'in', mods)])
                if ids:
                    modobj.button_install(cr, 1, ids)

            mods = [k for k in tools.config['update'] if tools.config['update'][k]]
            if mods:
                ids = modobj.search(cr, 1, ['&', ('state', '=', 'installed'), ('name', 'in', mods)])
                if ids:
                    modobj.button_upgrade(cr, 1, ids)

            cr.execute("update ir_module_module set state=%s where name=%s", ('installed', 'base'))


        # STEP 3: Load marked modules (skipping base which was done in STEP 1)
        # IMPORTANT: this is done in two parts, first loading all installed or
        #            partially installed modules (i.e. installed/to upgrade), to
        #            offer a consistent system to the second part: installing
        #            newly selected modules.
        states_to_load = ['installed', 'to upgrade']
        processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules)
        processed_modules.extend(processed)
        if update_module:
            states_to_load = ['to install']
            processed = load_marked_modules(cr, graph, states_to_load, force, status, report, loaded_modules)
            processed_modules.extend(processed)

        # load custom models
        cr.execute('select model from ir_model where state=%s', ('manual',))
        for model in cr.dictfetchall():
            pool.get('ir.model').instanciate(cr, 1, model['model'], {})

        # STEP 4: Finish and cleanup
        if processed_modules:
            cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
            for (model, name) in cr.fetchall():
                model_obj = pool.get(model)
                if model_obj and not isinstance(model_obj, osv.osv.osv_memory):
                    logger.notifyChannel('init', netsvc.LOG_WARNING, 'object %s (%s) has no access rules!' % (model, name))

            # Temporary warning while we remove access rights on osv_memory objects, as they have
            # been replaced by owner-only access rights
            cr.execute("""select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id""")
            for (model, name) in cr.fetchall():
                model_obj = pool.get(model)
                if isinstance(model_obj, osv.osv.osv_memory):
                    logger.notifyChannel('init', netsvc.LOG_WARNING, 'In-memory object %s (%s) should not have explicit access rules!' % (model, name))

            cr.execute("SELECT model from ir_model")
            for (model,) in cr.fetchall():
                obj = pool.get(model)
                if obj:
                    obj._check_removed_columns(cr, log=True)
                else:
                    logger.notifyChannel('init', netsvc.LOG_WARNING, "Model %s is referenced but not present in the orm pool!" % model)

            # Cleanup orphan records
            pool.get('ir.model.data')._process_end(cr, 1, processed_modules)

        if report.get_report():
            logger.notifyChannel('init', netsvc.LOG_INFO, report)

        for kind in ('init', 'demo', 'update'):
            tools.config[kind] = {}

        cr.commit()
        if update_module:
            # Remove records referenced from ir_model_data for modules to be
            # removed (and removed the references from ir_model_data).
            cr.execute("select id,name from ir_module_module where state=%s", ('to remove',))
            for mod_id, mod_name in cr.fetchall():
                cr.execute('select model,res_id from ir_model_data where noupdate=%s and module=%s order by id desc', (False, mod_name,))
                for rmod, rid in cr.fetchall():
                    uid = 1
                    rmod_module= pool.get(rmod)
                    if rmod_module:
                        # TODO group by module so that we can delete multiple ids in a call
                        rmod_module.unlink(cr, uid, [rid])
                    else:
                        logger.notifyChannel('init', netsvc.LOG_ERROR, 'Could not locate %s to remove res=%d' % (rmod,rid))
                cr.execute('delete from ir_model_data where noupdate=%s and module=%s', (False, mod_name,))
                cr.commit()

            # Remove menu items that are not referenced by any of other
            # (child) menu item, ir_values, or ir_model_data.
            # This code could be a method of ir_ui_menu.
            # TODO: remove menu without actions of children
            while True:
                cr.execute('''delete from
                        ir_ui_menu
                    where
                        (id not IN (select parent_id from ir_ui_menu where parent_id is not null))
                    and
                        (id not IN (select res_id from ir_values where model='ir.ui.menu'))
                    and
                        (id not IN (select res_id from ir_model_data where model='ir.ui.menu'))''')
                cr.commit()
                if not cr.rowcount:
                    break
                else:
                    logger.notifyChannel('init', netsvc.LOG_INFO, 'removed %d unused menus' % (cr.rowcount,))

            # Pretend that modules to be removed are actually uninstalled.
            cr.execute("update ir_module_module set state=%s where state=%s", ('uninstalled', 'to remove',))
            cr.commit()
    finally:
        cr.close()